Apr 3

First thing to clear up is this... a document library is not a folder and a folder is not a document library. A folder resides in a document library and the SPFolder class doesn't have the same methods as the SPDocumentLibrary class (unfortunately).

For example, you can get the last modified date of any file within an entire document library, but you can't get the last modified date of any file within a folder within that document library. I found this frustrating because that was exactly what I had to do.

Anyway, when you browse to a document library and click on a folder within that document library, you get a huge URL. One that looks something like http://intranet/site/subsite/DocLib/Forms/AllItems.aspx?RootFolder=%2fsite%2fsubsite%2fDocLib%2fFolderName&blah blah blah. Copy that link into a list with a URL field and sometimes you see this... http://intranet/site/subsite/DocLib/FolderName. Now, that's annoying when trying to figure out what the folder is in the URL that the user pastes.

So firstly, what you need to do is check if there is a value for RootFolder in the URL and if there is, convert it into the shortened version so you can more easily manipulate it.

    if (strURL.Contains("RootFolder="))
    {
        // need to shorten it
        int equalMark = strURL.IndexOf("=");
        int ampersandMark = strURL.IndexOf("&");
        string folderURL = SPEncode.UrlDecodeAsUrl(strURL.Substring((equalMark + 1), (ampersandMark - equalMark - 1)));

        SPSite site = new SPSite(strURL);
        strURL = site.Url + folderURL; // now the url is the link direct to the folder itself.
    }

From this smaller URL, you can get the document library details (see here). Then as far as I know, you have to loop through all the folders in the document library to find the one you are after.

    SPSite site = new SPSite(strURL);
    SPWeb web = site.OpenWeb();

    string[] explode = strURL.Replace(web.Url, "").Split(new char[] { '/' });
    string splitURL = explode[1];
    string splitFolderName = explode[2];

    string docLibName = SPEncode.UrlDecodeAsUrl(splitURL); // (this is also the list name with the location we're after)

    foreach (SPListItem folderListItem in web.Lists[docLibName].Folders)
    {
        if (folderListItem.Name == strFolderName) // compare
        {
            // then now we go through the items in this folder and see if there is anything new
            foreach (SPFile file in folderListItem.Folder.Files)
            {
                // you can now go through each file in that folder
            }
        }
    }

Note that web.Lists[docLibName].Folders is of type SPFolder already so you can manipulate the folder if you need to.

Apr 3

Here's what was happening. I needed to extract the document library name from an intranet URL that a user enters. So they would enter something like this as the URL: http://intranet/site/subsite/DocLib1/Forms/AllItems.aspx and from there I need to extract DocLib1 as SPDocumentLibrary. Problem here is that no matter the depth, I still need to find the document library name and manipulate it as SPDocumentLibrary.

I'm not sure if my way is the best way to do it, but it did work...

            SPSite site = new SPSite(strURL);
            SPWeb web = site.OpenWeb();

            string[] explode = strURL.Replace(web.Url, "").Split(new char[] { '/' });
            string splitURL = explode[1];

            string docLibName = SPEncode.UrlDecodeAsUrl(splitURL); // (this is also the list name with the location we're after)
            SPList thisDocLib = web.Lists[docLibName];

If you do a check for thisDocLib.BaseType, you will find it's of the type DocumentLibrary.

Now, how would it work if it were the folder that we were after instead of a document library?

Mar 25

In your web part render override, create a link that looks something like this:

<a href="http://your_intranet/path/to/page/with/webpart/Pages/default.aspx?getfileid=5">Get File with ID 5</a>

I'm hard coding the above because I'm assuming that you know how to query the database and display the relevant link on your web part.

