Saturday, September 19, 2009

Installing and Uninstalling Windows Service using C#

Install Windows Service:
public override void Install(System.Collections.IDictionary stateSaver)
        {
           
            base.Install(stateSaver);

            ConnectionOptions options = new ConnectionOptions();
            options.EnablePrivileges = true;
            options.Impersonation = ImpersonationLevel.Impersonate;

            ManagementScope scope = new ManagementScope(new ManagementPath(@"\ROOT\CIMV2"), options);
            scope.Connect();

            ManagementPath path = new ManagementPath("Win32_Service");

            ManagementClass mc = new ManagementClass(scope, path, new ObjectGetOptions());
            ManagementBaseObject inParams = mc.GetMethodParameters("create");

            inParams["Name"] = "GCSBLServices";
            inParams["DisplayName"] = "GCS BL Services";
            inParams["PathName"] = Context.Parameters["name"].ToString() + "BL.WndService.exe";
            inParams["StartName"] = @".\LocalSystem";
            inParams["StartPassword"] = "";

            ManagementBaseObject outParams = mc.InvokeMethod("create", inParams, null);

            ManagementPath path1 = new ManagementPath(string.Format("Win32_Service.Name='{0}'", "GCSBLServices"));

            using (ManagementObject service = new ManagementObject(scope, path1, new ObjectGetOptions()))
            {
               
                ManagementBaseObject outParams1 = service.InvokeMethod("StartService", null, null);
                   
            }
        }


Uninstall Windows Service:
public override void Uninstall(System.Collections.IDictionary savedState)
        {
            base.Uninstall(savedState);
            ConnectionOptions options = new ConnectionOptions();
            options.EnablePrivileges = true;
            options.Impersonation = ImpersonationLevel.Impersonate;

            ManagementScope scope = new ManagementScope(new ManagementPath(@"\ROOT\CIMV2"), options);
            scope.Connect();

            ManagementPath path = new ManagementPath(string.Format("Win32_Service.Name='{0}'", "GCSBLServices"));

            using (ManagementObject service = new ManagementObject(scope, path, new ObjectGetOptions()))
            {
               ManagementBaseObject outParams = service.InvokeMethod("StopService", null, null);
            }
           
            using (ManagementObject service = new ManagementObject(scope, path, new ObjectGetOptions()))
            {
                 ManagementBaseObject outParams = service.InvokeMethod("delete", null, null);   
            }
        }




Create Website under IIS using C#

