Sofware Architecture-SharePoint 2010-Getting name of all the Lists in a site via client-side object model

August 30, 2011

The new client-side object model provides remote access to the functionality of the SharePoint Foundation server-side object model. In previous releases of SharePoint Foundation, SOAP Web services provided access to only a fraction of the server-side object model, but in SharePoint Foundation 2010, the client object model fills many of the gaps.

Client Object model can be one of the following type:
1. ECMAScript (JavaScript, JScript)
2. .NET managed
3. Silverlight client
According to SDK Documentation:

The new ECMAScript (JavaScript, JScript), .NET managed, and Silverlight client object models each provide a subset of the server object model that is defined in Microsoft.SharePoint.dll, including objects that correspond to major objects at the site-collection level or lower in the SharePoint Foundation hierarchy. To improve security and performance, the client object models focus on the most relevant APIs for client-side development, and do not contain all the types and members that are represented in the server object model.
The client object models are provided through proxy .js and managed .dll files, respectively, which can be referenced in custom applications like other object models. The object models are implemented as a Windows Communication Foundation (WCF) service (.../_vti_bin/client.svc), but uses Web bindings to implement efficient request batching. All operations are inherently asynchronous, and commands are serialized into XML and sent to the server in a single HTTP request. For every command, a corresponding server object model call is made, and the server returns a response to the client in compacted JavaScript Object Notation (or JSON) format, which the proxy parses and associates with appropriate objects. 

1. Getting name of all the Lists in a site via ECMAScript (JavaScript, JScript).
Create a new site page and in contentplaceholder add following code:

<a href="#"  onclick="getAllSPLists();"> Click me</a>
<script type="text/javascript">
var  myLists;
function getAllSPLists()
{
 // get current context
 var ctx =  SP.ClientContext.get_current();
 // point  to get all the lists 
 myLists =  ctx.get_web().get_lists();
 // Load all lists
 ctx.load(myLists );
 // async excute
 ctx.executeQueryAsync(Function.createDelegate(this,this.succeeded) , Function.createDelegate(this,this.failed));
 }
 
 function succeeded(sender, args)
 {
 alert('Call succeeded......');
//get enumerator
 var ListEnumerator = this.myLists.getEnumerator();
// iterate to all items
 while(ListEnumerator.moveNext())
 {
 // point to current item
 var currentItem = ListEnumerator.get_current();
 // show item
 alert('Item:  ' + currentItem.get_title());
 }
 
 }
 function failed(sender, args)
 {
 alert('Failed. ' + args.get_message() + '\n' + args.get_stackTrace());
 }
</script>

Save site page and run it to see the result.
2. Getting name of all the Lists in a site via .NET managed
Create a console project and add reference to Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll
After that following piece of code provide name of all the lists in a sharepoint site:

 using (var ctx = new ClientContext("http://win2k8-ultimate/sites/Call/"))
            {
               var list = ctx.Web.Lists;
               ctx.Load(list );
               ctx.ExecuteQuery();
               foreach (var item in list)
               {
                   Console.WriteLine("Item: " + item.Title + " - " + item.Description+ "\n");
               }
            }

Console will show name of all lists.
3. Getting name of all the Lists in a site via Silverlight Client.
Create a silver project and in main page “MainPage.xaml”, add a list box with following tag as:

<ListBox Height="100" HorizontalAlignment="Left" Margin="10,10,0,0" Name="listBox1" VerticalAlignment="Top" Width="120" />

The code behind of this page will be as:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.SharePoint.Client;

namespace ClientSideSilverApp
{
    public partial class MainPage : UserControl
    {
        IEnumerable<List> spList = null;
        public MainPage()
        {
            InitializeComponent();
            using (var ctx =  ClientContext.Current)
            {

                spList = ctx.LoadQuery(ctx.Web.Lists);
                ctx.ExecuteQueryAsync(Succeded, Failed);

            }
        }

        private void Succeded(object sender, ClientRequestSucceededEventArgs e)
        {
            Dispatcher.BeginInvoke(BindList);
        }
        private void Failed(object sender, ClientRequestFailedEventArgs e)
        {
            
        }

        private void BindList()
        {
            listBox1.Items.Clear();
            listBox1.ItemsSource = spList;
            listBox1.DisplayMemberPath = "Title";
        }
    }
}