Now, the code to download the file once the above link is clicked.

        protected override void Render(HtmlTextWriter writer)
        {
            writer.Write("<a href="http://your_intranet/path/to/page/with/webpart/Pages/default.aspx?getfileid=5">Get File with ID 5</a>");
            try
            {
                if (Page.Request.QueryString["getfileid"] != null)
                {
                    OpenSQLConnection();
                    cmd = new SqlCommand("SELECT FileName, Content, ContentType FROM TableName WHERE ID=" + Page.Request.QueryString["getfileid"], connection);
                    cmd.CommandType = CommandType.Text;
                    rdr = cmd.ExecuteReader();
                    if (rdr.Read())
                    {
                        try
                        {
                            byte[] fileData = (byte[])rdr["Content"];

                            Page.Response.Clear();
                            Page.Response.Buffer = true;
                            Page.Response.ContentType = rdr["ContentType"].ToString();
                            Page.Response.AddHeader("content-disposition", "attachment;filename=" + rdr["FileName"].ToString());
                            Page.Response.Charset = "";
                            Page.Response.Cache.SetCacheability(HttpCacheability.NoCache);
                            Page.Response.BinaryWrite(fileData);
                            Page.Response.End();

                        }
                        catch (Exception ex)
                        {
                            // Error trying to download attachment.
                        }
                    }
                    else
                    {
                        // file not found.
                        writer.Write("File not found.");
                    }
                    rdr.Close();
                    CloseSQLConnection();
                }
            }
            catch (Exception ex)
            {
                CloseSQLConnection();
                // problem with connecting to db to get the file
            }
        }

On clicking that link, you will now be prompted to download the file and choose a location where you want to save that file (or just open it for viewing).

Mar 25

Firstly, make sure that you have a varbinary and/or image field in your table since we are going to store the file you upload in binary form.

Again, let's start with the important variables:

        private HtmlInputFile inputFile = new HtmlInputFile();
        private Button btnSubmitFile = new Button();

 Then within the CreateChildControls Override:

        protected override void CreateChildControls()
        {
                inputFile.ID = "_fileUpload";
                this.Controls.Add(inputFile);

                btnSubmitFile.Text = "Submit Request";
                btnSubmitFile.Click += new EventHandler(btnSubmitFile_Click);
                this.Controls.Add(btnSubmitFile);
        }

Then within the Render Override:

        protected override void Render(HtmlTextWriter writer)
        {
                inputFile.RenderControl(writer);
                btnSubmitFile.RenderControl(writer);
        }

Then within the btnSubmitFile event which runs when the button is clicked

        void btnSubmitRequest_Click(object sender, EventArgs e)
        {
            // check for allowed extensions
            string AllowedExtensions = "'.doc','.xls','.bmp','.gif','.jpg','.pdf'";
            if (String.IsNullOrEmpty(inputFile.PostedFile.FileName))
            {
                // This means there is no file submitted
            }
            else
            {
                // check the extension of the file before uploading
                if (AllowedExtensions.Contains(System.IO.Path.GetExtension(inputFile.PostedFile.FileName)))
                {
                    // is one of the allowed extensions
                    try
                    {
                        UploadAttachments();
                    }
                    catch (Exception ex)
                    {
                        // problem uploading the file... handle the exception
                    }
                }
                else
                {
                    // file extension is not allowed
                }
            }
        }

        private void UploadAttachments()
        {
            // now check if there are any attachments.
            try
            {
                if (inputFile.PostedFile.FileName.Length != 0)
                {
                    // then there is a file to upload
                    HttpPostedFile objHttpPostedFile = inputFile.PostedFile;

                    // Find its length and convert it to byte array
                    int intContentlength = objHttpPostedFile.ContentLength;

                    // Create Byte Array
                    Byte[] bytFile = new Byte[intContentlength];

                    // Read Uploaded file in Byte Array
                    objHttpPostedFile.InputStream.Read(bytFile, 0, intContentlength);

                    OpenSQLConnection();
                    SqlCommand cmd = new SqlCommand("INSERT INTO TableName(FileName,ContentType,Content) VALUES(@FileName,@ContentType,@Content)", connection);
                    cmd.CommandType = CommandType.Text;
                    cmd.Parameters.Add(new SqlParameter("@FileName", inputFile.PostedFile.FileName));
                    cmd.Parameters.Add(new SqlParameter("@ContentType", inputFile.PostedFile.ContentType));
                    cmd.Parameters.Add(new SqlParameter("@Content", bytFile));

                    cmd.ExecuteNonQuery();
                    CloseSQLConnection();
                }
            }
            catch (Exception ex)
            {
                CloseSQLConnection();
                // Problem uploading the file into the database... handle the exception
            }
        }

        private void OpenSQLConnection()
        {
            connection = new SqlConnection("server=localhost;database=DatabaseName;Integrated Security=SSPI");
            connection.Open();
        }

        private void CloseSQLConnection()
        {
            connection.Close();
        }

Note that the code above checks only for the file extension, which can be easily changed by renaming the file. You could also check their content types (inputFile.PostedFile.ContentType) if you want to be sure that the file being uploaded is really what it claims to be.

Next blog will explain how to place a link in a web part to download the file that was just uploaded.

Mar 25
Using XSLT in web parts
Posted by Wei in SharePoint Web Parts on 03 25th, 2009| | No Comments »

This is useful if you want to give the client the ability to design their own web part, format it in any way they like while pulling merge fields from xml. Not sure if that was very clear... let me try again. The web part will create XML that contains fields that can be used by XSL, which can be edited by the client within the properties of the web part to display the results in any way they choose.

Firstly we should declare a few variables and properties

        public string feedXsl = "";

        [WebBrowsable(true), WebPartStorage(Storage.Shared)]
        [Personalizable(PersonalizationScope.Shared)]
        [FriendlyNameAttribute("Xsl Template")]
        public string FeedXsl
        {
            get { return feedXsl; }
            set { feedXsl = value; }
        }

This code above is what allows the user to edit the XSL via the web part properties. Note that this will only give the user a single line to enter all their XSL code. You can click on the ... to get a text area. In future, I'll describe how you can customise the web part properties area and place items like drop down boxes, buttons, text areas and other form items within the web part properties section.

Now that we have the variables and the properties out of the way, we can start coding the main section of the web part.

Within the Render Override, you need to firstly get the xml. In this example, I'll hard code the XML, but you will probably fill the XML with variables that you want to make available to the client for your particular web part.

        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                #region Create the XML contents
                string xmlfile = "<?xml version="1.0"?>";
                xmlfile += "<UserDetails>";
                xmlfile += "<UserInfo>";
                xmlfile += "<Username>jsmith</Username>";
                xmlfile += "<PreferredName>John Smith</PreferredName>";
                xmlfile += "<Email>john.smith@example.com</Email>";
                xmlfile += "</UserInfo>";
                xmlfile += "<UserInfo>";
                xmlfile += "<Username>jdoe</Username>";
                xmlfile += "<PreferredName>Jane Doe</PreferredName>";
                xmlfile += "<Email>jane.doe@example.com</Email>";
                xmlfile += "</UserInfo>";
                xmlfile += "</UserDetails>";

                string strHTML = string.Empty;
                XslCompiledTransform xslt = new XslCompiledTransform();
                if (!((FeedXsl.ToString() == null) || (FeedXsl.ToString() == string.Empty) || (FeedXsl.ToString() == "")))
                {
                    TextReader tr = new StringReader(FeedXsl.ToString().Trim());

                    XmlReader xreader = new XmlTextReader(tr);

                    strHTML = TransformXML(xmlfile, xreader);
                }
                else
                {
                    strHTML = "Please associate a valid XSL Template";
                }

                writer.Write(SPEncode.HtmlDecode(strHTML).ToString());
            }
            catch (Exception ex)
            {
                // handle the exception (or just display it in the web part for your information, which I did below)
                writer.Write(ex);
            }
        }

