Easiest way to setup Form Based Authentication with Active Directory LDAP in Claims Based Web Apps for SharePoint 2010

In this post, I am going to explain the quickest possible way to enable Form Based Authentication with Active Directory which will use the new Claims Based Authentication. First thing to be aware of that, we cannot modify an existing web app which was created using Classic Mode Authentication. If we see any existing web app which uses only Windows Authentication in Classic Mode, we will see that FBA option is disabled there. So, in order to achieve our goal, we need to create a new web application and choose the following Claims Based instead of Classic Mode:

Go to Central Admin –> Application Management –> Manage Web Application –> Click New:

image

When we select Claims Based Authentication from the above figure, a new section opens up in the screen

image

In the above figure, you can see I have enabled both Windows Authentication and Form Based Authentication. I could mention the ASP.NET membership provider name here too. But, As I need to configure few things beforehand, I chose to configure this later. So, we now need to modify three web.config files for the following three applications:

1. Central Administration Site

2. The Web Application which we will be used for Claims Based Authentication.

3. Security Token Web Service Application

Go to IIS 7 of your SharePoint Web Server. Select the Central Administration Website. Right click and select “Explore” which will open up a WIndows Explorer where you will find the web.config file. Open up the configuration file using a notepad or Visual Studio and look for <system..web>.

Right before the beginning of <system.web>, Add the following section:

<connectionStrings>
   <add name="adconn"
        connectionString="LDAP://kfupm.edu.sa:389/dc=kfupm,dc=edu,dc=sa" />
</connectionStrings>
Here, “adconn” is my connection string name and connectionString holds the URL of my LDAP. After <system.web>, add the following:
<membership defaultProvider="admembers">
   <providers>
      <add name="admembers"
           type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           connectionStringName="adconn"
           enableSearchMethods="true"
           attributeMapUsername="sAMAccountName" />
   </providers>
</membership>
I have given my provider name as admembers and mentioned the connectionStringName which I declared before.
Now, we need to follow the same for rest of the two web.config files.
Now, Right Click the Web App for which we are trying to configure FBA and click “Explore” which will open up a location like “C:\inetpub\wwwroot\wss\VirtualDirectories\[PortNumber]” where you will see the web.config file for your web app. Open this file in the same manner as you did for central admin site and make the same changes:
Now, for the first section it will be the same (connectionStrings section). For the membership part, a membership provider is automatically added when we created this web app selecting Claims Based Authentication. So, we will look for <membership tag and edit the section as following:
<membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="admembers" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="adconn" enableSearchMethods="true" attributeMapUsername="sAMAccountName" />
      </providers>
    </membership>

In the above snippet, notice that, I only added an entry for membership provider admembers. The other settings were created when we created the web app. Right after this, you will find another settings for roleManager where you can add any active directory role. As I didn’t create any role for my purpose, I am not going to enter anything in that section here. This completes the second part.

Finally, we need to do the same for Security Token Web Service App’s web.config file. To do this, expand the SharePoint Web Services site from IIS and you will see the SecurityTokenServiceApplication.
image

Right Click and select “Explore” to open up the directory where you will find the web.config file for this application. Here, you will not find any <system.web> sections. So what you need to do is, go to the bottom of this file where you will find </configuration> and right before this tag, add the following:

<connectionStrings>
  <add name="adconn"
       connectionString="LDAP://kfupm.edu.sa:389/dc=kfupm,dc=edu,dc=sa" />
/connectionStrings>
system.web>
<membership defaultProvider="admembers">
  <providers>
     <add name="admembers"
          type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
          connectionStringName="adconn"
          enableSearchMethods="true"
          attributeMapUsername="sAMAccountName" />
  </providers>
/membership>
/system.web>

Do not forget to change the connection string for your Active Directory LDAP.

Now, go to the central admin and go to Application Management –> Manage Web App. Select your web app we created before for Claims Based authentication and choose Authentication Providers from the ribbon. From the pop up window, click on Default under zone and you will get the following window:

image

Note that, I have mentioned the provider name under ASP.NET Membership provider settings. There are other options here as well like to choose whether to use the default sign in page or to use a custom page for Forms Based Authentication. Now, my web application is ready to use both Windows and Form based authentication which will utilize the new Claims Based Authentication technology.

Let us now create a site collection to see for real. Go to Application Management –> SIte Collections –> Create Site Collection page. After setting the name and template for the new site collection, while choosing to  Site Collection Administrator, if you search for users you should get something like the following window:

image

As expected, I now get two instances for one name (one in Active Directory and another one is getting pulled by the new form based configuration to use with Forms Authentication). After creating this site, if I try to sign in the new site collection, I will get the following window:

image

You can see that two different authentications are now coming under the drop down box inside the default sign in page for my web application. If I now choose Forms Authentication, I will get the following window:

image

After that, if I click Sign In, I can successfully login to my new site collection. The following is the screenshot of it:

image

That’s it. In the next post, I will explain how you can create a custom Login Page for this Form Based Authentication and also how to create a custom Login Web Part for the same purpose which will enhance the functionality and provide better user experience in real life scenario.

Advertisements

Create a Dynamic User Control using Silverlight Client Object Model –upload Image, Add, Create, Delete both List and List items and populate current items [Part 2]

In my last post, I talked about how we can create new list, delete a list using Client Object Model. In this part, I am going to talk about how to create new List Items, retrieve those, update and delete items. I will also talk about how to upload an image directly to an Image Column of a list from the same Silverlight user control.

Retrieving List Items:

If you read the previous post, I had one column called “category” from the six fields that I created for the List “TechnoProducts”. In order to populate the drop down box “Category”, in this particular example, I click on “Get List Items” button to populate my user control fields. If there is no existing item in the list, it will only populate the drop down box with some predefined categories that I mentioned while creating the list.

Here, I wanted to show the titles of each List Items once you click “Get List Items” button and then after clicking on each item, I wanted to show the details.

For this to happen, I added the following code inside my event handler for clicking on Get Items Button.

private void txtGetItems_Click(object sender, RoutedEventArgs e)
{
    if (listProducts.Items.IsReadOnly)
        listProducts.ItemsSource = null;
    else
        listProducts.Items.Clear();
    CreateProgressBar("Getting Product Items..");
    GetItems();
}

Here, as you can see first of all, I am clearing the existing values of Products List and then creating a progress bar to let the user know about what is going to happen and then I am calling a method to get the items which is as below:

private void GetItems()
{
    var web = context.Web;
    getList = web.Lists.GetByTitle("TechnoProducts");
    context.Load(getList);

    techItems = getList.GetItems(CamlQuery.CreateAllItemsQuery());
    context.Load(techItems);
    context.ExecuteQueryAsync(getItemSuccess, failedCallback);
}
private void getItemSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        foreach (var item in techItems)
        {
            item.Tag = item["Title"].ToString();
        }
      
        if (listProducts.Items.IsReadOnly)
            listProducts.ItemsSource = null;
        else
            listProducts.Items.Clear();
      
        listProducts.ItemsSource = techItems;
        cbCategory.ItemsSource = new string[] { "Electronics", "Desktop Pc", "Laptop", "Mobile", "PC Accessories" };
        
    });
}

In this above code, I have called my List and then stored the values of the List items in a ListItemCollection object which I declared globally. Inside the successfulcallback event handler, at first, I have stored the Title of each list item inside the Tag property which I used to display the names inside Products ListBox. I set the data source of my ListBox as this ListItemCollection object and populated the drop down box with the string array.

Displaying the details of each List Item:

After retrieving the list items, I now wanted to show the details of each items. So if there is any list item, I am going to show it inside the user control. I will talk about how I added these items shortly after this.

   private void listProducts_SelectionChanged(object sender, SelectionChangedEventArgs e)
   {
       lblImageStatus.Content = string.Empty;
       if (listProducts.SelectedIndex == -1)
       {
           txtTitle.Text = string.Empty;
           txtModel.Text = string.Empty;
           txtStock.Text = string.Empty;
           txtUnitPrice.Text = string.Empty;
           cbCategory.SelectedIndex = 0;
           chkDiscontinued.IsChecked = false;
           productImg.Source = null;
           txtTitle.Focus();
       }
       else
       {
           var item = (ListItem)listProducts.SelectedItem;
           txtTitle.Text = item["Title"].ToString();
           txtModel.Text = item["ModelNo"].ToString();
           txtStock.Text = item["InStock"].ToString();
           txtUnitPrice.Text = item["UnitPrice"].ToString();
           var chk = (bool)item["Discontinued"];
           chkDiscontinued.IsChecked = chk;
           
           BitmapImage img = new BitmapImage();
           var url=(FieldUrlValue)item["Image"];
           if (url != null)
           {
               string urlvalue = url.Url.ToString();
               productImgUrl = urlvalue;

               Uri uri = new Uri(urlvalue);
               img.UriSource = uri;
           }
           if (img != null)
               productImg.Source = img;
       
           var cbItems = cbCategory.Items;
           for (int i = 0; i < cbItems.Count; i++)
           {
               string cbItem = cbItems[i].ToString();
               if (cbItem == item["Category"].ToString())
               {
                   cbCategory.SelectedIndex = i;
                   break;
               }
           }

       }

   }

I added the code inside the Selection Changed Event handler and what I did was checked the Mode of the current state whether it is in Add Items state or not. If not, then I went with showing each property of a selected list item. Notice that, to show the Image of an specific item, I created a BitmapImage object to get the property and display inside my user control where I set the source as current item’s Image. Lastly, I set the current category for that item which I tried to match using a for loop (There are better ways to do it though!).

This is a screenshot of how it looks like once I selected a List item from the ListBox:

image

Adding a New List Item:

For adding a new item, I wanted to clear out my user control, so I added the following code:

private void txtAddItems_Click(object sender, RoutedEventArgs e)
{
    listProducts.SelectedIndex = -1;
    productImgUrl = string.Empty;
}

And after filling out each field inside the user control and clicking the save button, I get the following screen:

image

After adding an item, I also added a notification message whether or not the item was added in the list. Now, here comes the big part: To save the list item based on its mode whether adding or editing an item.

Saving and Updating a List Item:

Below is the code for event handler of Save button:

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    ListItem item = null;
    if (listProducts.SelectedIndex == -1)
    {                        
        ListItemCreationInformation lci = new ListItemCreationInformation();
        item = getList.AddItem(lci);
    }
    else
    {       
        item = (ListItem)listProducts.SelectedItem;   
    }
   
    if (imgFile != null)
    {
        context.Load(web);
        List picLib = web.Lists.GetByTitle("RadiantProducts");
        context.Load(picLib);

        byte[] bFile = ReadFully(imgFile.OpenRead());
        FileCreationInformation file = new FileCreationInformation();
        file.Content = bFile;
        string picUrl = imgFile.Name.ToString();
        file.Url = "http://www.teamradiant.net/RadiantProducts/&quot; + picUrl;
        productImgUrl = file.Url;
        file.Overwrite = true;
        Microsoft.SharePoint.Client.File newFile = picLib.RootFolder.Files.Add(file);
        context.Load(newFile);
        context.ExecuteQueryAsync(succeedCallback, failedCallback);
    }

    item["Title"] = txtTitle.Text;
    item["Category"] = cbCategory.SelectedItem;
    item["ModelNo"] = txtModel.Text;
    item["UnitPrice"] = txtUnitPrice.Text;
    item["InStock"] = txtStock.Text;
    item["Discontinued"] = chkDiscontinued.IsChecked;
    item["Image"] = productImgUrl;
    item.Update();
    if(listProducts.SelectedIndex == -1)
        CreateProgressBar("Adding Product Item..");
    else
        CreateProgressBar("Updating Product..");
    context.ExecuteQueryAsync(saveSuccess, failedCallback);

}
private void saveSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        GetItems();
        lblImageStatus.Content = "Saved Successfully";
    });
}

As you can see here, I checked the mode whether I am adding or updating an Item. If it is in Add mode, I created a ListItemCreationInformation object and adding this info to my existing List getList which I got from calling GetItems method and assigned it to a new List item object.

To add a new image, I declared a FileInfo variable imgFile which I used to check the mode of adding or updating. To add an image directly to my List TechnoProducts, I have created an Picture Library List named RadiantProducts. As you might know that, in SharePoint, we can only add an existing Image URL to an Image Column of a list; so, behind the scene, first of all, I added the selected image using an Open File Window, read the file as Bytes and after that, I set the URL of this image using the name of the Image File. Then, I stored the image directly to the root folder of the Picture Library. Here is the code to read the image as a binary file:

public static byte[] ReadFully(Stream input)
  {
      byte[] buffer = new byte[16 * 1024];
      using (MemoryStream ms = new MemoryStream())
      {
          int read;
          while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
          {
              ms.Write(buffer, 0, read);
          }
          return ms.ToArray();
      }
  }

After that, it is pretty simple as I just assigned the current property of the List item with the values from the user control and updated it. Notice that, for the image I now can set the Image Url as I stored it beforehand.

Here is the code for selecting an image which opens up a Open File Dialog window:

private void btnSelect_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter = "JPEG Files (*.jpg)|*.jpg|PNG Files (*.png)|*.png";
    ofd.Multiselect = false;
    ofd.ShowDialog();
    imgFile = ofd.File as FileInfo;
    if (imgFile != null)
    {
        image = new BitmapImage();
        image.SetSource(imgFile.OpenRead());
        productImg.Source = image;
    }
    
}

In this above code, it will just open up a window to select a File of JPG/PNG type and after selecting it will display in the Image control as I set the source after reading the file. After saving a list item, I called the previously defined GetItems method to retrieve the updated List where it will also show if there is any newly added item.

Deleting a List Item:

Following is the code by which I can delete a selected list item after clicking on “Delete Item”:

private void btnDeleteItem_Click(object sender, RoutedEventArgs e)
{
    var web = context.Web;
    var item1 = (ListItem)listProducts.SelectedItem;
    string delTitle = item1["Title"].ToString();
    var delList = web.Lists.GetByTitle("TechnoProducts");
    var query=new CamlQuery();
    query.ViewXml = "<View>" +
        "<Query>" +
        "<Where><Eq>" +
        "<FieldRef Name='Title'/>" +
        "<Value Type='Text'>" + delTitle + "</Value>" +
        "</Eq></Where>" +
        "</Query>" +
        "<ViewFields>" +
        "<FieldRef Name='ID'/>" +
        "<FieldRef Name='Title'/>" +
        "</ViewFields>" +
        "</View>";
     

     techItems = delList.GetItems(query);
     context.Load(techItems);
     context.ExecuteQueryAsync(delCallSuccess, failedCallback);
   
}

 

