Contents tagged with .NET

  • Google and Bing Map APIs Compared

    At one of the local golf courses I frequent, there is an open grass field next to the course. It is about eight acres in size and mowed regularly. It is permissible to hit golf balls there—you bring and shag our own balls. My golf colleagues and I spend hours there practicing, chatting and in general just wasting time.

  • Learning to Like Linq or, Loving the Linq Loquacious

    Once upon a time, long, long ago, I was working at a company that gave their engineers some shiny, state-of-the-art, new-fangled HP calculators. They were awesome; instead of battery-draining LEDs for display, they used something called an LCD. And, they had buttons galore: more buttons than any other calculator at that time. We positively drooled at their appearance. They looked something like this:

  • ILDasm Helpful Hack

    I do not want to learn "yet another programming language", especially a low-level one like Microsoft's Intermediate Language (IL). And yet, sometimes it's useful to look under the hood and see what in tarnation is going on. And that means knowing something about IL.

    I was answering a question on optimization (the root cause of a lot of unmaintainable code) and found it useful to generate the IL to show which of two algorithms was quicker. With modern operating systems having dozens of background threads running, simple timing can lead to misleading results. Is the algorithm slow, or was System Restore creating a restore point when we measured?

    In order to examine code in IL, it's helpful to delimit sections. But we can't use comments, they are stripped out. So, here is a cheesy way to delimit sections of code. Note the variables assigned to MyInt:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {                      
                string MyString = string.Empty;
                int MyInt;
     
                MyInt = 0xAAAAAAA; // ---- Marker: algorithm A
     
                if (MyString == String.Empty)
                    MyInt = 1;
                else
                    MyInt = 2;
     
                MyInt = 0xBBBBBBB;  // ---- Marker: algorithm B
     
                MyInt = MyString == String.Empty ? 1 : 2;
     
                MyInt = 0xCCCCCCC;  // ---- Marker: end test.
            }
        }

    When you create the IL with ILDasm, you can easily see where the markers are. In this case I bolded and underlined them:

      .method private hidebysig static void  Main(string[] args) cil managed
      {
        .entrypoint
        // Code size       68 (0x44)
        .maxstack  2
        .locals init ([0] string MyString,
                 [1] int32 MyInt,
                 [2] bool CS$4$0000)
        IL_0000:  nop
        IL_0001:  ldsfld     string [mscorlib]System.String::Empty
        IL_0006:  stloc.0
        IL_0007:  ldc.i4     0xaaaaaaa
        IL_000c:  stloc.1
        IL_000d:  ldloc.0
        IL_000e:  ldsfld     string [mscorlib]System.String::Empty
        IL_0013:  call       bool [mscorlib]System.String::op_Equality(string,string)
        IL_0018:  ldc.i4.0
        IL_0019:  ceq
        IL_001b:  stloc.2
        IL_001c:  ldloc.2
        IL_001d:  brtrue.s   IL_0023
        IL_001f:  ldc.i4.1
        IL_0020:  stloc.1
        IL_0021:  br.s       IL_0025
        IL_0023:  ldc.i4.2
        IL_0024:  stloc.1
        IL_0025:  ldc.i4     0xbbbbbbb
        IL_002a:  stloc.1
        IL_002b:  ldloc.0
        IL_002c:  ldsfld     string [mscorlib]System.String::Empty
        IL_0031:  call       bool [mscorlib]System.String::op_Equality(string, string)
        IL_0036:  brtrue.s   IL_003b
        IL_0038:  ldc.i4.2
        IL_0039:  br.s       IL_003c
        IL_003b:  ldc.i4.1
        IL_003c:  stloc.1
        IL_003d:  ldc.i4     0xccccccc
        IL_0042:  stloc.1
        IL_0043:  ret
      } // end of method Program::Main
     

    A quick look at the IL code should tell you which algorithm is fastest…and you don't even have to be a rocket surgeon.

    But, of course, as any seasoned developer will tell you: "It's the maintenance stupid!"

    I hope you find this helpful.

    Steve Wellens

    [Update]

    My friend Svante pointed out to me that it is the JIT that does the final optimization and you can’t really go by IL to determine which algorithms are quicker.  He is correct.

    To look at the JIT output…

    Go to Tools->Options->Debugging->General and unclick "Suppress JIT optimization on module load."  You want the optimization.
    Add a breakpoint to the code. Run the program, when the breakpoint hits, right-click the source code and select "Go to Disassembly."   I removed the "markers" because they are no longer needed.

    JIT Output (edited):

                    if (MyString == String.Empty)
        00000050  mov         edx,dword ptr ds:[02CC102Ch]
        00000056  mov         ecx,dword ptr [ebp-40h]
        00000059  call        6A625FB8
        0000005e  mov         dword ptr [ebp-4Ch],eax
        00000061  cmp         dword ptr [ebp-4Ch],0
        00000065  sete        al  
        00000068  movzx       eax,al
        0000006b  mov         dword ptr [ebp-48h],eax
        0000006e  cmp         dword ptr [ebp-48h],0
        00000072  jne         0000007E
                        MyInt = 1;
        00000074  mov         dword ptr [ebp-44h],1
        0000007b  nop             
        0000007c  jmp         00000085
                    else
                        MyInt = 2;
        0000007e  mov         dword ptr [ebp-44h],2

     

                    MyInt = MyString == String.Empty ? 1 : 2;
        0000008c  mov         edx,dword ptr ds:[02CC102Ch]
        00000092  mov         ecx,dword ptr [ebp-40h]
        00000095  call        6A625FB8
        0000009a  mov         dword ptr [ebp-50h],eax
        0000009d  cmp         dword ptr [ebp-50h],0
        000000a1  jne         000000AD
        000000a3  nop             
        000000a4  mov         dword ptr [ebp-54h],2
        000000ab  jmp         000000B4
        000000ad  mov         dword ptr [ebp-54h],1
        000000b4  mov         eax,dword ptr [ebp-54h]
        000000b7  mov         dword ptr [ebp-44h],eax

    I hope this extra information is helpful to someone.

  • Debugging a Deployed Site

    "It works on my machine."

    How many times have we heard that?  Getting something to work on other machines, after deployment, can be the final challenge in a successful project.  The worst case scenario is having to go to the problem machine (hopefully it isn't in the remote reaches of Siberia) installing the IDE, patches, source code, third party libraries, compiling and then debugging.  It's not a pleasant task.

    An often overlooked but useful tool is:  System.Diagnostics.Debug.WriteLine(...)

    Here are some sample lines in global.asax:

    <%@ Application Language="C#" %>
     
    <script RunAt="server">
     
        void Application_Start(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("****ApplicationStart");
        }
        void Application_BeginRequest(object sender, EventArgs e) 
        {
            System.Diagnostics.Debug.WriteLine("Application_BeginRequest");
        }
        void Application_EndRequest(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Application_EndRequest");
        }
        void Session_Start(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Session_Start");
        }

    Here is what the outputs look like in Visual Studio: Debug->Windows->Output. I turned off the Module Load messages to keep the output cleaner. An interesting thing to note is that the first Application_BeginRequest triggers the Session_Start event. Clicking a button a few times generates the other Application_BeginRequest events.

       

    So far so good, but how does this help debugging on a deployed machine? The answer is by using a free tool called DebugView from Sysinternals.  Microsoft has acquired Sysinternals so you can search Microsoft's web site to download it.

    Here is the same output captured by DebugView. The extra lines are caused by a Sound Card device driver on the host machine (the developers may have made a mistake).

       

    Notes:

    1)  Depending on the operating system, you may need to turn on global capturing of events in DebugView:

    Capture->Capture Global Win32

    2)  Debugging strings are turned off when compilation debug is false in web.config. To get the debug strings to work, debug must be "true"

    <compilation debug="true" strict="false" explicit="true">

    3)  If you run the site in Visual Studio, you will not see the strings in DebugView. 

    I hope you find this information useful.

    Steve Wellens

  • Internet Explorer 7 and CSS….DOH!

    I wanted a cheap, simple visual indicator similar to a progress bar. Note, not the kind of dynamic progress bar used when updating AJAX pages, more of a single-bar graph. It should have been simple task.

    My plan was to use a Div as a container, implemented through a panel because they are more convenient to work with. Inside the Div I would put a Label control (which renders as a Span element) with an opaque background color, 100% height, and the width being the percentage done of the progress bar value.

    I dropped the controls on the page, added a function to set the percentage and it looked good. And then I looked closer…what the heck (WTH)?

    You can see the label is shifted down one pixel. Not a big deal, but…perfection is in the details.

    I spent time playing with CSS settings trying to get the Label inside the Div to line up correctly. I tried using a read-only textbox instead of a label but alas, IE7 and CSS are more stubborn then I am.

    I then tried using a Div inside of a Div with a Label in the inner Div to hold the text. It worked but the Asp code was ridiculous looking with its three nested elements. The code was too ugly for me to tolerate.

    Finally, I got it back to simple code by putting a Label inside of a Label without using a Div.

    Here is the Asp code for both versions of the ProgressBar:

        You have this much gas left in the tank:<br />
        <asp:Panel ID="ProgressBarContainer1" runat="server" 
            Height="18px" Width="324px" 
            Style="border-color: Black; border-width: 1px; border-style: solid;" 
            HorizontalAlign="Left">
            <asp:Label  ID="LabelProgressBar1" runat="server" 
                Text="10%"
                Height="100%" 
                Width="10%"
                BackColor="Yellow">
            </asp:Label>
        </asp:Panel>
        <br />
     
        Your project is this late:<br />
        <asp:Label ID="ProgressBarContainer2" runat="server" 
            Height="18px" Width="324px" 
            Style="border-color: Black; border-width: 1px; border-style: solid;">       
            <asp:Label ID="LabelProgressBar2" runat="server" 
                Text="10%" 
                Height="100%" 
                Width="10%" 
                BackColor="Yellow">
            </asp:Label>
        </asp:Label>

    Here is the function that updates the Progress Bar. I left the code in the affects both implementations:

        // ---- UpdateProgressBar -------------------------------
     
        void UpdateProgressBar(int Percent)
        {
            if (Percent < 0)
                Percent = 0;
            if (Percent > 100)
                Percent = 100;
     
            // first implementation
            LabelProgressBar1.Width = new Unit(Percent, UnitType.Percentage);
            LabelProgressBar1.Text = String.Format("{0}%", Percent);
     
            // second implementation
            LabelProgressBar2.Width = new Unit(Percent, UnitType.Percentage);
            LabelProgressBar2.Text = String.Format("{0}%", Percent);       
        }

    Here are both versions of the ProgressBar:

    Of course, this would be much nicer as a user control…but I didn't want to take away from the two points of this post:

    • Sometimes easy things are hard.
    • Sometimes it's hard to find easy solutions.

    I hope someone finds this helpful.

    Steve Wellens

  • Microsoft Chart Controls for the .Net Framework

    I haven't been impressed by any new technology in a long time…until I downloaded and tried out the new Microsoft Chart Controls for the .Net Framework. It contains charts for both Forms and Asp.Net applications. It was easy to put this chart in an Asp.Net page:

        

     

    The Charts home page is here: http://code.msdn.microsoft.com/mschart

    If you want to try it, you need to download these:

    Chart Controls for .NET Framework

    Chart Controls Add-on for Visual Studio 2008

    Chart Controls for .NET Framework Documentation (optional)

    To build the chart, I started with an SQLDataSource connected to the NorthWind database. I used a custom SQL String to sum up the sales for each week (7 days) given a beginning OrderDate. For the OrderDate parameter, I used a Calendar control.

    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
        ConnectionString="<%$ ConnectionStrings:NorthWind %>"
    
        SelectCommand="
    
        SELECT OrderDate, Sum(Quantity * Unitprice) as OrdersTotal 
    
        FROM Orders, [Order Details] 
    
        WHERE Orders.OrderID = [Order Details].OrderID AND 
    
           OrderDate BETWEEN @OrderDate AND dateadd(day, 7, @OrderDate) 
    
        GROUP BY OrderDate  
    
        ORDER BY OrderDate">
    
        <SelectParameters>
    
            <asp:ControlParameter 
                ControlID="Calendar1" 
                DefaultValue="7/30/1996" 
                Name="OrderDate"
    
                PropertyName="SelectedDate" />
    
        </SelectParameters>
    
    </asp:SqlDataSource>

    I dropped a GridView onto the form and fired it up to make sure the data connectivity was working. Clicking dates on the Calendar, causes the GridView to update immediately.

    Next, I dropped the Chart control from the Data tab of the ToolBox. I set the DataSourceID to be the same as the GridView's DataSourceID.

    The number of settings in the Chart control can be a bit overwhelming at first but if you dig around and drill down, you will eventually find what you need: With power and flexibility comes complexity.

    The final Asp markup code was surprisingly short:

    <asp:Chart ID="Chart1" runat="server" 
        BackColor="LightSkyBlue" 
        BackGradientStyle="VerticalCenter"
        BackSecondaryColor="128, 128, 255" 
        BorderlineColor="Black" 
        BorderlineDashStyle="Solid"
        BorderlineWidth="3" 
        DataSourceID="SqlDataSource1" 
        Width="400px" Height="300px"
        Style="top: 337px; left: 18px; position: absolute">
        <Titles>
            <asp:Title Name="Title1" 
                Text="Weekly Sales by Day" 
                Font="Times New Roman, 12pt, style=Bold">
            </asp:Title>
        </Titles>
        <Series>
            <asp:Series Name="Series1"  
                XValueMember="OrderDate" 
                YValueMembers="OrdersTotal">
            </asp:Series>
        </Series>
        <ChartAreas>
            <asp:ChartArea Name="ChartArea1">
                <Area3DStyle Enable3D="True" />
                <AxisY Title="Dollars">
                    <MinorGrid Enabled="True" />
                    <LabelStyle Format="{0:C}" />
                </AxisY>
            </asp:ChartArea>
        </ChartAreas>
    </asp:Chart>

    Of course, I should remove the .00 from the Y Axis, increase the font size of the Y Axis Title, change the format of the X Axis labels to show the day of week, etc. There are tons (and I mean tons) of features with this control….you could spend hours tweaking this thing. But it sure looks good.

    I hope you find this useful.

    Steve Wellens

    • Nested Generic Lists? Cool!

      While answering a question on the Asp.Net forums, I was pleasantly surprised to find nested Generic Lists are possible. They seem much easier than multidimensional arrays.

      Here is the key line:     List<List<int>> MyListOfIntLists; 

          protected void Button1_Click(object sender, EventArgs e)
          {
              List<int> MyInts1;
              List<int> MyInts2;
       
              List<List<int>> MyListOfIntLists;
       
              // create the list of lists
              MyListOfIntLists = new List<List<int>>();
       
              MyInts1 = new List<int>();
              MyInts1.Add(1);
              MyInts1.Add(2);
              MyInts1.Add(3);
       
              MyInts2 = new List<int>();
              MyInts2.Add(4);
              MyInts2.Add(5);
              MyInts2.Add(6);
       
              MyListOfIntLists.Add(MyInts1);
              MyListOfIntLists.Add(MyInts2);
       
              // access the list of lists
              MyInts1 = MyListOfIntLists[0];
              MyInts2 = MyListOfIntLists[1];
          }

       

      I hope you find this useful.

      Steve Wellens