The following code will help to create Website under IIS
 public static void createWebSite(string strSiteID, string strSiteName, string strWebAppPath)
        {
            CreateSite(strSiteID, strSiteName, strWebAppPath);
            SetSingleProperty(strMetaBasePath + "/" + strSiteID, "ServerBindings", ":8080:");
            CreateVDir(strMetaBasePath + "/1/Root", strSiteName, strWebAppPath);
        }
        static void CreateSite(string siteID, string siteName, string physicalPath)
        {
           try
            {
                DirectoryEntry service = new DirectoryEntry(strMetaBasePath);
                string className = service.SchemaClassName.ToString();
                if (className.EndsWith("Service"))
                {
                    DirectoryEntries sites = service.Children;
                    DirectoryEntry newSite = sites.Add(siteID, (className.Replace("Service", "Server")));
                    newSite.Properties["ServerComment"][0] = siteName;
                    newSite.CommitChanges();

                    DirectoryEntry newRoot;
                    newRoot = newSite.Children.Add("Root", "IIsWebVirtualDir");
                    newRoot.Properties["Path"][0] = physicalPath;
                    newRoot.Properties["AccessScript"][0] = true;
                    newRoot.CommitChanges();
                }
                else
                {

                }
            }
            catch (Exception ex)
            {
                
Debug.Writeline(ex.Message);
                throw ex;
            }
        }
        static void SetSingleProperty(string metabasePath, string propertyName, object newValue)
        {
           try
            {
                DirectoryEntry path = new DirectoryEntry(metabasePath);
                PropertyValueCollection propValues = path.Properties[propertyName];
                string oldType = propValues.Value.GetType().ToString();
                string newType = newValue.GetType().ToString();
                Console.WriteLine(" Old value of {0} is {1} ({2})", propertyName, propValues.Value, oldType);
                if (newType == oldType)
                {
                    path.Properties[propertyName][0] = newValue;
                    path.CommitChanges();
                }
                else
                {

                }
            }
            catch (Exception ex)
            {
                
Debug.Writeliner(ex.Message);
                throw ex;
            }
        }
        static void CreateVDir(string metabasePath, string vDirName, string physicalPath)
        {

           try
            {
                DirectoryEntry site = new DirectoryEntry(metabasePath);
                string className = site.SchemaClassName.ToString();
                if ((className.EndsWith("Server")) || (className.EndsWith("VirtualDir")))
                {
                    DirectoryEntries vdirs = site.Children;
                    DirectoryEntry newVDir = vdirs.Add(vDirName, (className.Replace("Service", "VirtualDir")));
                    newVDir.Properties["Path"][0] = physicalPath;
                    newVDir.Properties["AccessScript"][0] = true;
                    // These properties are necessary for an application to be created.
                    newVDir.Properties["AppFriendlyName"][0] = vDirName;
                    newVDir.Properties["AppIsolated"][0] = "1";
                    newVDir.Properties["AppRoot"][0] = "/LM" + metabasePath.Substring(metabasePath.IndexOf("/", ("IIS://".Length)));

                    newVDir.CommitChanges();
                    Object nativeObject = newVDir.NativeObject;
                    nativeObject.GetType().InvokeMember("AppCreate3", BindingFlags.InvokeMethod, null, nativeObject, new object[] { 2, "DefaultAppPool", false }); // 2 means to use an Application Pool.
                                      
                }
                else
                {

                }
            }
            catch (Exception ex)
            {
               Debug.Writeline(ex.Message);
                throw ex;
            }
        }

Import TFS Workitems through C# code

This is how you can import the TFS workitems through C# code
            NetworkCredential objCre = new NetworkCredential(txtUserName.Text, txtPassword.Text, "TFS");
            WebProxy objProxy = new WebProxy();
            objProxy.Credentials = CredentialCache.DefaultCredentials;
            TeamFoundationServer tfs1 = new TeamFoundationServer(txtTFSServer.Text, objCre);
            tfs1.EnsureAuthenticated();

            WorkItemStore store = (WorkItemStore)tfs1.GetService(typeof(WorkItemStore));
          
            WorkItemCollection objColl = store.Query("SELECT   [System.Id], [System.WorkItemType], [Microsoft.VSTS.Common.Rank], [System.State], [System.AssignedTo], [System.Title]  FROM     WorkItems  WHERE    [System.TeamProject] = 'Sample'   AND      [System.WorkItemType] ='Bug' AND [System.Title] CONTAINS '-ST-' ");



Before running this code ensure that you download and install the TFS SDK from microsoft site.
The following are the references you will have to add to the project
Microsoft.TeamFoundation.Client
Microsoft.TeamFoundation.WorkItemTracking.Client

Accessing Active Directory information from Sharepoint

To access the information in AD like username, first name, last name, given name, CN, Role etc... from sharepoint; the following are some of the options

  • Access the Active Directory directly from the Portal
  • Create a WCF Service running under privileged user which will access the Active Directory and return the required information
  • Create Shared Service provider and use “Profile Import” technique in the sharepoint
Option 1:
This option may not be the good one since every user to the sharepoint need to have access to the corresponding Active Directory. This might not work out in case of using Windows Authentication in the sharepoint.


Option 2: (Using WCF Service)

A WCF Service can be created and make it to run under the highly privileged user who have access to Active Directory. From Portal we can make a WCF call to get the Active Directory information. The service will pull the user information from Active Directory and return back to the portal.
Pros
  •  Unlike profile import approach, the information about the user is always up-to-date since we are directly fetching the information from Active Directory.
Cons 
  • One WCF Service has to be setup to access Active Directory. Involves a little bit effort to create & deploy the WCF Service.
  •  Whenever a user logs-in a web service call has to be made to fetch the Active Directory information. This might affect the performance of the portal a little
Option 3:(Profile Import)

