Thursday, January 29, 2009

ASP.net MasterPage Advanced

1. Dynamically Setting MasterPage At Runtime

MasterPage can be set dynamically at runtime in Pre_Init method of Page.

protected void Page_PreInit(object sender, EventArgs e)
    {
        Page.MasterPageFile = “<virtual path of .masterfile>";
    }

2. Strongly Type Access Of MasterPage And Its Properties.
 
MasterPage.aspx.cs
public partial class MainMaster : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    { 
    } 
 
    public string PageTitle
    {
        get
        {
            return Page.Title;
        }
        set
        {
            Page.Title = value;
        }
    }
}

Now in Content Page need for access PageTitle Property.

In Content Page use @MasterType directive.

<%@ Page Language="C#" MasterPageFile="~/MainMaster.master" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Title="Untitled Page" %>
<%@ MasterType VirtualPath="~/MainMaster.master" %>

//Default2.aspx.cs

protected void Page_Load(object sender, EventArgs e)
    {
        Master.PageTitle = "By use of MasterType";
    }
If @MasterType directive is not used than you can not access custom property of MasterPage . You are only limited to access MasterPage class property.
Note: When @MasterType directive used than it is not allowed to set page dynamically. It gives you type cast error as it try to convert object of one type to another type.

3. Access MasterPage Properties Using Reflection.   

By use of reflection you can also set property of master page.
For example access PageTitle Property (. It is not neccessary to specify MasterType directive on Page).

System.Reflection.PropertyInfo pinfo =  Page.Master.GetType().GetProperty("PageTitle");
        if (pinfo != null)
        {
pinfo.SetValue(Page.Master, "This is test reflection : Default", null);
        }

This approach is good if your requirement is set to masterpage at runtime.

4. By Use Of Common Interface For All MasterPage. 
    
Use this approach when decided that certain property must supported by MasterPage. In such case create one interface and that must be implemented by each of required masterpage.

// App_Code IMasterPageProperties.cs
public interface IMasterPageProperties
{
    string PageTitle
    {
        get;
        set;
    }
}


//SeconMaster.master.cs
public partial class SecondMaster : System.Web.UI.MasterPage , IMasterPageProperties
{
  //  Interface Implementation
  public string PageTitle
    {
        get
        {
            return Page.Title;
        }
        set
        {
            Page.Title = value;
        }
    }
}

// Defalt.aspx.cs (Page_Load event just for example)IMasterPageProperties property = Page.Master as IMasterPageProperties;
if (property != null)
        {
            property.PageTitle = "By use of Interface";
        }

Note : Try to cast Page.Master as Interface Type. This approach is good and cover both explicit and implicit implementation of interface.
5. By Use Of Abstract Base Class For MasterPage.

Create one abstract class . (Possibly in App_Code).

public abstract class BaseMasterPage : MasterPage
{
    public string PageTitle
    {
        get
        {
            return Page.Title;
        }
        set
        {
            Page.Title = value;
        }
    }
}

Now create new MasterPage ( I name it Third.master).  In normal case all masterpage inherits from MasterPage Class. Now ThirdMaster class should inherits from BaseMasterPage Class.

This is how Third.master.cs look like.

public partial class Third : BaseMasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
       this.PageTitle = "By use of abstarct base class";
    }
}

Saturday, January 24, 2009

Batch Update In SharePoint

SharePoint support batch update in List by webservice and SharePoint object model.

For Example i used sample Custom List (Orders).

image

1. By Use of Web Service.

SharePoint webservice allows update list items as a batch.At a time only one list can be updated by single webservice call.

CAML That use for Batch Update. Here i update item with ID 2 and create new item in Orders List in one webservice call.

<Batch OnError=’Continue’>
         <Method ID=’1’ Cmd=’Update’>
                <Field Name=’ID’ >2</Field>
                <Field Name=’OrderDate’ >2007-1-21</Field>
                <Field Name=’CustomerID’ >1;#Cust_1</Field>
         </Method>
         <Method ID=’2’ Cmd=’New’>
                <Field Name=’OrderDate’ >2007-1-21</Field>
                <Field Name=’CustomerID’ >2;#Cust_2</Field>
         </Method>
</Batch>

C# Code (Either Add web reference of SharePoint webservice or Create Proxy Class using wsdl.exe and use that class)

Lists lst = new Lists();
lst.Url = “http://<your site>/_vti_bin/lists.asmx”;
lst.Credentials = new System.Net.NetworkCredential ("test", "test");
XmlDocument doc = new XmlDocument();
XmlElement batchElement =  doc.CreateElement("Batch");
batchElement.SetAttribute("OnError", "Continue");
batchElement.InnerXml = "<Method ID='1' Cmd='Update'>" +
               "<Field Name='ID'>2</Field>" +
               "<Field Name='OrderDate'>2009-1-31</Field><Field Name='OrderDateTime'>2009-1-31</Field></Method><Method ID='2' Cmd='New'><Field Name='CustomerID'>1;#Cust_1</Field><Field Name='OrderDate'>2009-1-31</Field><Field Name='OrderDateTime'>2009-1-31</Field></Method>";