Compile the project to make sure that there is no compile time error.
Now login to sharepoint site, Upload .xap file generated from above acivity to document library of sharepoint site and copy the URL of file.
Go to “Edit” >> “Insert”, click on web part, select category of “Media and Content” , select “Silverlight web part” and click on add. Provide the URL of file obtained from previous step. Configure the properties of web part as per requirement.
This will show list box with name of all the list in sharepoint site.
Happy coding for SharePoint……:)

Advertisements

Software Architecture-To find public key token of an assembly

August 21, 2011

Objective: To find public key token of an assembly.
Explanation:
Strong name utility named sn.exe can be used to find the public key token of an assembly as below:

c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin>sn.exe -T C:\Windows\Mic
rosoft.NET\Framework\v2.0.50727\system.directoryservices.dll

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key token is b03f5f7f11d50a3a

c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin>sn.exe -T C:\Windows\Mic
rosoft.NET\Framework\v2.0.50727\system.data.dll

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key token is b77a5c561934e089

Second way is to wire thing in Visual studio 2010, Go to Tools>>External Tools and add new tool by providing:
Title: Get Public Key Token
Command: C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\sn.exe
Arguments: -T $(TargetPath)
Check the Use Output Window checkbox. So screen looks like as:


Now click on menu in tools as “Get Public Key Token” to see the public key token of current assembly in output window as:

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Public key token is 4cb554340e8b008b

Reference: http://msdn.microsoft.com/en-us/library/k5b5tt23(v=VS.100).aspx


Software Architecture – SharePoint 2010 – To list the Active Directory groups which are used for assignment of permission

August 21, 2011

Objective: As in previous blog entry here , we have created a new menu item in the permission tab of ribbon control, now on click of that menu we want to open a custom page residing in the layout folder which can list AD groups which are used to assign rights in this web site of SharePoint. On clicking on any AD group name a third party group management solution will be opened in new window.
Implementation:
Create a new aspx page with following code in layout folder of sharepoint.

<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Assembly Name="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"%>
<%@ Assembly Name="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"%>

<%@ Page Language="C#"          Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase"  %>

<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="System.DirectoryServices" %>
<%@ Import Namespace="System.Data" %>

<script runat="server">
    public enum objectClass
    {
        user, group, computer
    }
    public enum returnType
    {
        distinguishedName, ObjectGUID
    }
protected override void OnLoad(EventArgs e) {
SPWeb site = this.Web;
lblSiteTitle.Text = site.Title;
lblSiteID.Text = site.ID.ToString();
    
System.Collections.Generic.List<SPUser> lstADGroups = new System.Collections.Generic.List<SPUser>();
foreach (SPUser item in site.Users)
{
    if (item.IsDomainGroup)
        lstADGroups.Add(item);
}
grdADGroups.DataSource = lstADGroups;
grdADGroups.DataBind();

  }
    public string GetObjectDistinguishedName(objectClass objectCls,
    returnType returnValue, string objectName, string LdapDomain)
{
    string distinguishedName = string.Empty;
    string connectionPrefix = "LDAP://" + LdapDomain;
    DirectoryEntry entry = new DirectoryEntry(connectionPrefix);
    DirectorySearcher mySearcher = new DirectorySearcher(entry);

    switch (objectCls)
    {
        case objectClass.user:
            mySearcher.Filter = "(&(objectClass=user) (|(cn=" + objectName + ")(sAMAccountName=" + objectName + ")))";
            break;
        case objectClass.group:
            mySearcher.Filter = "(&(objectClass=group)  (|(cn=" + objectName + ")(dn=" + objectName + ")))";
            break;
        case objectClass.computer:
            mySearcher.Filter = "(&(objectClass=computer)  (|(cn=" + objectName + ")(dn=" + objectName + ")))";
            break;
    }
    SearchResult result = mySearcher.FindOne();

    if (result == null)
    {
        throw new NullReferenceException
        ("unable to locate the distinguishedName for the object " +
        objectName + " in the " + LdapDomain + " domain");
    }
    DirectoryEntry directoryObject = result.GetDirectoryEntry();
    if (returnValue.Equals(returnType.distinguishedName))
    {
        distinguishedName = "LDAP://" + directoryObject.Properties
            ["distinguishedName"].Value;
    }
    if (returnValue.Equals(returnType.ObjectGUID))
    {
        distinguishedName = directoryObject.Guid.ToString();
    }
    entry.Close();
    entry.Dispose();
    mySearcher.Dispose();
    return distinguishedName;
}
protected void grdADGroups_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        SPUser rowView = (SPUser)e.Row.DataItem;
        HyperLink hLink = (HyperLink)e.Row.FindControl("Edit");
        hLink.Text = "Edit Membership";
        DirectoryEntry ent = new DirectoryEntry();
        char[] key = new char[1];
        key[0] = '\\';
        
        String GroupName = rowView.LoginName.Split(key)[1].ToString();
      
       string dname= GetObjectDistinguishedName(objectClass.group,returnType.distinguishedName, GroupName, rowView.LoginName.Split(key)[0].ToString());
        dname= dname.Substring(7,dname.Length-7);
        hLink.NavigateUrl = "http://win-2k8-r2-64/WebShah/properties.aspx?dn=" + dname   ;
    }
}