In this above code, I am getting the current web from current client context. Then, I created a variable to get Selected List Item from the List Box. After that, I stored the Title of that item in a string variable which I used inside the CAML query later. The CAML query will retrieve ID and Title of an item from the List which matches the Title of the selected item. I then stored in inside a globally defined ListItemCollection which I used before and then called ExecuteQueryAsync . Following is the code for the successful callback of this action:

private void delCallSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        foreach (ListItem item in techItems)
        {
            item.DeleteObject();
        }
        context.ExecuteQueryAsync(deleteItemSuccess, failedCallback);
    });
}
private void deleteItemSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        GetItems();
        lblImageStatus.Content = "Item Deleted Successfully";
    });
}

In this above code, I deleted the item using DeleteObject method from SharePoint’s Client Object Model API. As I am only deleting one item, the for loop here will only get executed once. After that, I have another callback where for the successful handler, I am calling GetItems  method to show the updated List Items with a message that the item was deleted successfully. Here is the screenshot:

image

Here, I am deleting the product Samsung and right after that I get the following screen I don’t see this item anymore inside my List Box.

image

As you can see, after deleting the item, I can see the updated items Title inside the List Box.

That’s all for today. Next time, I will talk about how you can use Client Object Model using Javascript/ECMAscript. Thanks for reading and I will always appreciate if you can come up with a better solution and technique.

Create a Dynamic User Control using Silverlight Client Object Model –upload Image, Add, Create, Delete both List and List items and populate current items [Part 1]

Today, I am going to discuss about using the Silverlight Client Object Model in SharePoint 2010. You can actually develop scintillating user controls using Silverlight in SharePoint 2010. I am going to discuss the development work in two phases. In this part, I am going to show you how you can create and delete a List.

Alright, to begin with, let me clarify few things: Silverlight Client Object Model almost works in the same way as .NET Managed mode except in few areas, one of them is executing the request. In .NET Managed mode, the actual request and response happens synchronously whereas in Silverlight, it is Asynchronous. Therefore, we have to use ExecuteQueryAsync instead of ExecuteQuery. ExecuteQueryAsync must have two event handlers as parameters: one for a successful callback and another for a failed callback. Another big difference is that in .NET Managed mode, you code set the Authentication mode to default, form based, windows. But, here you do not have such option. We have two options to test our Silverlight user control in COM:

First method: To upload the build "XAP” file in SharePoint’s document library and then add a Silverlight Web Part and define the URL there.

Second method: To test the user control right from the VS2010, we need to create an XML file inside the Web Application Root (inside Intepub\wwwroot\…[Your Port No. for Web App] Directory] and name that file as ClientAccessPolicy.xml as by default SharePoint does not allow cross domain access [When you test your user control using VS2010, it uses localhost to test and it is considered as Cross Domain against your SharePoint web app].

Let me begin with explaining the demo:

First of all, I created a new Silverlight Project from Visual Studio 2010. While creating the project, VS will prompt you whether you want to add an ASP.NET test web page to test your user control; choose ‘Yes’ and always remember to select ASP.NET 3.5 version as SharePoint does not support framework 4 as of now. After that, your solution explorer should look like this:

image

You can see that I named my project as “DynamicListSilver”. The upper one shows my XAML file and at the bottom you can see the Test Page with a web.config which was automatically created by VS.

Now, I have designed my User Control as below:

image

Here, at the top, you can see some buttons which are self-explanatory. Beneath those buttons, I have one List Box to show my current List items and a dynamic Progress Bar. At the right side, the details of a particular list item will be shown once an item is selected from the List Box. Below the Product Image label, there is a status bar label which will show the messages from successful and failed callback and also display the actual happening of a list item and the list. Beneath that, right above the Save button, I have added an Image control which will be displayed for the current Item if any image exists for that and after selecting an Image locally to upload using “Select” button which will open up a File Browser Dialogue.

Here is the code for this particular user control:

<UserControl x:Class="DynamicListSilver.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    mc:Ignorable="d"
    d:DesignHeight="483" d:DesignWidth="604" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" Loaded="UserControl_Loaded">

    <Grid x:Name="LayoutRoot" Background="White" Height="488" Width="577">
        <StackPanel Height="485" HorizontalAlignment="Left" Margin="10,0,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="561"></StackPanel>
        <Canvas Name="canvas1" Margin="10,0,0,12" HorizontalAlignment="Left" Width="555">
            <Button Content="Get List Items" Height="23" Name="txtGetItems" Width="87" IsTabStop="True" VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center" IsEnabled="True" IsHitTestVisible="True" Canvas.Left="81" Canvas.Top="0" Click="txtGetItems_Click" />
            <Button Content="Create List" Height="23" Name="txtCreate" Width="75" Canvas.Left="0" Canvas.Top="0" Click="txtCreate_Click" />
            <Button Canvas.Left="383" Canvas.Top="0" Content="Delete List" Height="23" Name="btnDelete" Width="75" Click="btnDelete_Click" />
            <ListBox Canvas.Left="6" Canvas.Top="29" Height="401" Name="listProducts" ItemsSource="{Binding}" Width="162" SelectionChanged="listProducts_SelectionChanged" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Tag}" />
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>

            </ListBox>
            <dataInput:Label Canvas.Left="259" Canvas.Top="29" Height="26" Name="label1" Width="139" Content="List item Details" FontWeight="ExtraBlack" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="62" Height="24" Name="label2" Width="66" Content="Title" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="92" Height="24" Name="label3" Width="66" Content="Category" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="122" Height="24" Name="label4" Width="66" Content="Unit Price" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="155" Height="24" Name="label5" Width="66" Content="Stock" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="214" Height="24" Name="label6" Width="74" Content="Discontinued" />
            <TextBox Canvas.Left="259" Canvas.Top="62" Height="23" Name="txtTitle" Width="189" />
            <ComboBox Canvas.Left="261" Canvas.Top="92" Height="23" Name="cbCategory" Width="137" />
            <TextBox Canvas.Left="261" Canvas.Top="122" Height="23" Name="txtUnitPrice" Width="120" />
            <TextBox Canvas.Left="261" Canvas.Top="151" Height="23" Name="txtStock" Width="89" />
            <CheckBox Canvas.Left="261" Canvas.Top="214" Content="Yes/No" Height="24" Name="chkDiscontinued" Width="69" />
            <Button Canvas.Left="261" Canvas.Top="436" Content="Save" Height="23" Name="btnSave" Width="75" Click="btnSave_Click" />
            <Button Canvas.Left="174" Canvas.Top="0" Content="Add Item" Height="23" Name="txtAddItems" Width="104" Click="txtAddItems_Click" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="241" Height="20" Name="label7" Width="84" Content="Product Image" />
            <Button Canvas.Left="261" Canvas.Top="241" Content="Select.." Height="23" Name="btnSelect" Width="75" Click="btnSelect_Click" />
            <Image Canvas.Left="259" Canvas.Top="293" Height="137" Name="productImg" Stretch="Fill" Width="237" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="185" Height="24" Name="label8" Width="74" Content="Model No." />
            <TextBox Canvas.Left="261" Canvas.Top="185" Height="23" Name="txtModel" Width="120" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="267" Content="" Height="20" Name="lblImageStatus" Width="375" />
            <Button Canvas.Left="283" Canvas.Top="0" Content="Delete Item" Height="23" Name="btnDeleteItem" Width="94" Click="btnDeleteItem_Click" />
        </Canvas>
    </Grid>
</UserControl>

Let me now go through with each segment of this solution:

CREATING A LIST

To create a list in Client Object Model, there is few differences than Server Object Model as we define the List Columns and fields inside XML directly. In this demo, on my User Control Load event, I added the following code the load the current Client Context:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            context = ClientContext.Current;
            if (context == null)
                context = new ClientContext("http://www.teamradiant.net/&quot;); ;
            web = context.Web;
        }

Obviously, context and web objects were declared globally to access it from any method. As you can see, the code here is exactly as we write in .NET Managed mode. Now, when I wanted to create the list in the event handler of the Button “Create List” as below:

Creating List Snippet
listProducts.Items.Clear();
CreateProgressBar("List is getting created");

var lci = new ListCreationInformation();
lci.Title = "TechnoProducts";
lci.Description = "A List of Electronics & Techno Products";
lci.QuickLaunchOption = QuickLaunchOptions.On;
lci.TemplateType = (int)ListTemplateType.GenericList;
list=web.Lists.Add(lci);
var fields = list.Fields;

var titleField = fields.GetByTitle("Title");
titleField.Title = "ProductName";
titleField.Update();

As you can see from the above code that first of all, I cleared the List Box (on the left side). Then, I created a Progress Bar which will be populated dynamically inside the list box.

When you create a custom List in SharePoint, by default, it creates the “Title” field automatically. So here, I changed the column name “Title” to “ProductName”. Now, updating the field won’t actually happen unless we call the executequeryasync method. I have not done that yet as I need to some more fields for my List.

Here is the code for the progress bar:

public void CreateProgressBar(string progressContent)
{
    
    if (listProducts.Items.IsReadOnly)
        listProducts.ItemsSource = null;
    else
        listProducts.Items.Clear();

    listProgress = new ProgressBar();
    listProgress.Width = 100;
    listProgress.Height = 15;
    listProgress.Value = 10;
    listProgress.Maximum = 100;
    listProgress.Background = new SolidColorBrush(Colors.Gray);
    listProgress.Foreground = new SolidColorBrush(Colors.White);
    _timer.Duration = TimeSpan.FromMilliseconds(10);
    _timer.Completed += new EventHandler(_timer_Completed);
    _timer.Begin();

    Label lblProgress = new Label();
    lblProgress.Content = progressContent;
    listProducts.Items.Add(lblProgress);
    listProducts.Items.Add(listProgress);
}

And, here is the code for the Timer Event Handler:

void _timer_Completed(object sender, EventArgs e)
      {
          if (listProgress.Value < listProgress.Maximum)
          {
              listProgress.Value++;
              _timer.Begin();
          }
      }

As I used the progress bar on various occasions, I declared the following objects globally:

Storyboard _timer = new Storyboard();
 ProgressBar listProgress;

Next, I need to add the other columns or fields for my list. Now, to do that I will also need to pass a schema for each field that I add. As the schema is pretty big and hard to memorize, what I did was created a copy of exact same list in SharePoint web front end and got the values for schema using Server Explorer. [Open Server Explorer-> Go to your Web App-> Site Collection –> Site –> Fields and from the properties window, get the schema xml]

Then, I added the fields as below:

var categoryField = fields.AddFieldAsXml(@"<Field Type='Choice' DisplayName='Category' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' Format='Dropdown' FillInChoice='FALSE' StaticName='Category' Name='Category'><Default>Electronics</Default><CHOICES><CHOICE>Electronics</CHOICE><CHOICE>Desktop PC</CHOICE><CHOICE>Laptop</CHOICE><CHOICE>Mobile</CHOICE><CHOICE>PC Accessories</CHOICE></CHOICES></Field>", true, AddFieldOptions.DefaultValue);
var unitPriceField = fields.AddFieldAsXml(@"<Field Type='Currency' DisplayName='UnitPrice' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' Decimals='2' LCID='1033' StaticName='UnitPrice' Name='UnitPrice' />", true, AddFieldOptions.DefaultValue);
var stockField = fields.AddFieldAsXml(@"<Field Type='Number' DisplayName='InStock' Required='FALSE' EnforceUniqueValues='FALSE' Indexed='FALSE' Decimals='0' StaticName='InStock' Name='InStock' />", true, AddFieldOptions.DefaultValue);
var modelField = fields.AddFieldAsXml(@"<Field Type='Text' DisplayName='ModelNo' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' MaxLength='255' StaticName='ModelNo' Name='ModelNo' />", true, AddFieldOptions.DefaultValue);
var discontinuedField = fields.AddFieldAsXml(@"<Field Type='Boolean' DisplayName='Discontinued' EnforceUniqueValues='FALSE' Indexed='FALSE' StaticName='Discontinued' Name='Discontinued'><Default>0</Default></Field>", true, AddFieldOptions.DefaultValue);
var imageField = fields.AddFieldAsXml(@"<Field Type='URL' DisplayName='Image' Required='FALSE' EnforceUniqueValues='FALSE' Indexed='FALSE' Format='Image' StaticName='Image' Name='Image' />", true, AddFieldOptions.DefaultValue);
context.ExecuteQueryAsync(listcreatesuccess, failedCallback);

Now, when you add the Schema XML from the existing fields of a List there are some extra things which you should delete (generated IDs) and keep stuff clean which looks similar to the above code. I have added 6 more fields in this list which are: Category (Drop Down Choice Type), Unit Price (Currency type), InStock (Number type), ModelNo (Number Type), Discontinued (Yes/No Checkbox type) and an Image (Image type) which will hold the Image url for list item.

As you can see at the bottom of the code, I have called ExecuteQueryAsync which will call the server asynchronously and also passed two event handlers as parameters. Below is the code for successful callback event handler:

private void listcreatesuccess(object sender, ClientRequestSucceededEventArgs e)
 {
     this.Dispatcher.BeginInvoke(() =>
     {

         listProducts.Items.Clear();
         var msg = string.Format("{0} List was created at: {1}", list.Title, DateTime.Now.ToLongTimeString());
         lblImageStatus.Content = msg;
     });
 }

and here is for the failed callback:

private void failedCallback(object sender, ClientRequestFailedEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        var msg = "Error: " + e.Exception.ToString();
        listProducts.Items.Clear();
        listProducts.ItemsSource = null;
        listProducts.Items.Add(msg);

    });
}

That’s it. Now, if you click on “Create List”, your list should be created and you should see the progress bar and a message whether or not the list was created successfully with current time.

listcreated

Above one is a screenshot while creating the list and after completion, a message will be displayed if the creation was successful.

Let me now go through with deleting this list when I will click on “Delete List”.

The code for deleting this list is much simpler than creating it. Here it is:

private void btnDelete_Click(object sender, RoutedEventArgs e)
{
    CreateProgressBar("Deleting List…");
    context.Load(web, w => w.Title);
    context.Load(web.Lists);
    deleteList = web.Lists.GetByTitle("TechnoProducts");
    deleteList.DeleteObject();
    context.ExecuteQueryAsync(listdeletesuccess, listdeletefailure);
}
private void listdeletesuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        listProducts.Items.Clear();
        var msg = string.Format("List was Deleted at: {0}", DateTime.Now.ToLongTimeString());
        lblImageStatus.Content = msg;
    });
}
private void listdeletefailure(object sender, ClientRequestFailedEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        listProducts.Items.Clear();
        var msg = "Error: " + e.Exception.ToString();
        lblImageStatus.Content = msg;

    });
}

As you can see I just called the List using web.Lists.GetByTitle  and then deleted the object from the List deleteList which I declared previously.

Here is a screenshot for deleting this list:

deletelist

You can see the message here after the successful callback for deleting the List. That’s it for this part. In the next part, I am going to discuss about adding, modifying and deleting a List item and also adding an Image directly to this List.  [To Be Continued…]

Dealing with .NET Managed Code in Clinet Object Model

In SharePoint 2010, one of the major changes that Microsoft has brought in development is the Client Object Model which facilitates the developers to use SharePoint 2010 Client APIs and build client based applications such as Windows Application, Silverlight and JavaScript client apps. Today, I am going to show you a nice example of using Client Object Model in .NET Managed code.

For this, first of all, I have populated few tables (Product, Category) from Microsoft Northwind Database as SharePoint lists on my site. In this example, I will deal with two of those tables which are: Product and Category. These are the screenshots of the tables:

image

image

Note that, I have a Lookup Column named ‘Category’ in Product List which is coming from ‘CategoryName’ column of Category List.

After that, I have created a Windows Application in Visual Studio 2010 and designed the following UI:

image

You can clearly see that my intention is to get all the categories and populate them in a Combo box and Products List Box will display all the products for that particular Category and the selected Product will display Product Details inside the Product Details Grid View. I also want to enable selecting multiple products which will make my Grid View more Dynamic so that the number of products you will select from the Product List Box, the same number of Product Details information will be there in the Grid View.

To achieve my goal, I have added the following code inside my Form Load method to initialize the items of Category Combo Box:

Form Load
  context = new ClientContext("http://www.teamradiant.net/&quot;); //Creating New Client Context
  context.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication; //Setting the Authentication Mode
  FormsAuthenticationLoginInfo formLoginInfo=new FormsAuthenticationLoginInfo("morshed","mypassword"); //Providing credentials for Forms Auth
  context.FormsAuthenticationLoginInfo = formLoginInfo; //Passing the credentials to Current Client Context
  web = context.Web;
                  
  var list = web.Lists.GetByTitle("Category"); //Getting the 'Category' List
  var query = new CamlQuery(); //Create a new CAML query
  query.ViewXml = "<View>" +
                 "<ViewFields>" +
                 "<FieldRef Name='CategoryName' />" +
                 "<FieldRef Name='Title' />" +
                 "</ViewFields>" +
                 "</View>"; //CAML Query details
  var items = list.GetItems(query); //Receiving the items from CAML query
  context.Load(items); //Loading the items in Current Context
  context.ExecuteQuery(); //Calling the Client.svc to send the request to SharePoint server and receive the response

  var listData = new List<DictionaryEntry>(); //Creating a Dictionary Data Structure to hold the list items
  foreach (var item in items)
  {
      var data = new DictionaryEntry(item["CategoryName"], item["Title"]); //setting every list item's column value to Key and Value.
     
      listData.Add(data); //Adding the data inside the Dictionary Data Structure object
  }
  CategoryBox.DisplayMember = "Value"; //Set the Display name of Combo Box items to item["Title"]
  CategoryBox.ValueMember = "Key"; //Set the Value of Combo box items to item to item["Key"]
  CategoryBox.DataSource = listData; //Setting the Data Source of Combo Box

You can see from the above code that I am querying for two columns from Category List which are: CategoryName and Title. ‘CategoryName’ is the Lookup column  that I need to pass to the Product List to get the related products for the selected Category.

Now, I add the following code for selected index changed method of the Combo Box:

SelectedIndexChange (ComboBox)
 if (CategoryBox.SelectedIndex == -1)
     return; //If Nothing is selected
 var category = CategoryBox.SelectedValue; //Getting the Selected Value from Category Combo Box

 var list = web.Lists.GetByTitle("Product"); //Getting the 'Product' list from the current site
 var query = new CamlQuery();
 query.ViewXml = "<View>" +
                 "<Query>" +
                 "<Where><Eq>" +
                 "<FieldRef Name='Category'/>" +
                 "<Value Type='Lookup'>" + category+"</Value>" +
                 "</Eq></Where>" +
                 "</Query>" +
                 "<ViewFields>" +
                 "<FieldRef Name='ProductID'/>" +
                 "<FieldRef Name='ProductName'/>" +
                 "</ViewFields>" +
                 "</View>"; //CAML Query details to get 'ProductID' and 'ProductName' for the selected Category
 

 var items = list.GetItems(query); //Get all items from the CAML query

 context.Load(items); //Loading items
 context.ExecuteQuery(); //Calling Client.svc to send the request to the SharePoint server and get the response

 var listData = new List<DictionaryEntry>(); //Creating a Dictionary Data Structure to hold the list items
 foreach (var item in items)
 {
     var data = new DictionaryEntry(item["ProductID"], item["ProductName"]); //setting every list item's column value to Key and Value.
     listData.Add(data); //Adding the data inside the Dictionary Data Structure object
 }
 ProductListBox.DisplayMember = "Value"; //Set the Display name of List Box items to item["Title"]
 ProductListBox.ValueMember = "Key"; //Set the Value of List box items to item to item["Key"]
 ProductListBox.DataSource = listData; ////Setting the Data Source of the List box

Note that, in Client Object Model, unlike the Server Side Object, the actual Loading of list items or data does not happen until we call ExecuteQuery()  which is  synchronous for .NET Managed Code.

Now, To show multiple selected items from the Products list inside the Products Grid View, I have created the following Class:

public class Products
    {
        public string ProductID { get; set; }
        public string ProductName { get; set; }
        public string SupplierID { get; set; }
        public string QuantityPerUnit { get; set; }
    }

To show the selected Products Details in the grid view, I have added the following code block inside the Selected Index Changed method of the Products  List box:

SelectedIndexChange (ListBox)
  1. if (ProductListBox.SelectedIndex == -1)
  2.     return; //If Nothing is selected inside Product List box
  3. var product = ProductListBox.SelectedValue; //get the single selected value of Product List box
  4. string strInProduct = "";
  5.  
  6. var total = ProductListBox.Items.Count; //Total Items inside Product List Box
  7. for(int i=0; i<total ;i++)
  8. {
  9.      if(ProductListBox.SelectedItems.Contains(ProductListBox.Items[i]))
  10.     {
  11.         var product1 = new DictionaryEntry(); //Create a new Dictionary Data Object to hold multiple selected items
  12.         product1=(DictionaryEntry)ProductListBox.Items[i]; //Setting each selected item with Keys and Values
  13.         strInProduct += "<Value Type='Number'>" + product1.Key + "</Value>"; //Modifying the CAML query clause inside 'IN' to check a range of items
  14.     }
  15. }
  16.  
  17. var list = web.Lists.GetByTitle("Product"); //Calling the 'Product' list of current site
  18. var query = new CamlQuery();
  19. query.ViewXml = "<View>" +
  20.                 "<Query>" +
  21.                 "<Where><In>" +
  22.                 "<FieldRef Name='ProductID'/><Values>" +
  23.                 strInProduct +
  24.                 "</Values></In></Where>" +
  25.                 "</Query>" +
  26.                 "<ViewFields>" +
  27.                 "<FieldRef Name='ProductID'/>" +
  28.                 "<FieldRef Name='ProductName'/>" +
  29.                 "<FieldRef Name='SupplierID'/>"+
  30.                 "<FieldRef Name='QuantityPerUnit'/>"+
  31.                 "</ViewFields>" +
  32.                 "</View>"; //Selecting 'ProductID', 'ProductName', 'SupplierID' and 'QuantityPerUnit' for each Product which are IN the range of selected items
  33.  
  34. var items = list.GetItems(query); //Getting the items from CAML query result
  35.  
  36. context.Load(items); //Loading the items in Current Context
  37. context.ExecuteQuery(); //Calling the Client.svc to send request to SharePoint server and get the response
  38.  
  39. List<Products> spProducts = new List<Products>(); //Create a List of 'Products' class type which is already defined
  40. foreach (ListItem item in items)
  41. {
  42.     spProducts.Add(new Products
  43.     {
  44.         ProductID = item["ProductID"].ToString(),
  45.         ProductName=item["ProductName"].ToString(),
  46.         SupplierID=item["SupplierID"].ToString(),
  47.         QuantityPerUnit=item["QuantityPerUnit"].ToString() //Setting each property of 'spProducts' list which is 'Products' class type   
  48.     });
  49. }
  50. gvProductDetails.DataSource = spProducts; //Setting the Data Source for the Grid View with 'spProducts' list

That’s basically it. I have commented about each line of code explaining the details for your understanding.

Now, I will be able to run this application from any machine as this app is using Client Object Model. As long as you use two DLLs in your application (Microsoft.SharePoint.Client & Microsoft.SharePoint.Client.Runtime), you can get the advantage of Client Object Model APIs from any application. Here is a screenshot of the application I discussed until now:

image

As you can see that all the Products for a particular category is showing up inside the list box and the details of those products are being shown inside the Grid View.