XmlNode result = lst.UpdateListItems("Orders", batchElement); // This line of code make webservice call to update lists.

One more thing In CAML displayed above has two bold line for CustomerID field. CustomerID is a LookUp Field. So i mention that date id;#Value (Commom lookup Structure).If you want to choose lookup value only by id then use following CAML for Field.

<Batch OnError=’Continue’>
         <Method ID=’1’ Cmd=’Update’>
                <Field Name=’ID’ >2</Field>
                <Field Name=’OrderDate’ >2007-1-21</Field>
                <Field Name=’CustomerID’  Type=’LookUp’ LookUpID=’True’>1</Field>
         </Method>
         <Method ID=’2’ Cmd=’New’>
                <Field Name=’OrderDate’ >2007-1-21</Field>
                <Field Name=’CustomerID’ Type=’LookUp’  LookUpID=’True’ >2</Field>
         </Method>
</Batch>

2. By Use Of SharePoint Object Model. (SPWeb.ProcessBatchData)

SharePoint Object Model has SPWeb class. SPWeb class has ProcessBatchData Method , this method is used to update Batch via object model. Even this method allows you update two list items in Single method call.

Sample CAML .
<?xml version="1.0" encoding="UTF-8"?>
<ows:Batch OnError="Continue">
  <Method ID="1">
    <SetList>71a9fac3-2e94-4246-8fec-41e30ea65b06</SetList>
    <SetVar Name="Cmd">Save</SetVar>
    <SetVar Name="ID">New</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDate">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDateTime">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#CustomerID">1;#Cust_1</SetVar>
  </Method>
  <Method ID="2">
    <SetList>71a9fac3-2e94-4246-8fec-41e30ea65b06</SetList>
    <SetVar Name="Cmd">Save</SetVar>
    <SetVar Name="ID">3</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDate">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDateTime">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#CustomerID">1;#Cust_1</SetVar>
  </Method>
 
<Method ID="3">
    <SetList>71a9fac3-2e94-4246-8fec-41e30ea65b06</SetList>
    <SetVar Name="Cmd">Delete</SetVar>
    <SetVar Name="ID">4</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDate">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#OrderDateTime">2009-2-21</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#CustomerID">2;#Cust_2</SetVar>
  </Method>
</ows:Batch>

In above SetList element set GUID of SPList. Here i only update Orders List but you can set another list id combine it with above by just adding another Method Element.

SetVar element with attribute Name ‘cmd’ used to identify type of functionality. It has mainly two values : Save and Delete . Save is used for either for New Item or in case of update existing item.

SetVar element with attribute Name ‘ID’ used to find out on which item it operate. ID value ‘New’ is for new item and in case of Update and Delete it should have valid id value. (Integer).

SetVar element with Name attribute value urn:schemas-microsoft-com:office:office#<Field_Name> indicate perticular field of ListItem,<Field_Name> should replace by respetive field internal name.

C# Code.

SPSite site = new SPSite("http://avani:45830");
SPWeb web = site.OpenWeb();
SPList lst = web.Lists["Orders"];
string batchFormat = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<ows:Batch OnError=\"Return\">{0}</ows:Batch>";

string methodFormat = "<Method ID=\"{0}\">" +
             "<SetList>{1}</SetList>" +
             "<SetVar Name=\"Cmd\">{2}</SetVar>" +
             "<SetVar Name=\"ID\">{3}</SetVar>" +
             "<SetVar Name=\"urn:schemas-microsoft-com:office:office#OrderDate\">{4}</SetVar>" +
             "<SetVar Name=\"urn:schemas-microsoft-com:office:office#OrderDateTime\">{5}</SetVar>" +
             "<SetVar Name=\"urn:schemas-microsoft-com:office:office#CustomerID\">{6}</SetVar>" +            
             "</Method>";

StringBuilder strmethodFormat = new StringBuilder();
strmethodFormat.AppendFormat(methodFormat, 1, lst.ID.ToString(), "Save", "New", "2009-2-21", "2009-2-21","1;#Cust_1");
strmethodFormat.AppendFormat(methodFormat, 2, lst.ID.ToString(), "Save", "3", "2009-2-21", "2009-2-21","1;#Cust_1");
strmethodFormat.AppendFormat(methodFormat, 3, lst.ID.ToString(), "Save", "4", "2009-2-21", "2009-2-21","2;#Cust_2");
string processtext = String.Format(batchFormat, strmethodFormat.ToString());

web.ProcessBatchData(processtext);

Other usefull post about Batch element creation through XLinq or Linq are
http://dotnetstep.blogspot.com/2009/01/xlinq-to-generate-batch-element-for.html
http://dotnetstep.blogspot.com/2009/01/sharepoint-to-linq.html

Wednesday, January 21, 2009

ThreadPool Wait For All Thread To Complete

I already discuss issue related to WaitHandle.WaitAll that it does not support wait for more 64 waithandle. In that article discuss about 64 chunks of thread to be executed parallel.

When you use ThreadPool and you combine it with 64 chunks of thread concept than you can not take advantage of ThreadPool. In ThreadPool all task wait for pool become empty.( Not fully). As ThreadPool have available thread then new task automatically executed.

So wait for more than 64 waithandle is needed, i found solution by following way.

C# Code.

using System;
using System.Collections.Generic;
using System.Threading;
namespace ThreadPoolWaitForAllThread
{
    class Program
    {
        static void Main(string[] args)
        {
            List<ManualResetEvent> events = new  List<ManualResetEvent>();
            for (int i = 0; i < 100; i++)
            {
                ThreadPoolObj obj = new ThreadPoolObj();
                obj.ObjectID = i;
                obj.signal =  new ManualResetEvent(false);
                events.Add(obj.signal);
                WaitCallback callback = new WaitCallback(ThreadFunction);
                ThreadPool.QueueUserWorkItem(callback,obj);
            }          
           WaitForAll(events.ToArray());
           Console.WriteLine("Compelted");
           Console.ReadLine();
        }
        static bool WaitForAll(ManualResetEvent[] events)
        {
            bool result = false;
            try
            {
                if (events != null)
                {
                    for (int i = 0; i < events.Length; i++)
                    {
                        events[i].WaitOne();
                    }
                    result = true;
                }
            }
            catch
            {
                result = false;
            }
            return result;
        }
        static void ThreadFunction(object threadobj)
        {
            ThreadPoolObj obj = threadobj as ThreadPoolObj;
            if (obj != null)
            {
                Console.WriteLine(obj.ObjectID.ToString());
                Thread.Sleep(2000); // Just Wait To Show Syncronization
                obj.signal.Set();
            }
        }
    }
    class ThreadPoolObj
    {
        public int ObjectID;
        public ManualResetEvent signal;
    }
}
By this way you can wait for more than 64 Waithandle.

Same function you can use anywhere even in case of article (WaitHandle.WaitAll Limitation). After use of this function you can avoid logic of 64 chunks, but if your thread consume more resource than it is better to run as chunks of thread instead of starting all thread at once. ThreadPool maintain this thing automatically.

Please give your comment on this.

Find BigNumber Factorial (!)

Sometime when work with mathematical application , there is need to find out “Big Number” Factorial.

By Use of Simple Factorial Function

C# Code.

using System;
class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i < 50; i++)
            {
            Console.WriteLine(i.ToString() + "\t\t" +SimpleFactorial(i).ToString());
            }
            Console.ReadLine();
        }

        static System.Int64 SimpleFactorial(System.Int64 number)
        {
            System.Int64 result = 1;
            for (System.Int64 i = 2; i <= number; i++)
            {
                result = result * i;
            }
            return result;
        }
}
If you are using above code than maximum up to value 20 you can find right answer. (Means 20!). If need is to find out Factorial larger this than you have to use FSharp Library in C#.

You can find F#Sharp Library at DownLoad .

After download , extract it and Add reference of FSharp.Core in C# Project.

using System;
using Microsoft.FSharp.Math;
class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i < 50; i++)
            {
           Console.WriteLine(i.ToString() + "\t\t" + FSharpFactorial(i).ToString());
            }
            Console.ReadLine();
        }       

        static BigInt FSharpFactorial(System.Int64 number)
        {
            BigInt num = new BigInt(number);
            return BigInt.Factorial(num);
        }
    }

By using FSharp Version of factorial 50! easily calculated. Even i test upto 20000! and It product result.

Sunday, January 18, 2009

Connect To Office 2007(Access 2007 , Excel 2007) Without Installing Entire Office 2007

Deploy application that use office 2007 ( Access 2007 , Excel 2007) and end user machine does not have Office installed on machine. In this case it is not necessary that end user machine must have office 2007 installed on machine.

Just install Data Connectivity driver.
2007 Office System Driver: Data Connectivity Components

Office 2007 Data Connectivity driver

  • ODBC to connect to Microsoft Office Access data, set the Connection String to “Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=path to mdb/accdb file”

  • ODBC to connect to Microsoft Office Excel data, set the Connection String to “Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=path to xls/xlsx/xlsm/xlsb file”