Within the Render Override, I called a function named TransformXML(xmlfile, xreader). Here's the code for that function:

        private string TransformXML(string strXML, XmlReader strXSL)
        {    //Create a IO Stream
            System.IO.StringWriter oSW = new System.IO.StringWriter();

            try
            {
                StringReader stream;
                stream = new StringReader(strXML);

                System.Xml.XmlTextReader oXR = new System.Xml.XmlTextReader(stream);
                System.Xml.Xsl.XslCompiledTransform oXSLT = new System.Xml.Xsl.XslCompiledTransform();

                oXSLT.Load(strXSL);

                System.Xml.XPath.XPathDocument oXPath = new System.Xml.XPath.XPathDocument(oXR);

                if (oXPath != null)
                {
                    oXSLT.Transform(oXPath, null, oSW);
                }
            }
            catch (Exception ex)
            {
                // there is an error with the transformation...
                oSW = new StringWriter(new StringBuilder("You have an error in your XSL Template."));
            }
            return oSW.ToString();
        }

Building the XSLT Code

When you compile the code and view the web part, you'll get the message You have an error in your XSL Template. This is because you haven't set up the XSL yet. View the web part properties and under Miscellaneous, you'll see a text field. Click on it then click on the ... button next to it.

In the window that pops up, enter your XSL code in there. I've included a simple sample below of what can go in here to transform the xml to html:

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
               version="1.0" exclude-result-prefixes="xsl ddwrt msxsl rssaggwrt"
               xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
               xmlns:rssaggwrt="http://schemas.microsoft.com/WebParts/v3/rssagg/runtime"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:template match="/">

    <table>
      <xsl:attribute name="width">100%</xsl:attribute>
      <xsl:for-each select="UserDetails/UserInfo">
        <tr>
          <td>
            <xsl:attribute name="align">center</xsl:attribute>
            <div>
              <b>
                <xsl:value-of select="PreferredName"/>
              </b>
            </div>
            <div>
              <xsl:value-of select="Email"/>
            </div>
          </td>
        </tr>
      </xsl:for-each>
    </table>

  </xsl:template>
</xsl:stylesheet>

« Previous Entries Next Entries »