MOSS has the built-in technology for access the Active Directory called “Profile Import shared service”.
To use this,

  • Shared Services has to be created
  • Under “User Profiles and Properties”, “Import Connection” has to configured to the Active Directory
  • Using “Configure Profile Import” either incremental or full import has to be configured using the privileged user id and password
  • Property mappings have to be created for the information required from Active Directory
  • Then sharepoint will import all the profiles from Active Directory and store them in its SQL configuration database
  • From Portal using Elevated Privilege we will have to use “UserProfileManager” and access the user profiles.
Pros

  • The Active Directory information will be imported and stored in the configuration database of the sharepoint portal. Also, the profile information will be set in the User Context info of the logged-in user. Hence, accessing the Profile Information will have better performance than accessing the WCF Service.
  • “Profile Import” technique is in-built in sharepoint and does not involve any coding. Simple configuration settings in the “Sharepoint Central Administration” will suffice
Cons
  • The Profile Import from Active Directory will happen through schedule jobs. Hence there is a chance that the latest updated information of the user in Active Directory might not reflect immediately in the User Profile

Product Metrics - Cyclomatic Complexity

Developed by Thomas J. McCabe Sr. in 1976. It is used to measure the complexity of a program. It directly measures the number of linearly independent paths through a program's source code. It is computed using the control flow graph of the program.

The simplest formula for calculating the Cyclomatic  Complexity is as follows

M = E – N + 2

 M = Cyclomatic Complexity
E = Number of edges in the control graph
N = Number of nodes in the control graph


 

Sample 1:
Simple If statement, the CC will be
M = 3 - 3 + 2 ==> 2 

Sample 2:
If-else statement, the CC will be
M = 4 - 4 +2 ==> 2

Sample 3:
Switch block, the CC will be
M = 6 - 5 + 2 ==> 3

VSTS 2008 has inbuilt product metrics measurement option for LOC, CC, coupling and maintainability index. SourceMonitor is another open source tool which helps to measure some of the the product metrics including CC.

Complexity definition:

Cyclomatic Complexity
Risk Evaluation
1 to 10
a simple program, without very much risk
11 to 20
a more complex program, moderate risk
21 to 50
a complex, high risk program
> 50
an un-testable program (very high risk)

Friday, September 18, 2009

Issue with "$(document).ready(function() {...}" in JQuery

Today one of my friend faced a peculiar issue with JQuery. He told me, JQuery is working fine for ASP.NET controls if he add the JQuery code inline. But it is not working, if he move the code to an .js file and use it in the page.
Then we thought something wrong with the intelligent selector in JQuery. But the syntax of the intelligent looked perfect and no issues were there.
$("input[id$='txtName']").val("Text Added using jQuery");

Then I asked him, are you sure you have only one "$(document).ready(function() {...}" in the ASP.NET page. That ring a bell and when he checked, it was present in ASP.NET page and in .js file. Once he remvoed the "$(document).ready(function() {...}" from one place, Bingo!!! it started working.

Hence, an ASP.NET page can contain only one "$(document).ready(function() {...}". We need to be sure that, in the referenced .js files and in the inline javascript code it should not be present more than once.

Export ASP.NET Grid to Excel

Below is the code for exporting the ASP.NET grid into Excel document


            HtmlForm form = new HtmlForm();
            string attachment = "attachment; filename=Employee.xls";
            Response.ClearContent();
            Response.AddHeader("content-disposition", attachment);
            Response.ContentType = "application/ms-excel";
            StringWriter stw = new StringWriter();
            HtmlTextWriter htextw = new HtmlTextWriter(stw);
            form.Controls.Add(GridView1);
            this.Controls.Add(form);
            form.RenderControl(htextw);
            Response.Write(stw.ToString());
            Response.End();

SQLDepedency Caching in ASP.NET

The following code allows you to use the SQL Dependency caching ASP.NET.
To be able to use SQL Dependency caching, the following queries must be executed in the SQL Server (2005 and above)
ALTER DATABASE SET ENABLE_BROKER
GO
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO
GO
The above steps enable broker in the SQL Sever and subscribe the AppPool account for query notifications (new concept from SQL Server 2005 and above)