Driver is around 25mb so it can reduce overhead of office 2007.

XLinq To Generate Batch Element For SharePoint ListService

In my article (http://dotnetstep.blogspot.com/2009/01/update-datetime-column-using-webservice.html) i used SharePoint List Service to update SharePoint ListItems. In that article i manually set batchElement.InnerXml property with Xml.

When there is to many row and you want to generate it automatically then you can use XLinq.

In following example first select all items from orders List then use item id and update each item orderdate and orderdatetime column with current date and current datetime respectively.

Lists lst = new Lists();
lst.Url = “http://<your site>/_vti_bin/lists.asmx”;
lst.Credentials = new System.Net.NetworkCredential("test", "test"); // Site Administrator username and password
XmlNode resultNode = lst.GetListItems("Orders", String.Empty, null, null, int.MaxValue.ToString(), null, String.Empty);

// Use XElement To Generate Batch Element Automatically

XElement orders = XElement.Parse(resultNode.OuterXml);
XName name = XName.Get("data","urn:schemas-microsoft-com:rowset");
int methodsequence=1;
XElement updatexml =
new XElement("Batch", new XAttribute("OnError","Continue"),
from order in orders.Element(name).Elements()
// you can also use where condition over here
// for eg. where order.Attribure(“ows_ID”).value = “2”

select new  XElement("Method", 
new XAttribute("ID", (methodsequence++).ToString()), 
new XAttribute("Cmd", "Update"),
new XElement("Field", new XAttribute("Name", "ID"), order.Attribute("ows_ID").Value),
new XElement("Field",new XAttribute("Name","OrderDate"),DateTime.Now.SharepointFormatDate()),
new XElement("Field", new XAttribute("Name", "OrderDateTime"), DateTime.Now.SharepointFormatDateTime())));


Now Convert XElement to XmlNode as UpdateListItems only accept XmlNode as parameter.

XmlDocument doc=  new XmlDocument();
doc.LoadXml(updatexml.ToString());
lst.UpdateListItems("Orders",doc.FirstChild);

Update DateTime Column Using SharePoint ListService

SharePoint webservice can be used to update item or items in SharePoint List.When SharePoint List contains “Date And Time” Column with only Date or Date And Time Mode, you have to pass date or datetime in specific format so it can be update by webservice.

UpdateListItems method is used for this purpose.

To format DateTime for SharePoint Webservice, i created following extension methods.

// Extensions Method

public static class DateTimeExtensions
{
    // Only Date Column
    public static string SharepointFormatDate(this DateTime dt)
    {
        return dt.ToString("yyyy-MM-dd");
    }

    // Date And Time column
    public static string SharepointFormatDateTime(this DateTime dt)
    {
        return dt.ToString("yyyy-MM-ddTHH:mm:ssZ");
    }
}

To Update List using webservice.

System.Xml.XmlDocument doc = new System.Xml.XmlDocument();           
System.Xml.XmlElement batchElement = doc.CreateElement("Batch");
batchElement.SetAttribute("OnError", "Continue");
batchElement.SetAttribute("ListVersion", "1");
batchElement.InnerXml =”<Method ID='1' Cmd='Update'>" + "<Field Name='ID'>2</Field>" +
"<Field Name='OrderDate'>”+ DateTime.Now.SharepointFormatDate() +”</Field><Field Name='OrderDateTime'>”+ DateTime.Now.SharepointFormatDateTime()  +”</Field></Method>";

// List Serivce object  (Add web reference for this)
Lists lst = new Lists();
lst.Url = “http://<your site>/_vti_bin/lists.asmx” ;
lst.Credentials = new System.Net.NetworkCredential("test", "test");
lst.UpdateListItems(“Orders”,batchElement);

In above code <Field Name=’ID’>2</Field> is used to identify unique row that need to be update. In Sample only item with id 2 is updated. In order to update multiple items just add another method element. For example, (This update both item with id 2 and 3)

batchElement.InnetXml =

“<Method ID='1' Cmd='Update'>" + "<Field Name='ID'>2</Field>" +
"<Field Name='OrderDate'>”+ DateTime.Now.SharepointFormatDate() +”</Field><Field Name='OrderDateTime'>”+ DateTime.Now.SharepointFormatDateTime()  +”</Field></Method>" +
"<Method ID='2' Cmd='Update'>" + "<Field Name='ID'>3</Field>" +
"<Field Name='OrderDate'>”+ DateTime.Now.SharepointFormatDate() +”</Field><Field Name='OrderDateTime'>”+ DateTime.Now.SharepointFormatDateTime()  +”</Field></Method>"

Same way you can update another type of columns too.

More information available at following location.

http://msdn.microsoft.com/en-us/library/lists.lists.updatelistitems.aspx
http://msdn.microsoft.com/en-us/library/ms440289.aspx

Sunday, January 11, 2009

SharePoint to Linq

Here specially talking about SharePoint and XLinq. When you choose SharePoint webservice to get data from SharePoint List, data return by web service is in XML format. To read this data as well as filter data XLinq is more powerful.

How to Use SharePoint webservice.
1. Add Web reference or generate proxy using WSDL tool.
then

Lists lst = new Lists();
lst.Url = “http://<your site>/_vti_bin/lists.asmx”;
lst.Credentials = new System.Net.NetworkCredential("test", "test");

Now use GetListItems to retrieve all items from SharePoint List. I would suggest take scenario into consideration. If you require less data to be return from SharePoint List then use Query in GetListItems function. ( Here concentration is on XLinq so it is out of scope for this post).

XmlNode resultNode = lst.GetListItems("Customers", String.Empty, null, null, int.MaxValue.ToString(), null, String.Empty);

XElement (System.Xml.Linq) to read result into XElement
XElement customers = XElement.Parse(resultNode.OuterXml);

XName to read type of Node.
XName name = XName.Get("data","urn:schemas-microsoft-com:rowset");

Read All Node Using Linq
var filtercustomers = from ele in customers.Element(name).Elements()                                
select new {CustomerID =  ele.Attribute("ows_ID").Value , Name = ele.Attribute("ows_CustomerName").Value , City = ele.Attribute("ows_CustomerCity").Value , Country = ele.Attribute("ows_CustomerCountry").Value};

Filtering Node using XLinq
var filtercustomers = from ele in customers.Element(name).Elements()   
where ele.Attribute("ows_CustomerCountry").Value == "India" && ele.Attribute("ows_CustomerCity").Value == "Banglore"                             
select new {CustomerID =  ele.Attribute("ows_ID").Value , Name = ele.Attribute("ows_CustomerName").Value , City = ele.Attribute("ows_CustomerCity").Value , Country = ele.Attribute("ows_CustomerCountry").Value};

Join Using XLinq

1. Join Two Result
This is use full case when join in needed on filter data set.
In following code customers and orders represent two sample reslut set.

XmlNode resultNode = lst.GetListItems("Customers", String.Empty, null, null, int.MaxValue.ToString(), null, String.Empty);
            XElement customers = XElement.Parse(resultNode.OuterXml);
            XName name = XName.Get("data","urn:schemas-microsoft-com:rowset");

            var filtercustomers = from ele in customers.Element(name).Elements()         
where ele.Attribute("ows_CustomerCountry").Value == "India" && ele.Attribute("ows_CustomerCity").Value == "Banglore"                       
select new {CustomerID =  ele.Attribute("ows_ID").Value , Name = ele.Attribute("ows_CustomerName").Value , City = ele.Attribute("ows_CustomerCity").Value , Country = ele.Attribute("ows_CustomerCountry").Value};

            // Retrive data From Orders
            resultNode = lst.GetListItems("Orders", String.Empty, null, null, int.MaxValue.ToString(), null, String.Empty);
            XElement orders = XElement.Parse(resultNode.OuterXml);
            var filterorders = from ele in orders.Element(name).Elements()                                 
                                  select new { OrderID = ele.Attribute("ows_ID").Value, CustomerID = ele.Attribute("ows_CustomerID").Value.Split(new string[]{";#"},StringSplitOptions.None)[0] , OrderDate = ele.Attribute("ows_OrderDate").Value };

Join Results

var joinresult = from customerele in filtercustomers
                     join orderele in filterorders on customerele.CustomerID equals orderele.CustomerID
                     select new { customerele, orderele };

2. Directly Join Two XElement

var directjoin = from customerele in customers.Element(name).Elements()
                             join orderele in orders.Elements(name).Elements() on customerele.Attribute("ows_ID").Value equals orderele.Attribute("ows_CustomerID").Value.Split(new string[] { ";#" }, StringSplitOptions.None)[0]
                             select new { CustomerID = customerele.Attribute("ows_ID").Value, Name = customerele.Attribute("ows_CustomerName").Value, City = customerele.Attribute("ows_CustomerCity").Value, Country = customerele.Attribute("ows_CustomerCountry").Value, OrderID = orderele.Attribute("ows_ID").Value, OrderDate = orderele.Attribute("ows_OrderDate").Value };

Note: When working with webservice do care while retrieve data. Whatever data needed from single list for operation try to retrieve in single webservice call instead of making many web service call.For my point of view this will improve the performance.

Wednesday, January 7, 2009

WaitHandle.WaitAll Limitation

WaitHanlde.WaitAll function has limitation about no. of WaitHandles it can handle. As it take array of WaitHandles so one can think it can handle any no. of WaitHandles, but it is not true. It can only handle 64 waithandles. When array exceed this value it display following error.

“The number of WaitHandles must be less than or equal to 64.”

Example that cause this error.

using System;
using System.Collections.Generic;
using System.Threading;

namespace WaitHandle_Limitation
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                List<ManualResetEvent> events = new List<ManualResetEvent>();
                for (int i = 0; i < 100; i++)
                {
                    Thread th = new Thread(new ParameterizedThreadStart(ThreadRunner));
                    ThreadParamObj obj = new ThreadParamObj();
                    obj.startval = (i*100);
                    obj.endval = (i*100)+10;
                    obj.eve = new ManualResetEvent(false);
                    events.Add(obj.eve);
                    th.Start(obj);
                }
                WaitHandle.WaitAll(events.ToArray());
/* Cause error when event.ToArray return array larger than 64. Here to cause error i used 100. So it will create array of 100. */
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);           
            }
            Console.ReadLine();           
        }

        static void ThreadRunner(object thObj)
        {
            ThreadParamObj obj = (ThreadParamObj)thObj;
            if (obj != null && obj.startval < obj.endval)
            {
                for (int i = obj.startval; i < obj.endval; i++)
                {
                    Console.WriteLine("Thread ID {0} Value : {1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
                }
                obj.eve.Set();
            }

        }
    }

    class ThreadParamObj
    {
        public int startval;
        public int endval;
        public ManualResetEvent eve;
    }
}


