Hil's .NET development

Good practices in the life of software development

  • Load Code Coverage Data to SQL database

    Load Code Coverage Data to SQL database

    Use Visual Studio’s code coverage tools to obtain the .coverage file

    Visual Studio has a set of tools that can collect your code coverage data. The data structure of the collected code coverage data is in a table format. As you can see from the link, it shows how to obtain code coverage data, which is not what I am covering here. This article is talking about how to load the .coverage file into a SQL server database. You can refer to my previous blog about how to obtain x64 code coverage data. The result of the code coverage data is a .coverage file. Open it in Visual Studio 2008 Code Coverage Results panel (see attachments). When you expand the first + sign, Visual Studio reads the .pdb and binary files from where you originally executed the code coverage profiler. For example, suppose you collected code coverage data on a remote server and copied the .coverage file to your local machine. When you click on the + sign of the .coverage file, you will get “Code Coverage Analysis engine threw exception(s): Error when creating coverage info: Error loading symbol file. Symbol and binary files should be in the same folder as the coverage file or on the symbol path”. The solution is copy the symbol (.pdb) files and the binary from the remote server to your local machine at the same path. Click on Export Results button in the panel to save to a .xml file. We will cover how to use the xml file in the later section.

    Use code coverage API to retrieve code coverage data

    The code coverage API is not documented. The closest thing you can get is joc's bLog. You could find the code coverage assembly at \Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Coverage.Analysis.dll. If you run in x64 Windows, make sure you configure your project properties to Platform Target: x86. Otherwise, you will get {"Could not load file or assembly 'Microsoft.VisualStudio.Coverage.Analysis, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. An attempt was made to load a program with an incorrect format."} exception. Microsoft.VisualStudio.Coverage.Analysis.dll is a 32 bit dll. joc's bLog shows how to use a query to filter what methods you want for method code coverage data:
    using Microsoft.VisualStudio.CodeCoverage;
    CoverageDSPriv
    .MethodDataTable methodDT = myCovDS.Method;
    DataRow[] methodDR = methodDT.Select("MethodName IN " + searchmethods);
    Above is the code breakdown. You can use “SqlBulkCopy” class to load “methodDT” to a SQL server table. You need to have the same column name in the table on the SQL server as those in “methodDT”. Below is the code that uses “SqlBulkCopy” class to import the code coverage data:
    using (SqlBulkCopy SqlBCP = new SqlBulkCopy(connString))

    {

        SqlBCP.DestinationTableName = "Method";

        SqlBCP.WriteToServer(methodDT);

    }

    Use SQL Server Integration Service project to create code coverage data tables

    SqlBulkCopy” class does not create the table structure for you. You need to create it manually. Although it’s only 8-9 columns depending on the CoverageDSPriv’s DataTable structure, there is actually a smarter way to create the table by using a SSIS (SQL server integration service) project through SQL Server Business Intelligence Development Studio. Make sure you have the following features installed in your SQL Server 2008: Business Intelligence Development Studio and Integration Services. Integration Services can run under Network Service account. Open Visual Studio 2008. Click on File > New > Project… Find Project types Business Intelligence Projects > Integration Services Project. Open the SSIS Packages > Package.dtsx, go to the Data Flow tab. Click to add a data flow task. Open Toolbox. Drop and drop XML Source into the designer surface. Double click on the XML source. Locate the XML file generated from the Code Coverage Results panel’s export results. Check “Use inline schema” and hit OK. Choose OK to accept the warnings. Drag and drop an OLE DB Destination to the designer surface. Highlight the XML source and point the green arrow to the OLE DB Destination. Select Output as what kind of CoverageDSPriv’s DataTable you want. For example, you can choose Class and hit OK. Double click on the OLE DB Destination. Click on New… at “OLE DB connection manager” to create a new connection to the database you want to load code coverage data to. Click on New at “Name of the table or the view” to see the SQL query that will create the table. Change the table name and hit OK. The table is now created. The OK button in the editor is disabled. Click on Mappings on the left pane and make sure the Input columns in CoverageDSPriv’s DataTable correctly map to the destination columns. Now, you can hit OK in the editor. Add more OLE DB Destination to the designer surface and link the XML source to it with different Output. If you see any error in the Error List, try to resolve them by double clicking on them to analyze. Removing incorrectly mapped references might help. When you see no errors, save the .dtsx file and open it in Execute Package Utility by double clicking on it. This should guide you through loading data to the SQL server. At this point, I always get errors when loading method coverage data to the database. There seems to be a truncation error. You might have to load it row by row in ADO.NET or LINQ by following the code sample in the previous section.

  • Test .NET library using PowerShell and Visual Studio Debugger

    Often times, when a developer builds a C# library, there is always a need for unit testing it. If your company already has strictly guidelines on how to enforce unit testing before any code is checked in, you might want to read the policy procedure about how to do it. Visual Studio Team System 2008 can be configured to enforce such policy that if any unit tests fail, the check in is rejected. You can right click on the solution->New->Add project->Test->Test project to create unit tests. Every time, you change the data in your test, you need to re-compile the test dll and run the test. Don’t you think that’s an overhead for changing calls from ”client.CreateEmail("XBOX", "hil1@msn.com");” to “client.CreateEmail("Live", "hil1@msn.com");”? PowerShell comes handy to solve this problem. You can easily code unit tests for your methods and change them without re-compiling. Here is how:

    1.       Install Windows PoweShell

    2.       Open a PowerShell window, type powershell and hit enter. Notice there are 2 powershell.exe processes running. One is the parent and the other is the child. You are in the child process. Use process explorer to observe the 2 processes and write down the child process ID.

    3.       Build the .NET library solution. The .dll should reside in bin\Debug folder.

    4.       At powershell prompt, run PS > $loadResult = [Reflection.Assembly]::LoadFrom("D:\product\src\test\DataAccess\bin\Debug\Microsoft.IT.Product.Library.dll"). All the dll files referenced by Microsoft.IT.Product.Library.dll will also be loaded. Be aware that if you use [Reflection.Assembly]::LoadFile, the referenced dll files will NOT be loaded.

    5.       If you see no errors and $loadResult shows no errors, you are probably fine.

    6.       Command to instantiate your class: PS > $verify = New-Object Microsoft.IT.Product.Library.VerifyData("Data Source=.;Initial Catalog=EmailStore;Integrated Security=True"). Notice that VerifyData is the class name which takes a constructor of 1 string argument.

    7.       Run a unit test on a method: PS > $verify.EmailExists("testuser@msn.com"). If the constructor throws an exception, you will see the following:
    New-Object : Exception calling ".ctor" with "1" argument(s): "Database EmailStore does not exist"

    At line:1 char:21

    + $verify = New-Object  <<<< Microsoft.IT.Product.Library.VerifyData("Data Source=.;Initial Catalog=EmailStore;Integrated Security=True")

    8.       In Visual Studio 2008, click on Debug->Attach to Process… You should be able to see 2 PowerShell processes. Choose the child process. Remember you call [Reflection.Assembly]::LoadFrom in the child powershell process.

    9.       After successfully attached to the correct process, you should be able to set break points at anywhere within your library. If the break point says “No symbols have been loaded for this document”, you probably have attached to the wrong powershell process.

    10.   You can use PowerShell to run all the methods in your library to unit test them in Visual Studio. When you are done testing, unfortunately, you can’t unload the assembly. You need to exit the Child PowerShell to unload the assembly. Otherwise, you will get error when building the solution: Unable to delete file. That is because the child PowerShell process is still holding the loaded assembly. Simply type exit at the child PowerShell prompt to unload it.

    11.   To test static method in the library, use [Microsoft.IT.Product.Library.VerifyData]::RandomString(4). RandomString is a static method that takes 1 int argument.

  • ASP.NET AJAX Control Toolkit example

    There are situations where you don’t want user to click on a button twice too fast or on a checkbox when the server is still processing. One quick trick is to use “this.Button1.Attributes.Add("onclick", "this.disabled=true;");” to disable the button right after user clicks on it. ASP.NET AJAX Control Toolkit has a rich set of controls that allow you to show fancy effects using AJAX. Among which, UpdatePanelAnimation can have the same effect as disabling the button after user’s click. If you set the fade out on updating and fade in on updated, your page can disable the whole panel which might contain buttons or checkboxes after user’s click:

    <%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc1" %>

    ...

    <cc1:UpdatePanelAnimationExtender ID="EndpointUpdatePanel_UpdatePanelAnimationExtender"

            runat="server" TargetControlID="EndpointUpdatePanel">

                <Animations>

                    <OnUpdating>

                        <FadeOut Duration="0.5" Fps="20" />

                    </OnUpdating>

                    <OnUpdated>

                        <FadeIn Duration="0.5" Fps="20" />

                    </OnUpdated>

                </Animations>
    </
    cc1:UpdatePanelAnimationExtender>

    The only drawback is that the target control must be an UpdatePanel. When the user clicks on anything that causes an postback in the UpdatePanel such as a checkbox or a button, the panel fades out and user can’t click on anything in the panel. When the server finishes processing the postback (for example, querying data in the SQL server backend), the panel fades in with information back. You need to install the toolkit before you can add the “AjaxControlToolkit” tags to your aspx page source. Be aware that if you add the Toolkit to the Toolbox, you need to close the Visual Studio 2008 instance (suppose this is the last devenv.exe instance in the process list) and start new instances to have the AJAX Control Toolkit in Toolbox.

  • Common Tasks in Developing ASP.NET Application

    I mentioned developing an ASP.NET website in the first blog. ASP.NET is a sophisticated architecture that often confuses developers, especially which event fires first could be difficult to expect. You should understand ASP.NET Page Life Cycle before you start dragging WebControl to the page.

    Task 1: Impersonation

    Often times, you need to impersonate as a specific active directory user to connect to a server, check service status, or access MSMQ. Microsoft Support has a very good example page about how to impersonate as a specific user. You can change the impersonate method and undo impersonation method to be public static to allow all other methods in your application to use them. Below is the code showing how to consume the impersonation methods:

    ServiceStatus.impersonated = ServiceStatus.impersonateValidUser("ServiceAccountUser","Domain","Don’tTell");

    if (!ServiceStatus.impersonated)

    {

        // impersonation failed. Do not continue to call Administration web service

    string message = DateTime.Now + " - Impersonaion failed.”

    Trace.WriteLineIf(ServiceStatus.debugSwitch.TraceError, message);

        throw new Exception(message);

    }

    Task 2: Start application thread

    The static constructor is the best place you can start and manage a thread. The thread will exist in the scale of the application regardless of how many page instances there are at any moment. It is a useful practice if you need to run long haul SQL queries or you need to check Windows Service status every 10 minutes alongside your ASP.NET application.
    // There should always be 1 static instance of ServiceStatus executing

    // method ServiceStatus.StartChecking in the application pool

    static _Default()

    {

        if (_Default.logEnvStatus == null || !_Default.logEnvStatus.IsAlive)

        {

            _Default.logEnvStatus = new Thread(new ThreadStart(ServiceStatus.StartChecking));

            _Default.logEnvStatus.Start();

        }

        _Default.refreshTime = ServiceStatus.appSettings["RefreshTime"];

        _Default.MaxLatencyAllowed = int.Parse(ServiceStatus.appSettings["MaxLatencyAllowed"]);

    }

    Task 3: Access DetailsView or GridView Rows

    The DetailsView class bound to a data source is convenient to display data from a SQL database table. However, we don’t have much control over the data on the rows at runtime. In the DataBound event of DetailsView class, you can use the following code to access text on each row and modify the row’s color:

    System.Data.DataRowView rowView = (System.Data.DataRowView)this.EndpointDetailsView.DataItem;
    if (rowView != null)

    {
        for (int i = 0; i < rowView.Row.ItemArray.Length; ++i)
        {
            string endpoint = rowView.Row[i].ToString();
            if (endpoint.IndexOf("http") == 0)
            {
                // text in the row’s cell has string http
                ControlCollection c = this.EndpointDetailsView.Controls;
                DetailsViewRow row = this.EndpointDetailsView.Rows[i];
                // change the row color
                row.BackColor = System.Drawing.Color.LightGreen;

    The same technique on GridView’s RowDataBound event:

    const int latencyIndex = 5;

    const int EnvIDIndex = 1;

    if (e.Row.RowType == DataControlRowType.DataRow)

    {

        int latency = int.Parse(e.Row.Cells[latencyIndex].Text);

        if (latency > _Default.MaxLatencyAllowed)

        {

            e.Row.Cells[latencyIndex].ForeColor = System.Drawing.Color.Red;

            e.Row.ToolTip = _Default.LatencyHighMessage;

        }

    The only drawback is you need to know the index of the cell data to manipulate it. In the example code above, latencyIndex is a number. If you miscalculated the index and the string is not a number, int.Parse will throw a format exception.

  • System.Windows.Automation

    It has always been difficult to solve UI automation problems. There are many UI automation frameworks not only on the Internet but also internal at Microsoft. Choosing the right one that best fits your need could be difficult. Finally, there is an ultimate solution that’s shipped with .NET 3.0 or later: System.Windows.Automation. It supports automating WPF (Windows Presentation Foundation) applications and will probably support SilverLight applications in the future. Dr. James McCaffrey talked about how to use it at http://msdn.microsoft.com/en-us/magazine/cc163288.aspx. I took his approach and built an automation project. The difference is that I know all the values in the Windows Form Control Name property which identify the objects in the Windows Form application I want to automate. In the code, you will see new PropertyCondition(AutomationElement.AutomationIdProperty, "EndpointTextBox") versus using AutomationElement.NameProperty. EndpointTextBox is the Control Name property in the Windows Form project I want to automate. 2 references are required to use the automation library: UIAutomationClient, UIAutomationTypes.

    using System;

    using System.Text;

    using System.Windows.Automation;

    using System.Diagnostics;

    using System.Threading;

    using System.Text.RegularExpressions;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    // Get the main form element from the desktop

    Process ProductServiceCheckProc = Process.Start(FormUIAuto.ProductServiceCheckExePath);

    AutomationElement desktop = AutomationElement.RootElement;

    AutomationElement mainForm = null;

    do

    {

        mainForm = desktop.FindFirst(TreeScope.Children,

            new PropertyCondition(AutomationElement.NameProperty, "MDSClientForm"));

        Thread.Sleep(TimeSpan.FromSeconds(this.waitSecond));

    }

    while (mainForm == null);
    // In the Windows Form project being automated, the TextBox.Name property is set to InputFileTextBox
    AutomationElement inputFileTextBox = mainForm.FindFirst(TreeScope.Children,

    new PropertyCondition(AutomationElement.AutomationIdProperty, "InputFileTextBox"));

    Dr. James McCaffrey did not write about how to select a single item from a dropdown list Control. I thought the library would have this format: DropDownList.Select(desiredItem) but it turned out to be desiredItem.Select():

    // Find the dropdown list of Name property createService
    AutomationElement
    endpointComboBox = mainForm.FindFirst(TreeScope.Descendants,

        new PropertyCondition(AutomationElement.AutomationIdProperty, "createService"));

    SelectionPattern selectEndpointComboBox = (SelectionPattern)endpointComboBox.GetCurrentPattern(SelectionPattern.Pattern);
    // The dropdown list can only select one item

    Assert.IsFalse(selectEndpointComboBox.Current.CanSelectMultiple, "ComboBox can select multiple endpoints");
    // Find the item to select in the dropdown list
    AutomationElement ItemInDropdown = endpointComboBox.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "desiredItem"));
    // returns null if the item is not found

    Assert.IsNotNull(ItemInDropdown, "Can't find list item {0} in createService ComboBox", EndpointName);

    SelectionItemPattern ItemInDropdownSelectItem = (SelectionItemPattern) ItemInDropdown.GetCurrentPattern(SelectionItemPattern.Pattern);
    // Simulate choosing the item in the dropdown list

    ItemInDropdownSelectItem.Select();

    It could be difficult to figure out how to automate some controls such as ErrorProvider Class, OpenFileDialog Class, and ToolTip Class. They might have something to do with writing a provider for those controls. If you know how to automate them, please leave a comment with the link to the article.

  • Code Coverage using Visual Studio 2008’s Code Coverage tools

    The code coverage tools in Visual Studio have existed since 2005 in the Team Developer and Tester Tools -> Code Analysis Tools in Visual Studio Team System 2008 installation. However, there have not been enough articles about how to use them on Windows Service and WCF (Windows Communication Foundation) applications. The steps are not as easy as using the Test Run Configuration’s Code Coverage at http://msdn.microsoft.com/en-us/library/ms182496.aspx. You actually need to run the tools at command line to start and stop the code coverage monitor. I talked to the engineers in the Visual Studio team and compiled the official steps for doing code coverage on Windows Service and WCF applications. The biggest problem of the code coverage tools is that it does not support 64-bit code coverage collection. The reason is that there is no integrated solution for 64-bit code coverage collection in Test Run Configuration’s Code Coverage.  Visual Studio team decided to proactively deny instrumenting 64-bit assemblies for code coverage in Visual Studio 2008. The tool executables can be found at \Program Files (x86)\Microsoft Visual Studio 9.0\Team Tools\Performance Tools.

    WCF application code coverage:

    1.       Instrument the web service binary that you want coverage on: VsInstr.exe /coverage myWebService.dll. Deploy the dll to IIS 6 or 7.

    2.       Start the monitor for collecting coverage data: VSPerfCmd.exe /start:coverage /output:”C:\CoverageData.coverage” /cs /user:”NT AUTHORITY\Network Service” /user should be whatever identity IIS is running under. /cs means cross session which allows the code coverage collection to be run from other sessions such as making a WCF call from a remote machine.

    3.       Run the scenario or test cases that will exercise the WCF service.

    4.       Verify the monitor has started: VSPerfCmd.exe /status:
    PS D:\Users\hiliao> & 'D:\Program Files\VSCC\VSPerfCmd.exe' /status

    Microsoft (R) VSPerf Command Version 9.0.30305 x64

    Copyright (C) Microsoft Corp. All rights reserved.

     

     

    Process and Thread Status

    ============================================================

    Output File Name            : D:\tmp\CoverageData.coverage

    Collection mode             : COVERAGE

    Maximum Processes           : 64

    Maximum Threads             : 256

    Number of Buffers           : 258

    Size of Buffers             : 65536

    ============================================================

    Maximum Number of Processes : 64

    Number of Active Processes  : 1

    Global Start/Stop Count     : 1

    Global Suspend/Resume Count : 0

    ------------------------------------------------------------

     Process                    :  d:\windows\system32\inetsrv\w3wp.exe

     Process ID                 : 6604

     Num Threads                : 0

     Start/Stop Count           : 1

     Suspend/Resume Count       : 0

    ============================================================

    Users with access rights to monitor:

    UserName (SID)

    NT AUTHORITY\NETWORK SERVICE (S-1-5-20)

    BUILTIN\Administrators (S-1-5-32-544)

    NT AUTHORITY\SYSTEM (S-1-5-18)

    PS D:\Users\hiliao>

    5.       Shutdown the monitor when your scenario is done: VSPerfCmd.exe /shutdown
    Waiting for process 6604 ( d:\windows\system32\inetsrv\w3wp.exe) to shutdown...

    6.       The command does not return until you totally stop IIS for process w3wp.exe to exit. When the command returns. The code coverage data should be saved at C:\CoverageData.Coverage. Do not move the .pdb files of the instrumented EXE or DLL. Otherwise, C:\CoverageData.Coverage will fail to load.

    Windows Service code coverage:

    1.       Instrument the Windows Service executable that you want coverage on: VsInstr.exe /coverage WinSvc.exe. Deploy the exe to the Windows Service folder.

    2.       Start the monitor for collecting coverage data: VSPerfCmd.exe /start:coverage /output:”C:\CoverageData.coverage” /cs /user:”Everyone”

    3.       Start the Windows Service.

    4.       Verify the monitor has started: VSPerfCmd.exe /status:
    PS D:\Users\hiliao> & 'D:\Program Files\VSCC\VSPerfCmd.exe' /status


    Microsoft (R) VSPerf Command Version 9.0.30305 x64

    Copyright (C) Microsoft Corp. All rights reserved.

     

     

    Process and Thread Status

    ============================================================

    Output File Name            : E:\build73FST2.coverage

    Collection mode             : COVERAGE

    Maximum Processes           : 64

    Maximum Threads             : 256

    Number of Buffers           : 258

    Size of Buffers             : 65536

    ============================================================

    Maximum Number of Processes : 64

    Number of Active Processes  : 1

    Global Start/Stop Count     : 1

    Global Suspend/Resume Count : 0

    ------------------------------------------------------------

     Process                    :  D:\Program Files\Product\PRODUCT Bulk Service\ProductBulkService.exe

     Process ID                 : 6768

     Num Threads                : 0

     Start/Stop Count           : 1

     Suspend/Resume Count       : 0

    ============================================================

    Users with access rights to monitor:

    UserName (SID)

    \Everyone (S-1-1-0)

    BUILTIN\Administrators (S-1-5-32-544)

    NT AUTHORITY\SYSTEM (S-1-5-18)

    5.       Run the scenario or test cases that will exercise the Windows Service

    6.      Stop the Windows Service and Shutdown the monitor: VSPerfCmd.exe /shutdown. The code coverage data should be saved at C:\CoverageData.Coverage. Do not move the .pdb files of the instrumented EXE or DLL. Otherwise, C:\CoverageData.Coverage will fail to load.

    If you can’t get any code coverage results, look at application event log (eventvwr.exe) with Source == VSPERF. There might be useful information about why the monitor is not running.

    You can probably find x64 folder in \Program Files (x86)\Microsoft Visual Studio 9.0\Team Tools\Performance Tools. However, a necessary component VSCover90i.dll on 64 bit Windows is missing which causes collecting 64 bit code coverage to fail. The output message is from running the internal code coverage tools build at Microsoft. I am hoping the next release of Visual Studio will have the necessary DLL to run 64 bit code coverage.

  • PowerShell for system administration work

    Since Windows Server 2000, VB script has been the primary language for doing system administration work. The philosophy and design were to provide more scripting features than the .bat or .cmd batching programming. As .NET evolves, developers build sophisticated applications in Visual Studio. But that did not solve the problems VB script was solving. When Microsoft shipped PowerShell, developers or system administrators finally could get out of the VB script hell. As an engineer at Microsoft IT, it’s common to use scripts to manage servers. One thing I learned is that it takes about 6 times more effort to develop scripts in VB than in PowerShell. Most of the time wasted is in debugging VB scripts. I am listing some useful PowerShell scripts I’ve learned:

    # Creating MSMQ
    [Reflection.Assembly]::LoadWithPartialName("System.Messaging")
    $q = [System.Messaging.MessageQueue]::Create(".\private$\organization.response", $true) # true means create transactional queue
    # check if UAC is enabled in Windows Server 2008
    $UAC = Get-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA
    if ($UAC.EnableLUA -eq 1) # UAC is enabled
    # Get the current running script path
    $ScriptDirPath = Split-Path -Parent -Path $myInvocation.MyCommand.Path
    # Check if WMI software is installed
    $Product = Get-WmiObject -Class Win32_product

    $ProductClient = $Product | ? { $_.Name -like "*PRODUCT*Client*" }

    $ProductServer = $Product | ? { $_.Name -like "*PRODUCT*Server*" }
    # Get the previous Exception
    $Error[0].Exception
    # If there is an exception, abort the script
    trap
    {
                Write-Error $("TRAPPED: " + $_.Exception.GetType().FullName);
                Write-Error $("TRAPPED: " + $_.Exception.Message);
                exit 1
    }
    # Get the current windows user
    $userName = [System.Security.Principal.WindowsIdentity]::
    GetCurrent().Name
    # enable script to take argument switches. Put it at the top of the script
    Param(
      [string]$VMDirPath = $(throw "Please specify -VMDirPath"),
      [string]$VM_Name = $(throw "Please specify -VM_Name")
    )

    If you want ADO.NET examples, read http://blogs.technet.com/threekings/default.aspx

  • ASP.NET 2.0 and LINQ

    I have been developing and maintaining an internal website at Microsoft IT which monitors the status of multiple master data management systems for almost 1 year. At the beginning of the development phase, I decided to use ADO.NET for querying and updating system status data. I was satisfied with the flexibility of ADO.NET 2.0. Testing the code was as easy as running queries in SQL server management studio 2005. Recently, I watched several videos at http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/05/10/9322.aspx about .NET integrated query which is a new feature in .NET 3.5. With the aid of Visual Studio 2008, building data model is as easy as few steps of drag and drop into the designer. Visual studio 2008 has a nice designer interface which uses code behind concept to turn database schema into C# code. It all starts with Add New Item -> LINQ to SQL Classes. The file extension is .dbml as you can see in the videos. All I had to do to setup the class was drag the table from Visual Studio’s Server Explorer and drop it to the .dbml designer page.

    The next step is to find out the class name of the code behind page. If the .dbml filename is WebServicesSettings.dbml, the code behind file would be WebServicesSettings.designer.cs. Inside the code file, you would find WebServicesSettingsDataContext class inherited from System.Data.Linq.DataContext. The class enables you to manipulate the data in the database. In the example below, I will show you how to query a string value from table EnvironmentEndpoints and use it as the SQL server hostname to connect to another database to query 4 other string values which are MSMQ endpoints. When the 4 MSMQ endpoints are acquired, the code updates the EnvironmentEndpoints table with the 4 MSMQ endpoints with command EnvEndDC.SubmitChanges();

        byte envID = kvp.Key;

        try

        {

            // the connection string in web.config is used for the default constructor

            EnvEndpointsDataContext EnvEndDC = new EnvEndpointsDataContext();

            // Very useful command similar to SqlCommand.ExecuteScalar

            EnvironmentEndpoint endpoint = EnvEndDC.EnvironmentEndpoints.Single(end => end.EnvironmentID == envID);

            SqlConnectionStringBuilder sqlConSB = new SqlConnectionStringBuilder();

            // build the connection string to connect to the MSMQ endpoint database

            sqlConSB.DataSource = endpoint.SQLServer;

            sqlConSB.InitialCatalog = "ConfigurationStore";

            sqlConSB.IntegratedSecurity = true;

            // example of using impersonation

            ServiceStatus.impersonated = ServiceStatus.impersonateValidUser(serviceAccountUser, serviceAccountDomain, serviceAccountPassword);

            if (!ServiceStatus.impersonated)

            {

                // impersonation failed

                string message = DateTime.Now + " - Impersonaion failed. Continue updating MSMQ endpoints...";

                Trace.WriteLineIf(ServiceStatus.debugSwitch.TraceError, message);

            }

            // connect to the MSMQ endpoint database

            WebServicesSettingsDataContext WebServiceDC = new WebServicesSettingsDataContext(sqlConSB.ToString());

            // WSSetting is a local variable name to the LINQ query for the Single command

            // What I am doing here is querying the row which has column ‘Name’ ServiceAsyncAddressSecondServer

            WebServicesSetting ServiceAsyncAddressSecondServer = WebServiceDC.WebServicesSettings.Single(WSSetting => WSSetting.Name == "ServiceAsyncAddressSecondServer");
            // Update the values in EnvironmentEndpoints table

            endpoint.CorpNetAsyncWebService = ServiceAsyncAddressSecondServer.Value;

            WebServicesSetting AcknowledgmentServiceAddressSecondServer = WebServiceDC.WebServicesSettings.Single(WSSetting => WSSetting.Name == "AcknowledgmentServiceAddressSecondServer");

            endpoint.CorpNetAckWebService = AcknowledgmentServiceAddressSecondServer.Value;

            WebServicesSetting ServiceAsyncAddress = WebServiceDC.WebServicesSettings.Single(WSSetting => WSSetting.Name == "ServiceAsyncAddress");

            endpoint.ExtraNetAsyncWebService = ServiceAsyncAddress.Value == ServiceAsyncAddressSecondServer.Value ? string.Empty : ServiceAsyncAddress.Value;

            WebServicesSetting AcknowledgmentServiceAddress = WebServiceDC.WebServicesSettings.Single(WSSetting => WSSetting.Name == "AcknowledgmentServiceAddress");

            endpoint.ExtraNetAckWebService = AcknowledgmentServiceAddress.Value == AcknowledgmentServiceAddressSecondServer.Value ? string.Empty : AcknowledgmentServiceAddress.Value;

            if (ServiceStatus.impersonated)

            {

                ServiceStatus.undoImpersonation();

                ServiceStatus.impersonated = false;

            }    

            // LINQ runtime generates a SQL update when the line is executed

            EnvEndDC.SubmitChanges();

        }

        catch (Exception ex)

        {

            string message = DateTime.Now + " - Failed to update MSMQ endpoints on Environment ID " + envID + " -> " + ex.GetType() + ": " + ex.Message;

            Trace.WriteLineIf(ServiceStatus.debugSwitch.TraceError, message);

        }

        if (ServiceStatus.impersonated)

        {

            ServiceStatus.undoImpersonation();

            ServiceStatus.impersonated = false;

        }


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker