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.

Tuesday, December 30, 2008

Windows Identity Impersonation

Sometime in window application it is required that it run in context of user account other than current login account.Few condition that required this is

1) Window Application that authenticate and authorize user by his/her user account.

2) SharePoint sometime required this to gain access of resource that is not granted for SharePoint users.

You can use following code to impersonate particular user.

[System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
String lpszUsername,
String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
        [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        static void Main(string[] args)
        {

            IntPtr usertoken = new IntPtr(0);
            bool b = LogonUser("test", "local", "123", 2, 0, ref usertoken);
            if (b == true)
            {
                System.Security.Principal.WindowsIdentity iden = new System.Security.Principal.WindowsIdentity(usertoken);
                System.Security.Principal.WindowsImpersonationContext con = iden.Impersonate();

// You Code that required impersonation

con.undo()

}

}

Note : Impersonation can be used in any type of application. (Window Application , Web Application , Class Library).

In Web Application web.config contains specific <identity> attribute for impersonation.

Linq to SharePoint List. (Where , Join )

This article give you information regarding how to use Liinq with SharePoint List to fetch data from SPList.

For Example there are three SharePoint List . Customers , Orders , OrderDetails. (Please See image below). In Orders list CustomerID is lookup field and in OrderDetails list OrderID is lookup field.

Customer

orders

Order Details

Now Get All Customer From Customer List using Linq.

SPSite site = new SPSite("http://localhost:45833"); 
SPWeb web = site.OpenWeb();
SPList lstCustomer = web.Lists["Customers"];

var customers = from SPListItem customer in lstCustomer.Items
                       select customer;

by use of SPListItem (As we use select customer in Linq query)
foreach (SPListItem item in customers)
{
Console.WriteLine(item.ID.ToString() + "-" +item["CustomerName"].ToString());
}

or by using ananymous type

var customers = from SPListItem customer in lstCustomer.Items
                       select new {ID = customer.ID.ToString(), Name= customer[“CustomerName”].ToString()};
foreach (var item in customers)
{
Console.WriteLine(item.ID + "-" + item.Name);
}

use of where clause with this

var customers = from SPListItem customer in lstCustomer.Items
                       where customer.ID == 1
                       select new { ID = customer.ID.ToString(), Name = customer["CustomerName"].ToString() };

Join Three List to get Related Data

SPList lstCustomer = web.Lists["Customers"];
SPList lstorders = web.Lists["Orders"];
SPList lstorderdetails = web.Lists["OrderDetails"];
var customerorders =

from SPListItem customer in lstCustomer.Items
join SPListItem order in lstorders.Items on customer.ID.ToString() equals order["CustomerID"].ToString().Split(new string[]{";#"},StringSplitOptions.None)[0]
join SPListItem orderdetail in lstorderdetails.Items on order.ID.ToString() equals orderdetail["OrderID"].ToString().Split(new string[] { ";#" }, StringSplitOptions.None)[0]                                
select new {Product = orderdetail["Product"].ToString() , Price = Convert.ToDouble(orderdetail["Price"].ToString()) , Qty = Convert.ToInt32(orderdetail["Qty"].ToString()) , OrderID = order.ID , OrderDate = order["OrderDate"].ToString() , CustomerID = customer.ID.ToString(), CustomerName = customer["CustomerName"].ToString() };


foreach (var item in customerorders)
               {
                   Console.WriteLine(item.Product + "  " + item.Price.ToString() + "," + item.Qty.ToString() + ","+ (item.Price * item.Qty).ToString() + ","+ item.OrderID.ToString() + "," + item.OrderDate + "," + item.CustomerName);
               }

                  Note :In above code, I used split operation on string in order to compare LookUp Field ID Value with ID of parent List. There is also posibility to join more than three tables.

For that you have to use nested this join inside other. Please give your comment or advice on this.

Wednesday, December 17, 2008

MCTS 70-528 Book update (MCTS Self-Paced Training Kit (Exam 70-528))

MCTS book update. If you have book called MCTS Self-Paced Training Kit (Exam 70-528): Microsoft .NET Framework 2.0 Web-Based Client Development, then you have to look at following correction.

 

http://support.microsoft.com/kb/930739