</script>

<form runat="server">
<table border="1" cellpadding="4" cellspacing="0" style="font-size:12">
<tr><td colspan="2"><b>Custom GroupManagement solution </b> - Custom GroupManagement solution,Custom GroupManagement solution,Custom GroupManagement solution,Custom GroupManagement solution.</td></tr>
    <tr>
      <td>Site Title:</td>
      <td><asp:Label ID="lblSiteTitle" runat="server" /></td>
    </tr>
    <tr>
      <td>Site ID:</td>
      <td><asp:Label ID="lblSiteID" runat="server" /></td>
    </tr>
  </table>
  <br />
  <asp:GridView ID="grdADGroups" runat="server" CellPadding="3" 
            EnableModelValidation="True" GridLines="Vertical" 
            AutoGenerateColumns="False" BackColor="White" BorderColor="#999999" 
            BorderStyle="None" BorderWidth="1px" 
            onrowdatabound="grdADGroups_RowDataBound" >
            <AlternatingRowStyle BackColor="#DCDCDC" />
            <Columns>
                <asp:BoundField AccessibleHeaderText="Group Name" DataField="LoginName" 
                    HeaderText="Group Name" />
                
                <asp:TemplateField HeaderText="Modify membership">     
                <ItemTemplate>
                 <asp:HyperLink ID="Edit" runat="server" />
                </ItemTemplate>
                </asp:TemplateField>
            </Columns>
            <FooterStyle BackColor="#CCCCCC" ForeColor="Black" />
            <HeaderStyle BackColor="#000084" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Center" />
            <RowStyle BackColor="#EEEEEE" ForeColor="Black" />
            <SelectedRowStyle BackColor="#008A8C" Font-Bold="True" ForeColor="White" />
        </asp:GridView>
        </form>

The above code is self-explanatory.
Happy coding SharePiont.


Software Architecture-SharePoint 2010-To Create new menu item in Ribbon control in Permission tab

August 21, 2011

Objective:
To create a new menu item in Ribbon control in Permission tab of SharePoint 2010.
Steps to follow:
A feature will be used to deploy the customization of ribbon control. Create a new folder named “CustomMenuRibbon” in feature folder. Create one file named “feature.xml” with following content.

 
<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
  Id="4E1C8B4C-D7DD-4351-8A58-17CDD3688BB3"
  Title=” New Menu"
  Description="This Feature adds a new menu item to the site permissions page "
  Hidden="FALSE"
  Scope="Web"
  Version="1.2.0.0">
  <ElementManifests>
    <ElementManifest Location="CustomMenuItem.xml" />
  </ElementManifests>
</Feature>

