Friday 26 April 2013

How to create DocumentSets programmatically

Here is a simple code for creating DocumentSets programmatically and update metadata of it:


string strName = "<Name of the DocumentSet>";
SPContentTypeId cntntID = new SPContentTypeId();
cntntID = _docLib.ContentTypes["<DocumentSet content type name>"].Id;
Hashtable prop = new Hashtable();
DocumentSet _docSet = DocumentSet.Create(_fldr, strName, cntntID, prop, true);
SPListItem _docSetItem = _docLib.GetItemById(_docSet.Item.ID);
_docSetItem["<field>"]="<value>";
_docSetItem.Update();


Here _fldr is the SPFolder object, inside which we want to create document set.
_docLib is the SPDocumentLibrary object inside which document set has to be created.

Thursday 25 April 2013

How to close a custom modal dialogue (application page) in SharePoint

We created an application page in SharePoint, which opens up as a modal dialogue box on one of the Button click. Functionality wise, page was working fine and we didn't face any issue with it until we thought of having a close button on application page.

Till now the only way to close the page was by clicking on "X" button present in extreme right top corner.

Here is how we achieved this:

1. Created a cancel button, as shown below, in aspx page:


2. On button click event, add below lines:
protected void btnCancel_Click(object sender, EventArgs e)
{
     Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
     Context.Response.Flush();
     Context.Response.End();
}

How to get SharePoint browse button in sharepoint application pages

Here is a quick demo on how to use browse button for selecting files present within a SharePoint site.

1. Create a text box (for displaying SharePoint URL to users), and a normal button (which would be used as a browse button) in application page, as shown below.


2. In the header section of application page, just add the below script section for getting the picker tree dialogue control reference.

<script type="text/javascript" language="javascript" src="/_layouts/1033/PickerTreeDialog.js"></script>

3. In the header section, add another script section for ecma script, which defines the function defined in point 1 (launchPicker()). Here is the code for launchPicker() function:


<script type="text/ecmascript">
        var lastSelectedListSmtPickerId = '';
        function launchPicker() {
            var url = location.protocol + "//" + location.hostname + ":" + location.port;
            if (!document.getElementById) return;

            var listTextBox = document.getElementById('<%=txtDestURL.ClientID %>');
            var rootVar = document.getElementById('<%=hidField.ClientID %>').value;
            var varListURL = document.getElementById('<%=hidListURL.ClientID %>').value;
            if (listTextBox == null) return;

            var serverUrl = '\u002f';

            var callback = function (results) {
                if (results == null
                        || results[1] == null
                        || results[3] == null) return;

                lastSelectedListSmtPickerId = results[0];
                var listUrl = '/';
                if (results[3].charAt(0) == '/') results[3] = results[3].substring(1);
                listUrl = listUrl + results[3];
                listTextBox.value = url + varListURL + listUrl;
            };
            LaunchPickerTreeDialog('ProductFolderURLPicker', 'ProductFolderURLPicker', 'websListsFolders',  rootVar, serverUrl, varListURL, '', '', '/_layouts/images/Copy.gif', '', callback, '', '');
        }
    </script>

4. Here "txtDestURL" is the name of the text box created in step-1.
5. "hidListURL" and "hidField" are 2 hidden fields, which I created for storing the server relative list url and other necessary parameter for loading the picker control.
6. Here is how I created the hidden fields in application page:







7. Here is the code for setting up the values of hidden field in class file of application page. The values has to be set on Page_Load of application page.

string sListID = Request.Params["ListID"];

hidField.Value = "SPList:" + sListID.Substring(1, sListID.Length - 2) + "?SPWeb:" +  _web.ID + ":";
hidListURL.Value = (_web.Lists[new Guid(sListID)]).RootFolder.ServerRelativeUrl;



Wednesday 24 April 2013

Version history of document set is showing incorrect data.

Few days back, client reported us with a issue, where they said that some of the metadata in document sets are not matching with the data shown in its version history (specially "Date" type fields).

We spent lots of time to figure out the issue and in the end it turned out to be a SharePoint bug.

Here is a microsoft link which confirms the same and also gives the hotfix for it.

Please read the "INTRODUCTION" section of the article before applying the fix (as it covers many more areas than the one specified in header of this post).

Tuesday 23 April 2013

How to update managed metadata field in SharePoint 2010 programatically

Updating a managed metadata field is not as simple as it looks, the update is not straight forward and needs some extra effort to update, when compared to other field types in SharePoint.

Here is the link which gives some extra insight about the managed metadata in SharePoint 2010.

Here is how we update managed metadata field.


using (SPSite _site = new SPSite("<site collection URL>"))
{
         using (SPWeb _web = _site.OpenWeb())
         {
                        SPDocumentLibrary _docLib =  (SPDocumentLibrary)_web.Lists["<ListName>"];
                        TaxonomySession session = new TaxonomySession(_site);
                        TermStore store = session.TermStores["<Managed Metadata Term store Name>"];
                        Microsoft.SharePoint.Taxonomy.Group group = store.Groups["<Term group Name>"];
                        TermSet set = group.TermSets["Term Set Name"];
                        TaxonomyField tagsField = (TaxonomyField)_docLib.Fields["<Managed Metadata Field Name>"];
                        //we are assuming that managed metadata field values are separated with ';' (if managed metadata field accepts multiple values)
                        List<string> fieldValues = "<Managed Metadata Value>".Split(';').ToList();
                        //if managed metadata field accepts multiple value

                        if (tagsField.AllowMultipleValues)
                        {
                                    //SetTaxonomyFieldMultiValue(termSet, taxField, item, fieldValues);
                                    // declare a collection for the terms to capture all those for a multiple value field
                                    var fieldTerms = new List<Term>();
                                    foreach (var value in fieldValues)
                                    {
                                                    // search for the terms we wish to set the field to
                                                    var terms = set.GetTerms(value, true);
                                                   
                                                    // if we have found a term populate the field
                                                    if (terms.Count > 0)
                                                    {
                                                        terms.ToList().ForEach(t => fieldTerms.Add(t));
                                                    }
                                                    // else leave it blank
                                    }
                                    // set the field to the term(s) we have found
                                    tagsField.SetFieldValue(_docSetItem, fieldTerms);
                  }
                  else
                  {
                             //SetTaxonomyFieldValue(termSet, taxField, item, fieldValues.First())
                             // search for the terms we wish to set the field to
                             var terms = set.GetTerms(fieldValues[0], true, StringMatchOption.ExactMatch, 1, false);
                              // if we have found a term populate the field
                              if (terms.Count > 0)
                              {
                                   // set the field to the term(s) we have found
                                    tagsField.SetFieldValue(_docSetItem, terms.First());
         
                             }
                  }

          }
}

Tuesday 9 April 2013

Downloading files from a site, which uses FBA

I had a requirement where I was suppose to download some files from the URL provided by client. I wrote a simple console app for this, provided the login credentials and downloaded the files. It looked quite simple and everything went well until I observed something fishy in downloaded files.

All the files were of same size. When I opened the files, I saw that it contains the login page of the site, and not exactly the content of the file :(.

Where exactly I went wrong?

The site provided by the client was not using windows authentication (for which I wrote the code), but it was using Form based Authentication.

So, next question, How to convert my console app to other form so that it can download the files from site using FBA?

Here is how I did that:

1. Write a class which inherits from WebClient class and overwrite GetWebRequest method.

public class OverWrittenWebClient : WebClient
{
        private CookieContainer cookie = new CookieContainer();
        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            try
            {
                if (request is HttpWebRequest)
                {
                    (request as HttpWebRequest).CookieContainer = cookie;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR : " + ex.Message);
            }
            return request;
        }
}

2. Use this class' object for downloading the files, as shown below:


var client = new OverWrittenWebClient();
client.BaseAddress = @"<login page url>";
var loginData = new NameValueCollection();
loginData.Add("<loginID field name>", "<loginID>");
loginData.Add("<password field name>", "<Password>");
client.UploadValues(client.BaseAddress, "POST", loginData);
client.DownloadFile("<url of file>", "<download file location>");

3. "<loginID field name>" and "<password field name>" can be obtained by right clicking and then clicking on "view source" link of login page and then finding the ID for login text box and password text box respectively.

Monday 8 April 2013

How to Disable event firing on item edit

We often comes across many situations where we need to disable the event firing on item edit.

Here is a simple trick to do that.

First, create a class which inherits from SPItemEventReceiver class and IDisposable interface as shown below

class DisableEventFiring : SPItemEventReceiver, IDisposable
{
         bool bEvent;
         public DisableEventFiring()
        {
                   bEvent = this.EventFiringEnabled;
                   this.EventFiringEnabled = false;
         }
         public void Dispose()
        {
                  this.EventFiringEnabled = bEvent;
        }
}

Now just use this class for disabling the event firing like shown below: 

using(new DisableEventFiring())
{
           _item.update;
}