To overcome this error one solution is make chunk of 64 thread first then wait for that all thread complete then start another 64 chunk.

// Possible Solution by use of 64 Chunks.

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

namespace WaitHandle_Limitation
{
    class Program
    {
        static void Main(string[] args)
        {
            int noofthread = 100;
            int startindex = 0;
            int endindex = 64;
            try
            {
                int noofchunk = (int)Math.Ceiling(((double)noofthread / 64.00));
                if (noofthread < endindex)
                    endindex = noofthread;
                for (int chunk = 0; chunk < noofchunk; chunk++)
                {
                    List<ManualResetEvent> events = new List<ManualResetEvent>();
                    for (int i = startindex; i < endindex; i++)
                    {
                        Thread th = new Thread(new ParameterizedThreadStart(ThreadRunner));
                        ThreadParamObj obj = new ThreadParamObj();
                        obj.startval = (i * 100);
                        obj.endval = (i * 100) + 10;
                        obj.eve = new ManualResetEvent(false);
                        events.Add(obj.eve);
                        th.Start(obj);
                    }
                    WaitHandle.WaitAll(events.ToArray());
                    startindex += 64;
                    endindex += 64;
                    if (endindex > noofthread)
                    {
                        endindex = noofthread;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);           
            }
            Console.WriteLine("Completed");
            Console.ReadLine();           
        }

        static void ThreadRunner(object thObj)
        {
            ThreadParamObj obj = (ThreadParamObj)thObj;
            if (obj != null && obj.startval < obj.endval)
            {
                for (int i = obj.startval; i < obj.endval; i++)
                {
                    Console.WriteLine("Thread ID {0} Value : {1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
                }
                obj.eve.Set();
            }

        }
    }
    class ThreadParamObj
    {
        public int startval;
        public int endval;
        public ManualResetEvent eve;
    }
}


Let me know if you have any other ideas or comment on this.

Another possible solution at http://dotnetstep.blogspot.com/2009/01/threadpool-wait-for-all-thread-to.html.

Flags Attribute For Enum

Really a very good functionality provided by “Flags Attribute” for Enum. When Enum mark with “Flags“ attribute it will work as bit field.
Here i am going to explain Enum with and without Flags Attribute.

// Enum Without Flags Attribute.
public enum Simple : int
        {
            UserRead =1,
            UserWrite = 2,
            UserExecute = 4,
            GroupRead = 8,
            GroupWrite = 16,
            GroupExecute = 32
        }

//Enum With Flags Attribute
[Flags()]
public enum WithFlagAttrib : int
        {
            UserRead = 1,
            UserWrite = 2,
            UserExecute = 4,
            GroupRead=  8,
            GroupWrite = 16,
            GroupExecute = 32
        }

In Above code Simple Enum is without attribute and in that i explicitly defined value for each of Enum. (That is just for compare both of them in same scenario).

Now Simple Example Test

int result = (int)(Simple.UserRead | Simple.UserWrite | Simple.GroupRead))
Console.WriteLine(result.ToString()); // output 11

Now value to enum

Console.WriteLine(((Simple)result).ToString()); // output 11. It will not converted to enum as none of the value is associated with 11.
In some scenario when Enum converted to value and stored in database and when it retrieve back from database , we want to convert it to Enum. This is where “Flags Attribute” real usage comes into picture.

Now With Flags Attribute Enum

int result = (int)(WithFlagAttrib.UserRead | WithFlagAttrib.UserWrite | WithFlagAttrib.GroupRead)).ToString();
Console.WriteLine(result.ToString()); // output 11