Now its time for coding to achieve the SQL Dependency Caching.

            connString = ConfigurationManager.ConnectionStrings["AppConnectionString1"].ConnectionString;
            SqlConnection conn = new SqlConnection(connString);
            conn.Open();
            SqlCommand command = new SqlCommand("select dbo.Test.ColA,dbo.Test.ColB from dbo.Test", conn);
            SqlCacheDependency cacheDependency = new SqlCacheDependency(command);
            SqlDependency.Start(connString);
            if (Cache["Test"] == null)
            {
                Cache.Add("Test", Common.ConvertReaderToTest(command.ExecuteReader()), cacheDependency, Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration, CacheItemPriority.Normal, new CacheItemRemovedCallback(this.RemovedCallback));
            }

public void RemovedCallback(string k, object v, CacheItemRemovedReason r)
        {
            if (r == CacheItemRemovedReason.DependencyChanged)
            {
                SqlConnection conn = new SqlConnection(connString);
                conn.Open();
                SqlCommand command = new SqlCommand("select dbo.Test.ColA,dbo.Test.ColB from dbo.Test", conn);
                SqlCacheDependency cacheDependency = new SqlCacheDependency(command);
                Cache.Add("Test", Common.ConvertReaderToTest(command.ExecuteReader()), cacheDependency, Cache.NoAbsoluteExpiration,
            Cache.NoSlidingExpiration, CacheItemPriority.Normal, new CacheItemRemovedCallback(this.RemovedCallback));
                conn.Close();
            }

        }

Please note that, for SQL Cache dependency to work; one has to use fully qualified name for column names and table names.
select dbo.Test.ColA,dbo.Test.ColB from dbo.Test 
 
 

Show/Hide Datagrid columns using JQuery


Recently one of our customer came with a special requirement of letting the users to show/hide the columns in a grid as he wish. The customer was little hesitant to ask for this requirement. (he was thinking, it will be difficult to achieve). But we gave him confidence by achieving this by using JQuery. This is how we achieved this functionality


Grid code:

<asp:GridView ID="grdView" runat="server" AutoGenerateColumns="false" OnRowDeleting="grdView_RowDeleting"
    EnableViewState="true">
    <Columns>
        <asp:TemplateField>
            <HeaderTemplate>
                <div id="ColAH" >
                    <asp:ImageButton ID="ImageButtonDelete2" runat="server" ImageUrl="~/_assets/img/delete.png"
                        CssClass="deleteButton" />
                </div>
            </HeaderTemplate>
            <ItemTemplate>
                <div id="ColA" class="columnA">
                    <asp:Label ID="l1" runat="server" Text='<%# Eval("ColA") %>'></asp:Label>
                </div>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <HeaderTemplate>
                <div id="ColBH" >
                    <asp:ImageButton ID="ImageButtonDelete1" runat="server" ImageUrl="~/_assets/img/delete.png"
                        CssClass="deleteButton" />
                </div>
            </HeaderTemplate>
            <ItemTemplate>
                <div id="ColB" class="columnB">
                    <asp:Label ID="l2" runat="server" Text='<%# Eval("ColB") %>'></asp:Label>
                </div>
            </ItemTemplate>
        </asp:TemplateField>
       
    </Columns>
</asp:GridView>