In same folder create a new file named “CustomMenuItem.xml” with following content.

 
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="VN.SharePoint.Ribbon.CustomTab" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition      Location="Ribbon.Permission.Scaling._children">
     <MaxSize      Id="Ribbon.Permission.Customs.MaxSize"      Sequence="15"      GroupId="Ribbon.Permission.Customs"      Size="LargeLarge" />
    </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.Permission.Groups._children">
          <Group Id="Ribbon.Permission.Customs"
                   Sequence="101"
                   Command="Perm_Custom"
                   Description=""
                   Title="Imanami Corp - GroupID"                                     
                   Template="Ribbon.Templates.Flexible2" >
            <Controls Id="Ribbon.Permission.Customs.Controls">
              <Button
               Id="Ribbon.Permission.Customs.Add"
               Command="Perm_AddCustom"
               Sequence="10"
               Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-128" Image16by16Left="0"
               Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="0" Image32by32Left="-416"              
               LabelText="Custom Permission"
               Alt=" Custom Permission"
               ToolTipTitle=" Custom integration with SharePoint"
               ToolTipDescription=" Custom integration with SharePoint . Custom integration with SharePoint . Custom integration with SharePoint . "
               TemplateAlias="o1"/>
            </Controls>
          </Group>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler
         Command="Perm_AddCustom"
         CommandAction="javascript:window.showModalDialog('http://win2k8-ultimate/sites/softcom/_layouts/SSP/setpermission.aspx','', 'dialogWidth:500px; dialogHeight:400px; center:yes');" />
        <CommandUIHandler
         Command="Perm_Custom"
         CommandAction="javascript:window.showModalDialog('http://win2k8-ultimate/sites/softcom/_layouts/SSP/setpermission.aspx','', 'dialogWidth:500px; dialogHeight:400px; center:yes');" />
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>

This feature can be installed as:

Install-spfeature CustomMenuRibbon –force

In site settings, go to features page and activate the feature. Go to site permissions page to view the new menu.
According to MSDN, Location of Ribbon control can be defined as:

The Server ribbon in Microsoft SharePoint Foundation supports customization of the default tabs, groups, and controls. In order to customize these objects, you need the specific identifier (ID) for the object you plan to customize. The IDs are found in the CMDUI.xml file that is stored in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\GLOBAL\XML directory on the front-end Web server.

Reference: http://msdn.microsoft.com/en-us/library/ee537543.aspx


Software Architecture – To find lockedout users from active directory

August 6, 2011

Objective : To find lockedout users from active directory

General Implementation:
Generally LDAP filter for getting Lockout accounts list is as:
(&(objectCategory=Person)(objectClass=user)(lockoutTime:1.2.840.113556.1.4.804:=4294967295))
Where 4294967295 is the highest number you can get using 32 bits (Binary digits)
11111111111111111111111111111111 = 4,294,967,295
FFFFFFFF = 4,294,967,295

1.2.840.113556.1.4.804 is the LDAP_MATCHING_RULE_BIT_OR rule. The matching rule is true if any bits from the property match the value. This rule is like the bitwise OR operator.

LockoutTime is AD attribute which is the date and time (UTC) that this account was locked out. This value is stored as a large integer that represents the number of 100-nanosecond intervals since January 1, 1601 (UTC). A value of zero means that the account is not currently locked out.
So (lockoutTime:1.2.840.113556.1.4.804:=4294967295) means fetch those entries which has any date time value in form of large integer.
Problem:
However searching for any accounts that have a value for lockouttime is not an accurate method to use because an account is determined to be locked out if the CurrentTime – lockouttime exceeds the Lockout Duration.
It is only upon a successful logon that AD sets the value of lockouttime to zero, so it is possible for an account to still contain a value for lockouttime, yet the account is not locked.

Solution:
The correct LDAP filters with a dynamic calculation based on Active Directory Account Lockout policy.
To determine the users that are currently locked out, you have to query the lockoutDuration attribute stored on the domain object (e.g., dc=rallencorp,dc=com). This attribute defines the number of minutes that an account will stay locked before becoming automatically unlocked. You need to take this value and subtract it from the current time to derive a timestamp that would be the outer marker for which users could still be locked. You can then compare this timestamp with the lockoutTime attribute of the user object. The search filter to find all locked users once you’ve determined the locked timestamp would look something like this:

(&(objectcategory=Person)(objectclass=user)(lockoutTime>=DerivedTimestamp))

For any users that have a lockoutTime that is less than the derived timestamp, their account has already been automatically unlocked per the lockoutDuration setting.

Where DerivedTimestamp = ( Now-LockoutDurationFromDomainPolicy)
[While accounting for local time zones and daylight savings time.]

So in this way, we can avoid problem in previous ldap filter.

Use of Windows Time Service Tool named W32tm.exe for diagnostic purpose to Convert an NT system time, in (10^-7)s intervals from 0h 1-Jan 1601, into a readable format as below.

w32tm /ntte

Code:
Class for getting the domain policy will be as:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;