Now value to Enum

Console.WriteLine(((WithFlagAttrib)result).ToString()); // It will produce output UserRead , UserWrite , GroupRead. This is what we needed.

In both of the case when bitwise operation done at first place it produce same output but when convert value to Enum then Enum with “Flags Attribute” show right result b’coz it use bit as usage.

One thing keep into mind that when Enum create with “Flags Attribute” always assign value power of 2 starting from 1. like 1,2,4,8,16,32,64,128. (Actually it shows which bit is used for particular enum operation and it also limit this type of enum with no criteria it contains).

// For Value (11)
11 (32 bit binary value) : 00000000000000000000000000001011

Bit Position 32 16 8 4 2 1
Enum GroupExecute GroupWrite GroupRead UserExecute UserWrite UserRead
Value 0 0 1 0 1 1

Only used few bits in above table to display value 11. Now you get idea that which ever bit is on it produce in result.

For Example :
int val = 12;
Console.WriteLine(((WithFlagAttrib)val).ToString());
// 12 binary number  00000000000000000000000000001100. So output is GroupRead , UserExecute.

Let me know if you have any question or comment on this.

Note : When you search this thing MSDN please make sure that Enum mark with “Flags Attribute “  start with value 1 not by 0.

Sunday, January 4, 2009

Custom GridView Field For SharePoint LookUp Column

In Sharepoint When retrieve data using web service, there is need for customization during display in GridView. There are two ways to do this.

1. First Way

Use Template Column of GridView. Write Inline coding to Format data.

For Example .

In Codebehind file Write Following Function.

To Fetch data using web service.

public DataTable GetData()
{     

DataTable dt = new DataTable();
Lists lst = new Lists();
lst.Url = "
/_vti_bin/lists.asmx";'>http://<your site>/_vti_bin/lists.asmx";
lst.Credentials = new System.Net.NetworkCredential("test", "test"); 
XmlNode result =lst.GetListItems("Orders", String.Empty, null, null, int.MaxValue.ToString(), null, string.Empty); 
System.IO.StringReader read = new System.IO.StringReader(result.OuterXml); 
DataSet dst = new DataSet(); 
dst.ReadXml(read); 
if (dst.Tables.Count == 2 && Convert.ToInt32(dst.Tables[0].Rows[0]["ItemCount"].ToString()) > 0)
        {
            dt = dst.Tables[1];
        }
        else
        {
            dt.Columns.Add(new DataColumn("ows_CustomerID",typeof(string)));
        }
        return dt;

    }

// Enum For Display Mode of LookUpField.

public enum Mode
{
        ID,
        Value,
        All
};

// Function that format data (This Fuction must be Public or Proctected)

protected string GetLookupValue(string value,Mode LookUpDisplayMode)
    {
        string returnVal = String.Empty;
        string[] str;
        try
        {
            switch (LookUpDisplayMode)
            {
                case Mode.All:
                    returnVal = value;
                    break;
                case Mode.ID:
                    str = value.Split(new string[] { ";#" }, StringSplitOptions.None);
                    returnVal = str[0];
                    break;
                case Mode.Value:
                    str = value.Split(new string[] { ";#" }, StringSplitOptions.None);
                    returnVal = str[1];
                    break;
            }
        }
        catch
        {
        }
        return returnVal;
    }

And in ASPX Page.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" >
        <Columns>                     
            <asp:TemplateField>
                <ItemTemplate>
                    <%# GetLookupValue(Eval("ows_CustomerID").ToString(),Mode.ID) %>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField>
                <ItemTemplate>
                    <%# GetLookupValue(Eval("ows_CustomerID").ToString(),Mode.Value) %>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField>
                <ItemTemplate>
                    <%# GetLookupValue(Eval("ows_CustomerID").ToString(),Mode.All) %>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
</asp:GridView>
   

2. Other Way

This way is create custom DataBoundField that inherits from BoundField.This is required one time coding as well as avoid inline coding.

Put following class in either App_Code or create class library and use it any application you want.

//LookupField Class

