Sunday 17 February 2013

Read AD Group from People Picker field, Get users of corresponding Group from AD & add them in other People Picker field of Library/List in SharePoint 2010



In SharePoint we can validate users using People Picker functionality. We can create a column with type as Person or Group which will provide us to validate users or groups. 

Now I have a requirement that user should be able to share particular documents with specific Users without breaking the inheritance every time. To achieve this I created a column “Shared Members” with column type as People or Group. Now the user can search & add the users in this column. Also in the view of this library I have applied a filter to show the documents only if “Created By= [Me]” or “Shared Members = [Me]”. This filter will display only those documents to the user if the document is created by him or he is present in the Shared Members column. 

Now here the challenge I was facing is if User wants to share the document with specific AD Group, he will add the group in the Shared Members column. But in this case the filter does not work as the SharePoint does not read users from that group. Hence to get all the users from the group I have fired an Event Receiver on Event Updated as it is a document library. 

Now I will create another column same as “Shared Members” & name it as “All Shared Members”.
In this Event Receiver we will read the AD Group from the “Shared Members“ column, get all the users of that group from AD using LDAP connection & store these users in the “All Shared Members” column.
Now I will change the column in filter & filter the documents based on “Created By” & “All Shared Members”.

Below are the steps to create the Event Receiver

  1. Open Visual Studio & Select Event Receiver & give proper Name.
   2.  After giving the Proper Name to the Project, the next screen appears asking to deploy the solution as Sandboxed or Farm level. Select Deploy as Farm Solution
    3.  The Next Popup will provide to choose the Event Receiver Settings. Here in the Type of Event Receiver we will select “List Item Event” as I have to fire the Event Receiver on each item. Then select the “Document Library” as the Event Source & finally the when the event is to be fired, here select “An item was updated” as it is a document library.
    If we want to achieve this functionality “List” then we need to fire the Event Receiver on “An Item was Added” as it is a list. Click Finish.
    4.  The Default solution will look as below
     5.  The default code in the Event receiver file will be as below
    6.  Now in the ManageSharedMembers.cs file add the below code.

    public class ManageSharedMembers : SPItemEventReceiver
{

    private string listname = "";
    //Give Shared Members Column Name
    private string SharedMembers = ConfigurationManager.AppSettings["DocumentSharedMembers"];
    //Give All Shared Members Column Name
    private string DestinationSharedMembers = ConfigurationManager.AppSettings["DocumentDestinationSharedMembers"];
   /// <summary>
   /// An item was updated.
   /// </summary>
   public override void ItemUpdated(SPItemEventProperties properties)
   {
    listname = properties.ListTitle.ToString();
    //Disable Event Firing as we are updating the item
    this.EventFiringEnabled = false;
    try
    {
     SPSecurity.RunWithElevatedPrivileges(delegate()
     {
      //Get current item
      SPListItem currentitem = properties.ListItem;
      //Check for the Shared Members & All Shared Members fields are present or not
    if (properties.ListItem.Fields.ContainsField(SharedMembers) && properties.ListItem.Fields.ContainsField(DestinationSharedMembers))
    {
     properties.Web.Site.AllowUnsafeUpdates = true;

     //Check whether the Shared Members column contains value or not.
     //If the event receiver is fired on List then in the if condition check the shared members column for empty or not as below commented
     Properties.AfterProperties[SharedMembers].ToString()!=string.Empty
     If it is on document library then as shown in below if condition

     if (currentitem.Properties[SharedMembers].ToString() != string.Empty)
     {
      string fieldValue = currentitem[SharedMembers].ToString();
      SPFieldUserValueCollection users = new SPFieldUserValueCollection(currentitem.Web, fieldValue);
      SPFieldUserValueCollection user = new SPFieldUserValueCollection();
      //Create LDAP connection with the Active Directory Server
      DirectoryEntry de = new DirectoryEntry();
      de.Path = "LDAP://Network IP/DC=sharepoint,DC=com";
      de.AuthenticationType = AuthenticationTypes.Secure;
      //Read users one by one to check for any groups present
      for (int i = 0; i < users.Count; i++)
      {
       SPFieldUserValue singlevalue = users[i];
       SPUser singleuser = singlevalue.User;
       string groupname = singleuser.Name.ToString();
       //Check whether the given value is user or group
       if (singlevalue.User.IsDomainGroup)
       {
        //If given value is a group then get all users from AD of that group
        DirectorySearcher searcher = new DirectorySearcher();
        searcher.Filter = ("(&(objectClass=group)(CN=" + groupname + "))");
        SearchResult result = searcher.FindOne();
        string username;
        if (result != null)
        {
         DirectoryEntry deGroup = new DirectoryEntry(result.Path);
         PropertyCollection pcoll = deGroup.Properties;
         try
         {
          //Fetch the users from the AD and add in the SPFieldUserValueCollection
          foreach (object obj in deGroup.Properties["member"])
          {
           username = obj.ToString();
           char[] split1 = { ',' };
           string[] getname = username.Split(split1);
           string temp = getname[0];
           char[] split2 = { '=' };
           string[] getname2 = temp.Split(split2);
           username = getname2[1];
           SPUser uservalue = currentitem.Web.EnsureUser(username);
           user.Add(new SPFieldUserValue(currentitem.Web, uservalue.ID, uservalue.Name));
          }
         }
         catch (Exception)
         {

         }
        }
       }
       else
       {
        //if singlevalue is user then you can use all SPUser properties & add.
        SPUser userdetails = singlevalue.User;
        user.Add(new SPFieldUserValue(currentitem.Web, userdetails.ID, userdetails.Name));
       
       }
      }
      //update all these users in the All Shared Members column.
      currentitem[DestinationSharedMembers] = user;
      currentitem.Update();
      //After updating the item now enable the Event Firing
      this.EventFiringEnabled = true;
     }
    }
    //}
   });
  }
  catch (Exception)
  {

  }
  base.ItemUpdated(properties);
 }
}
         Now Build & deploy the solution in the SharePoint Web Application.
       
       When this Event Receiver is fired, it will check for any groups in the “Shared Members” columns & then fetch the corresponding users from the AD & store them in the other column i.e. “All Shared Members”.