namespace MyDirectoryServices.MyDirectory
{

    /*     
     This class get the domain poilcy from domain controller
     All policy attributes can be get via that.
     Make a public property and user it, as done for LockoutDuration
     Reference: http://en.csharp-online.net/User_Management_with_Active_Directory%E2%80%94Determining_Domain-Wide_Account_Policies
     */

    [Flags]
    public enum PasswordPolicy
    {
        DOMAIN_PASSWORD_COMPLEX = 1,
        DOMAIN_PASSWORD_NO_ANON_CHANGE = 2,
        DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 4,
        DOMAIN_LOCKOUT_ADMINS = 8,
        DOMAIN_PASSWORD_STORE_CLEARTEXT = 16,
        DOMAIN_REFUSE_PASSWORD_CHANGE = 32
    }

    public class DomainPolicy
    {
        public static string pLockoutTime = "lockoutTime";
        public static string pLockoutDuration = "lockoutDuration";
        public const long pNeverExpireConstant = 9223372036854775807;  // Used for AD attribute accountexpire, to show as never expires value
    
        ResultPropertyCollection attribs;

        public DomainPolicy()
        {
            // hardcoded domain name
            String pathRootDSE = String.Format("LDAP://softcom.imanami.lab");
            DirectoryEntry dse = new DirectoryEntry(pathRootDSE);
            
            //properties to fetch
            string[] policyAttributes = new string[] {
                  "lockoutDuration", "objectClass", 
                      "distinguishedName"
                        };

            DirectorySearcher ds = new DirectorySearcher(
              dse,
              "(objectClass=domainDNS)",
              policyAttributes,
              SearchScope.Base
              );

            // search
            SearchResult result = ds.FindOne();

            //do some quick validation...							  
            if (result == null)
            {
                throw new ArgumentException(
                  "domainRoot is not a domainDNS object."
                  );
            }

            this.attribs = result.Properties;
        }

        //for some odd reason, the intervals are all stored
        //as negative numbers. We use this to "invert" them
        private long GetAbsValue(object longInt)
        {
            return Math.Abs((long)longInt);
        }

        /// <summary>
        /// LockoutDuration of domain policy
        /// </summary>
        public TimeSpan LockoutDuration
        {
            get
            {
                string val = pLockoutDuration;
                //this should fail if not found
                var value = this.attribs[val][0];
                if (value == null)
                    return TimeSpan.MinValue;

                var result = (long)value;
                if (result == pNeverExpireConstant || result == 0)
                    return TimeSpan.MaxValue;

                var finalResult = TimeSpan.FromTicks(result);
                return finalResult;
            }
        }
    }
    
}

The code to get list of locked out accounts will be as:

 DomainPolicy dc = new DomainPolicy();
            
            // Print LockoutDuration from domain policy
            Console.WriteLine(" lockout" + dc.LockoutDuration);

            // get difference timestamp 
            DateTime dateTimeStamp = DateTime.Now.Subtract(-dc.LockoutDuration);

            // Hard coded domain name
            String pathRootDSE = String.Format("LDAP://dc=softcom,dc=imanami,dc=lab");

            DirectoryEntry dse = new DirectoryEntry(pathRootDSE);

            // list of properties to fetch
            string[] policyAttributes = new string[] {
            "distinguishedName" , "cn","lockoutTime"
                  };

            // filter to search the items
            string filterString = string.Format("(&(objectCategory=Person)(objectClass=user)(lockoutTime>={0}))", dateTimeStamp.ToFileTimeUtc().ToString());

            DirectorySearcher ds = new DirectorySearcher(
              dse,
              filterString,
              policyAttributes,
              SearchScope.Subtree
              );

            //search
            SearchResultCollection result = ds.FindAll();

            // loop n print users
            foreach (SearchResult item in result)
            {
                Console.WriteLine("Item: " + item.Properties["cn"][0].ToString() + " " + item.Properties["distinguishedName"][0].ToString() + " " + item.Properties["lockoutTime"][0].ToString());
            }
            //wait...
            Console.ReadLine();
       

Happy exploring AD related application architecture.

References:
http://msdn.microsoft.com/en-us/library/ms676843(v=vs.85).aspx
http://support.microsoft.com/kb/269181
http://technet.microsoft.com/en-us/library/cc773263(WS.10).aspx