public class LookupField : BoundField
    {
        public enum Mode { ID, Value, All};

        public LookupField()
        {
}

        public Mode LookUpDisplayMode
        {
            get;
            set;
        }

        protected override string FormatDataValue(object dataValue, bool encode)
        {
            dataValue = GetLookupValue(dataValue.ToString());
            return base.FormatDataValue(dataValue, encode);
        }

        protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
        {
            if(rowState == DataControlRowState.Normal || rowState == DataControlRowState.Selected || rowState == DataControlRowState.Alternate)
                base.InitializeDataCell(cell, rowState);           
            else
            {                              
                TextBox txt = new TextBox();               
                cell.Controls.Add(txt);
                txt.DataBinding += new EventHandler(OnDataBindField);               
            }           
        }

        protected override DataControlField CreateField()
        {
            return new LookupField();
        }

        protected override void OnDataBindField(object sender, EventArgs e)
        {
            Control c = sender as Control;
            if(c is TableCell)
                base.OnDataBindField(sender, e);
            else if (c is TextBox)
            {
                string val=  GetLookupValue(this.GetValue(c.NamingContainer).ToString());
                ((TextBox)c).Text = val;
            }
        }
        private string GetLookupValue(string value)
        {
            string returnVal = String.Empty;
            string[] str;
            try
            {
                switch (LookUpDisplayMode)
                {
                    case Mode.All:
                        returnVal = value;
                        break;
                    case Mode.ID:
                        str = value.Split(new string[] { ";#" }, StringSplitOptions.None);
                        returnVal = str[0];
                        break;
                    case Mode.Value:
                        str = value.Split(new string[] { ";#" }, StringSplitOptions.None);
                        returnVal = str[1];
                        break;
                }
            }
            catch
            {
            }
            return returnVal;
        }
    }

// ASPX Page.
Register Control
<%@ Register TagPrefix="CC" Assembly="App_Code" Namespace="LookupFields" %>

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"
            AutoGenerateEditButton="true" onrowediting="GridView1_RowEditing">
        <Columns>
            <CC:LookupField DataField="ows_CustomerID" LookUpDisplayMode="ID" HeaderText="CustomerID"></CC:LookupField>
            <CC:LookupField DataField="ows_CustomerID" LookUpDisplayMode="Value" HeaderText="CustomerValue"></CC:LookupField>
            <CC:LookupField DataField="ows_CustomerID" LookUpDisplayMode="All" HeaderText="Customer"></CC:LookupField>

</asp:GridView>

In above two way use following code to bind GridView.

//ASPX Page

protected void Page_Load(object sender, EventArgs e)
   {
       if (!Page.IsPostBack)
       {
           GridView1.DataSource = GetData();
           GridView1.DataBind();
       }
   }

Note: Implementation of custom LookupField is not complete. You may required to add or override few more function in order to work with diffrent mode of GridView Row. (Row Selection , Editing etc).

Please give me your comment.

Saturday, January 3, 2009

InternalsVisibleTo Attribute Usage

Before going into detail of InternalsVisibalTo attribute usage i would like to clear two access modifier in C#.

Internal : Access limited to current assembly.

Protected Internal : This means that protected or internal. So access limited to all class of current assembly or in other assembly class derive from this class.

In certain situation that is needed when you write your own set of classlibrary that you have to access internal of other assembly.In that case this attribute is usefull.

InternalsVisibalTo attribute applied at assembly level.

For example you have Two Assembly.

One in Library1 and Another one is Library2.

Library1 Contains Following Code.

public class Library1Class
    {
        protected internal void TestProctectedInternal()
        {
            Console.WriteLine("You are in protected internal method");
        }

        internal void TestInternal()
        {
            Console.WriteLine("You are in internal method");
        }    

         public void TestPublic()
        {
            Console.WriteLine("You are in public method");
        }

    }

Build Library1. That create library1.dll .

Now In Library2 you want to use Library1. So you add reference of Library1.

Library2 sample Code.

public class Library2Class
    {
        public void TestMethod()
        {
            Library1.Library1Class cls = new InterVisibalsToTest.Class1(); 

           cls.TestPublic(); // it’s ok

           cls.TestInternal(); // can’t access due to protection level.

           cls.TestProtectedInternal(); // can’t access due to protection level.                      
        }
    }

When you compile Library2 you can see two errors in build. (Mark as red in above code).

Now in order to avoid this error and give access to Library2 so it can access Internal and Protected Internal member, you have to use InternalsVisibleTo attribute in Library1 assemblyinfo.cs.

You have to add following line in assemlbyinfo.cs

[assembly: InternalsVisibleTo("Library2")]

After apply this attribute again build library1 and update reference in Library2. Now you have access of both method . TestInternal() and TestProtectedInternal();

Also possible to grant access to more than one assembly. For that you just have to add another line in assemlbyinfo.cs with diffrent assembly name.

For Example :

[assembly: InternalsVisibleTo("Library2")]                     [assembly: InternalsVisibleTo("Library3")].

Please give your comment on this.