Create Custom List Definition using custom Content Type using .Net in SharePoint 2010



Please follow the link to create custom content type & custom site columns.


After creating custom content type it is now time to create a custom list definition & bind the custom content type to this List Definition so that on creating a list using the custom List Definition, the default Content type of this list should be our custom content type created & the site columns attached with it.

    1.  In the given solution we need to add a List Definition to create a custom List Template. Right Click on the Solution to add a new List Definition as shown below.

     2.   Now select the List Definition & give the List Definition a proper name & click add as shown below.

     3.  Now the popup will appear, provide the appropriate Display Name to the List Definition & select the type of list definition we want to create to add the default content type. Here select aye type as later on we will remove its default content type & add our custom content type & click “Finish” as shown below.

     4.  The Default solution will look as shown below

Now as we can see a default List Instance is created in the List Definition, we will give it a proper name & URL as shown below

      5.  Now open the Schema.XML file of the List Definition. We can see the default code which binds the default content type & its columns as shown below

    6.  Now in this solution at the beginning we can see the <ContentType></ContentaType> tag. It contains the default content type defined with its ID. Now we will comment the existing content type & insert our custom content type with ite appropriate ID as given below

<!--Define the Custom Content Type to the List Defination(List Template)with its ID-->
<ContentTypeRef ID="0x01004c89ffc4ed8242a886ff715d9da4f04d" />

The ID here is the ID of the Custom Content Type which we can get from the Elements.XML file of that particular Content type. Comment the default content type as shown below.

    7.  Now below in the Schema.XML file we can find the <ViewFields></ViewFields> which displays the default View. The columns defined here will be displayed in the default view.

     8.  Now in this <ViewFields></ViewFields> tag we will add our custom fields defined in the custom content type.

<FieldRef Name="DemoName"></FieldRef>
   <FieldRef Name="DemoValue"></FieldRef>
   <FieldRef Name="DemoChoiceType"></FieldRef>
   <FieldRef Name="DemoAmount"></FieldRef>
   <FieldRef Name="DemoDate"></FieldRef>
   <FieldRef Name="DemoLookupField"></FieldRef>

      The solution will look as shown below

    9.  Now build & deploy the solution in your SharePoint Web Application. After activating the feature the custom site columns will get created, also the Custom Content type is created & a default list with given List Definition is created.
      10.  Now to check whether our custom List Template is available for us to create list using this list template go the SharePoint site & click More Options in Site Actions. Filter by List from Right side Navigation. Here we can see our custom List template as shown below