Javascript code:

    $(document).ready(function() {
       
        
        $('#ColAH').each(
            function(e)
            {
            $(this).find(".deleteButton").click(
                function (e)
                {
                e.preventDefault();
                var res = getDivs('columnA');
                    for(var i=0; i
                    {
                        var state = res[i].style.display;
                        if (state == 'block' || state == '')
                        {
                            res[i].style.display = 'none';
                        }
                        else
                        {
                            res[i].style.display = 'block';
                        }
                        alert(res[i].style.display);
                    }
                }
               
            );
            }
        );
       
         $('#ColBH').each(
            function(e)
            {
            $(this).find(".deleteButton").click(
                function (e)
                {
                e.preventDefault();
                var res = getDivs('columnB');
                    for(var i=0; i
                    {
                        var state = res[i].style.display;
                        if (state == 'block' || state == '')
                        {
                            res[i].style.display = 'none';
                        }
                        else
                        {
                            res[i].style.display = 'block';
                        }
                        alert(res[i].style.display);
                    }
                }
               
            );
            }
        );
       
    });

    function deleteRow(args) {
        $(args).click();
        return false;
    }
   
    function getDivs(cName)
    {
    var ar = document.getElementsByTagName("div");
    var divArray = new Array();
   for(var i=0; i
     if(ar[i].className == cName ){
        divArray.length++;
        divArray[divArray.length -1] = ar[i];
     }
  }
  return divArray;
}
  
function hideColumn(id)
{
var state = document.getElementById(id).style.display;
if (state == 'block' || state == '') {
     document.getElementById(id).style.display = 'none';
} else {
       document.getElementById(id).style.display = 'block';
   }
}
    function confirm(message, callback) {
        $('#confirm').modal({
            close:false,
            overlayId:'confirmModalOverlay',
            containerId:'confirmModalContainer',
            onShow: function (dialog) {
                dialog.data.find('.message').append(message);

                // if the user clicks "yes"
                dialog.data.find('.yes').click(function () {
                    // call the callback
                    if ($.isFunction(callback)) {
                        callback.apply();
                    }
                    // close the dialog
                    $.modal.close();
                });
            }
        });
     }
                           
 And don't forget to include the Jquery.


Kudo to JQuery!!!!! JQuery is a proof for "Impossible is Nothing"!!!!



Thursday, September 17, 2009

Uploading an XML to SQL Table


Here is how u can upload an XML directly to SQL Table


DECLARE @INTPOINTER AS INT
DECLARE @XML AS XML
SET @XML = '<UpdateRentalData>
  <verhuurderField>
    <fiscaalNumberField>100000009</fiscaalNumberField>
    <huurobjectField>
      <kalehuurField>444444</kalehuurField>
      <postcodeField>2342ff</postcodeField>
      <recordCodeField>105</recordCodeField>
    </huurobjectField>
    <recordCodeField>002</recordCodeField>
  </verhuurderField>
</UpdateRentalData>'
DECLARE @TEMP_TABLE TABLE (
                                    fiscaalNumberField NVARCHAR(50),
                                    kalehuurField NVARCHAR(50),
                                    postcodeField NVARCHAR(50),
                                    recordCodeField NVARCHAR(50)
                                   
                                  )
        EXEC sp_xml_preparedocument @INTPOINTER OUTPUT, @XML
        Insert into @TEMP_TABLE
                            Select * from OpenXml(@INTPOINTER,'/UpdateRentalData/verhuurderField/huurobjectField',2)
                            With (
                                    fiscaalNumberField NVARCHAR(50) '../fiscaalNumberField',
                                    kalehuurField NVARCHAR(50) ,
                                    postcodeField NVARCHAR(50),
                                    recordCodeField NVARCHAR(50) '../recordCodeField'
                                )
        exec sp_xml_removedocument @INTPOINTER

SELECT * FROM @TEMP_TABLE

Refresh Parent page while closing the modal popup in sharepoint

In sharepoint, to refresh the parent page on closing the popup just add this piece of code after calling the window.showModalDialog "window.location.href=window.location.href"


WatiN and LINQ

Web Application Automation in .NET (WatiN) leverages the LINQ functionality which helps the developers to easily create Unit Testcases for automating the Unit Testing Web Application. Sample below will give you an idea of how you can use LINQ features along with WatiN for web test automation.

Policy Injection and Unity Application block

This sample will help you understand how policy injection and Unity Application blocks can be used together to achieve Auditing.
One can leverage the matching rules shipped with Policy Injection block along with the custom Handlers option in Unity Application Block.

To be able to create Custom Handlers, one has to Implement the ICallHandler interface available in "Microsoft.Practices.Unity.InterceptionExtension"


Example:

















The ICallHandler interface has an method "Invoke" which needs to be overriden. In that method, we can write code before executing an particular method and after also.

IMethodReturn result = getNext()(input, getNext); indicates the actual execution of method. Whatever code written before this statement will be executed before the actual method call. And whatever code written after this statement will be executed after the actual method call.

And the application configuration file has to be updated with something like this;