Infosys Microsoft Alliance and Solutions blog

« March 2007 | Main | May 2007 »

April 30, 2007

VSTS (Orcas Beta 1) Profiler - Comparing Performance Reports

In my earlier blog I had looked at March CTP of Orcas and talked about performance reports and performance comparison reports and raised a few issues.

I downloaded and started to play around with Orcas Beta 1 today and thought of checking the performance comparison report to start with. I ran the same code as I did earlier and compared the reports.

The first thing I noticed is that the Performance Wizard and related menu options have moved under the new "Developer" menu. The highlighting for hot paths in the Call Tree view (incidently there is a "Current View" label also added before the drop down) has also changed.

The important change is the way the deltas are displayed. A negative delta between baseline report and new report, which signifies a reduction in execution time is now shown with downwards green arrow, while a positive delta is shown with upwards orange arrow (see the snap shot below). This is exactly opposite to what it was in March CTP.

OrcasBeta.JPG

I will explore this further and update this blog with the findings soon.

April 24, 2007

Where are ASP.NET 2.0 Website Project Properties Stored?

Earlier today someone asked me where are the project properties of ASP.NET 2.0 web site stored? This seemingly simple question proved lot more difficult to answer since there is no .CSPROJ file for the web site (I was working with C# and hence .CSPROJ).

I started by creating a new ASP.NET 2.0 Web site project (you can create this on HTTP or file system, the behavior is the same). After that I went to the project properties dialog and modified a few properties like in Start action group, I modified Specific page to some value dummy value and in the Server group I modifed to point to some custom server. Do note that the custom server option can't be set if you created the web site on HTTP.

After this I saved the solution and closed Visual Studio to ensure that all data will be written to disk. However I didn't find any .CSPROJ file in the folder where I had created the project. I decided to search the other paths I knew are used by Visual Studio to store data and first looked at "C:\Documents and Settings\atulg\My Documents\Visual Studio 2005\Projects".

I could see only the .SLN and .SUO files here and no sign of any .CSPROJ file. The SLN file had solution specific entries and the SUO had Visual Studio settings. I then searched the other location where typically files for ASP.NET Site are maintained and that is "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files". However this folder contains files related to code and compiled output and again there wasn't any sign of .CSPROJ file.

I searched the registry but no luck. The project settings were definitely being saved somewhere since I could reopen the web site in Visual studio and see the values as set by me. I copied the project to another machine and when I opened the web site there, I didn't see my custom values, but the default values. This just reconfirmed that the project settings were being saved some place on local machine, but where remained a mystery.

Finally I got an idea and decided to use FileSystemWatcher class to monitor file writes on my machine and hence locate where the information was being saved. I started with Path as "C:\" and NotifyFilter as "NotifyFilters.LastWrite". However when I put a watch on C:\, it resulted in a whole lot of events being generated and I couldn't essentially make out anything.

I suspected the information to be getting stored somewhere in the Documents and Settings folder so I narrowed the Path to "C:\Documents and Settings\atulg". This time, the data was more manageable and I saw writes happening to two files inside of "C:\Documents and Settings\atulg\Local Settings\Application Data\Microsoft\WebsiteCache".

One was to FileAttributes.xml inside another subfolder by the name of the solution and one was to Websites.xml. The FileAttributes.xml didn't contain data of interest, however the other one did and I was finally seeing the project properties data in the Websites.xml file as below

  <Website RootUrl="E:\Work\v3.0\ProjTestWebsite\" CacheFolder="ProjTestWebsite" startpage="whatis this.aspx" customserverurl="http://localhost/ThreadlTest/Default.aspx" addnewitemlang="Visual C#" vwdport="4103" enablevswebserver="false" startaction="1" _LastAccess="4/24/2007 2:18:35 PM"/>

The startpage and customserverurl attributes contained values that I had assigned via the project properties screen.

For those of you who work with Vista, the path for Websites.xml will be as "C:\Users\atulg\AppData\Local\Microsoft\WebsiteCache". 

Do note however, that the entries to this file are written when either Visual Studio is closed or you open another project/solution in it. Just by hitting Save or Save All won't write the project properties in the file.

April 23, 2007

LINQ and its linkage to new features in .NET Framework 3.5 - Part II,,,

In my previous blog “LINQ and its linkage to new features in .NET Framework 3.5 – Part I”, we have seen how a query can be expressed with clarity with object oriented programming notation and couple of code snippets that showed how a class can be extended through “extension” methods – a concept that is introduced in .NET Framework 3.5. It is really important to know that when the query gets executed at runtime. The following code snippet shows the usage of query expression.

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);

The query execution does not happen in this line of code, though it uses the assignment operation. Only when, looping is happening through the foreach statement of IEnumerable[] items, the query gets executed.

See the following code.

 

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);
            Names.SetValue("All's Well That Ends Well", 5);
           
            Console.WriteLine("Shakespeare's play - All's Well That Ends Well - is added into Names,,,");
            Console.WriteLine("=======================");
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }

            Console.WriteLine("=======================");

After assigning the query expression to the type “IEnumerable<string>”, I changed the first element of “Names” to be a Shakespeare’s work – “All’s Well That Ends Well”. Then I do the looping for displaying the result that outputs only the Shakespeare’s works. The Console output now shows this play as well on the screen.

LINQ Part 02 Image

 

This dynamism is very essential when the application deals with highly flux data, on which query is executed.

However, if the changes to the source type happen with in looping logic, we can’t expect the query execution to reflect on those changes. In the following code snippet, change to “Names” is done from within the foreach construct. The output will not reflect this change. But, the updated change will be reflected in the console, in the second looping.

IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length >= 15)
                        .Select(s => s);
            Names.SetValue("All's Well That Ends Well", 5);
           
Console.WriteLine("Shakespeare's play - All's Well That Ends Well - is added into Names,,,");


            foreach (string str in name)
            {
                if (string.Compare(str, "All's Well That Ends Well") == 0)
                {
                    Names.SetValue("Much Ado About Nothing", 8);
                    Console.WriteLine("Shakespeare's play - Much Ado    About Nothing - is added into Names,,,");
                }


                Console.WriteLine("{0}", str);


            }


            Console.WriteLine("======================");
            Console.WriteLine("During Second Run,,,");
            Console.WriteLine("======================");
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }


            Console.WriteLine("=======================");


Console output

LINQ Part 02 Image 02

Now, another twist to this story is all is not really well if there are two static classes that implement the extension method with the same name. Let us assume that we need to build another static class “HenrikIbsenWords” that will have the extension method with the same name (“Select”) as that of “ShakespeareWorks”. That extension method is designed to select only Henrik Ibsen’s plays.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Linq.Expressions;
namespace System.HenrikIbsenQuery
{
    public static class HenrikIbsenWorks
    {
        public static IEnumerable<T> Select<T>(this IEnumerable<T> source, Func<T, string> selector)
        {
            string[] dramasList = {
                                       "The Pretenders",
                                       "Peer Gynt",
                                       "Emperor and Galilean",
                                       "A Doll's House",
                                       "An Enemy of the People",
                                       "The Wild Duck",
                                       "Hedda Gabler",
                                       "The Master Builder"                             
                                      
                                   };
            foreach (T item in source)
            {
                foreach (string str in dramasList)
                {
                    if (string.Compare(item.ToString().ToLower(), str.ToLower()) == 0)
                        yield return item;
                }
            }
        }
    }

}

And if we need to use them interchangeably in the code, by importing namespaces of both those classes (as given in the following code snippet), we will get the following error message during build time.

The call is ambiguous between the following methods or properties:

'System.HenrikIbsenQuery.HenrikIbsenWorks.Select<string>(System.Collections.Generic.IEnumerable<string>, System.Linq.Func<string,string>)'

and

'System.ShakespeareQuery.ShakespeareWorks.Select<string>(System.Collections.Generic.IEnumerable<string>, System.Linq.Func<string,string>)'        

Code Snippet

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.ShakespeareQuery;
using System.HenrikIbsenQuery;
using System.MyStringExtensionNS;
namespace MyConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] Names = {   "Waiting for Godot",
                                 "Death of a Salesman",
                                 "Rosencrantz and Guildenstern Are Dead",
                                 "The Devil's Disciple",
                                 "Mrs. Warren's Profession",
                                 "Arms and the Man",
                                 "Candida",
                                 "You Never Can Tell",
                                 "Caesar and Cleopatra",
                                 "Man and Superman",
                                 "Major Barbara",
                                 "The Doctor's Dilemma",
                                 "Pygmalion",
                                 "My Fair Lady",
                                 "The Pretenders",
                                 "Peer Gynt",
                                 "Emperor and Galilean",
                                 "A Doll's House",
                                 "An Enemy of the People",
                                 "The Wild Duck",
                                 "Hedda Gabler",
                                 "The Master Builder",
                                 "Hamlet",
                                 "Macbeth",
                                 "Othello",
                                 "Venus and Adonis",
                                 "A Midsummer Night's Dream",
                                 "As You Like It",
                                 "Henry VI Part I",
                                 "Henry V",
                                 "Henry IV Part I",
                                 "Henry VIII",
                                 "Richard II",
                                 "Richard III"                                 
                             };
           
           
            IEnumerable<string> name = Names.OrderBy(s => s.Length)
                        .Where(s => s.Length > 0)
                        .Select(s => s);
                        
                       
            foreach (string str in name)
            {
                Console.WriteLine("{0}", str);
            }
            Console.WriteLine("=======================");
            Console.Read();
        }
    }
}
If more than one namespace that are imported into a code, contain extension methods with the same name, it will create the ambiguity problem as we have just seen. But those namespace may contain some other methods that may need to be accessed by our code. In such circumstances, we can mitigate this ambiguity issue through the usage of namespace alias.
In the following code snippet, I have ensured that the extension method of “HenrikIbsenWork” class that is in “System.HenrikIbsenQuery” namespace is being applied to the “Names” type.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Shakespeare = System.ShakespeareQuery;
using System.HenrikIbsenQuery;
using System.MyStringExtensionNS;
namespace MyConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] Names = {   "Waiting for Godot",
                                 "Death of a Salesman",
                                 "Rosencrantz and Guildenstern Are Dead",
                                 "The Devil's Disciple",
                                 "Mrs. Warren's Profession",
                                 "Arms and the Man",
                                 "Candida",
                                 "You Never Can Tell",
                                 "Caesar and Cleopatra",
                                 "Man and Superman",
                                 "Major Barbara",
                                 "The Doctor's Dilemma",
                                 "Pygmalion",
                                 "My Fair Lady",
                                 "The Pretenders",
                                 "Peer Gynt",
                                 "Emperor and Galilean",
                                 "A Doll's House",
                                 "An Enemy of the People",
                                 "The Wild Duck",
                                 "Hedda Gabler",
                                 "The Master Builder",
                                 "Hamlet",
                                 "Macbeth",
                                 "Othello",
                                 "Venus and Adonis",
                                 "A Midsummer Night's Dream",
                                 "As You Like It",
                                 "Henry VI Part I",
                                 "Henry V",
                                 "Henry IV Part I",
                                 "Henry VIII",
                                 "Richard II",
                                 "Richard III"                                
                             };
           
           
            IEnumerable<string> name = Names.OrderBy( s => s.Length )
                                        .Where( s => s.Length > 0 )
                                        .Select( s => s );
                                     
            foreach (string str in name)
                Console.WriteLine("{0}", str);
            Console.WriteLine("=======================");  
            Console.Read();
        }
    }
}

Console ouput

LINQ Part 02 Image

We will see the details about LINQ over database and XML in future blogs.

Loading Multiple Versions of same Assembly

The other day a colleague asked if there was a way he could work with different versions of the same assembly in his code i.e. could he invoke say Method A on Version 1.0 and Method B on Version 2.0 of the same assembly?

I was initially surprised as to why he would want to do that? People ask about being able to automatically load newer version of the assembly with the application or in case of .net being able to load an assembly built with .net framework 1.1 in an application built with .net framework 2.0, but usually not this.

When he explained his situation it made sense. He was working with Sharepoint Server API and there have been some changes in the API between SPS 2003 and 2007. So there was a need to invoke some functionality using SPS 2003 assembly and some functionality using the newer version available with SPS 2007.

I can think of another case where you have programmed against say a buggy assembly and have written some workaround logic for the bug in your code. With the newer version of that assembly that bug has been fixed, but due to some constraints, you can't remove your workaround code and hence can't use the new version. There is however new functionality provided by this new version which you do want to use. Hence you would need to be able to call new methods on new version and the buggy method on the old version.

With this preamble, lets get into how to get this done. There are various permutations and combinations and I will address them. At a high level the solution is in working with one version as already programmed (typically using early binding) and with another version using reflection. Do also note that the assembly loading follows probing rules as defined in .NET SDK documentation. To keep things simple, I will keep the folder path simple and not get into such diversions.

Consider this extremely critical business logic inside of a uniquely named assembly - ClassLibrary1.dll as below. Again to keep things simple, I am not showing the various "using" statements with the code. Additionally to identify which version the method is called on, I return the version# in the string itself. I can do a dynamic query for assembly version and remove this hard coding, but the recall.. our moto is simplicity at this time and focus on loading different versions and not any other aspect, hence the hard coding.

    public class Class1
    {
        public static string Method1()
        {
            return "Method 1 called on version 1.0.0.0";
        }
    }

Then there is this Winform application that invokes this static Method1 and displays the returned string in message box. To help identify if this call has happened due to early binding or reflection, I prefix the string accordingly. I build the code with version 1.0.0.0 of ClassLibrary1.dll and run the application. On invoking the method, I see a message box displaying the appropriate version#. Before we get into multiple versions, a quick discussion of what happens with private as against strong named assemblies is in order.

Weakly named library assembly (privately deployed)

If you update the version of such an assembly and redeploy it with the application, the application is able to load it without any issues. The change in just minor version to 1.1.0.0 or major version also to 2.0.0.0 doens't impact and the application works fine. Note that this is in line with basics of versioning that aren't applicable to weakly named assemblies.

Strongly named library assembly (privately deployed)

If you update the version of such an assembly and redeploy it with the applicaton, the application will give a runtime error when it tries to invoke a method of the library assembly. Due to strong naming, the version policy comes into effect and the application tries to invoked method on version against which it was complied, in this case 1.0.0.0. When it doens't finds this at runtime, it will give an error. It won't automatically start using 1.1.0.0 version. For that you need to specify the
bindingRedirect in the application configuration file.

There are multiple ways to create this configuration file. One is to do this with Visual studio itself and when the application is compiled, the config file is also complied and deployed along wih it. However if you aren't sure of the exact syntax, you can use the Microsoft .NET Framework 2.0 Configuration MMC from Administrators group. Via this you can add the specific application for configuration, then configure the specific library assembly and specify the binding policy. The configuration file generated will look something like this

<?xml version="1.0"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="ClassLibrary1" publicKeyToken="fbc28d9ca2fc8db5" />
        <publisherPolicy apply="no" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>


To reiterate, this bindingRedirect is required only for strongly named assemblies. Once this configuration setting is in place, the application is able to load the 1.1.0.0 assembly and invoke methods on it. The same logic will work for assemblies deployed in GAC.

Let us now get on with loading of different versions of the same assembly. See the sample code below on how to achieve it.

        private void btn_Click(object sender, EventArgs e)
        {
            string str = "early bind - ";
            str += ClassLibrary1.Class1.Method1();
            MessageBox.Show(str);
 
            Assembly al = Assembly.LoadFile(@"E:\Temp\old\ClassLibrary1.dll");
 
            Type t = al.GetType("ClassLibrary1.Class1");
            MethodInfo m = t.GetMethod("Method1");
            str = "reflection - " + (string)m.Invoke(null, null);
            MessageBox.Show(str);
        }

When we run the application, we expect the early binding call to go to the newer version and the call via reflection to go to the older version, that we have specifically deployed in another sub-folder. We are using Assembly.LoadFile method so that we can specify a path.

One important aspect to note here is that the application will have to be compiled with the newer version of the assembly if the assembly is strongly named. If that isn't done, as discussed earlier, we will have to use a bindingRedirect configuration setting. Such setting works for all assembly load calls and will even redirect the assembly load call that we are doing via reflection and hence we will not be able to invoke methods on older version. By explicitly building the application with newer version, we don't need to the bindingRedirect configuration setting and our reflection call to earlier version will then work.

Loading assemblies from GAC

There is slight difference in the way the assembly is loaded via reflection if working against GAC. To successfully load different versions from GAC it is best to use the AssemblyName class and specify the FullName of the assembly you want to load. As we all know, FullName includes name, version number, culture and public key token.

        private void btn_Click(object sender, EventArgs e)

        {

            string str = "early bind - ";

            str += ClassLibrary1.Class1.Method1();

            MessageBox.Show(str);

 

            AssemblyName asm = new AssemblyName("ClassLibrary1, Version=1.1.0.0, Culture=neutral, 
                                                                                            PublicKeyToken=fbc28d9ca2fc8db5"
);

            Assembly al = Assembly.Load(asm);

 

            Type t = al.GetType("ClassLibrary1.Class1");

            MethodInfo m = t.GetMethod("Method1");

            str = "reflection - " + (string)m.Invoke(null, null);

            MessageBox.Show(str);

        }

Needless to say that it also possible to load as many versions as you want using the option of reflection and you need not invoke any version via early binding. I have used to early binding option just to highlight a case where you are already working with a version and want to also specifically invoke methods on a different version. This also means that you can early bind to an older version and load the newer version by reflection.

While playing around with this, I also realized that one needs not worry about references added to the project. The compiler is intelligent enough to add them to the manifest only if a call is made to any method contained in the referenced assembly. If no call is made, the reference isn't included and hence the assembly won't be loaded at run time. You can easily verify this by viewing the manifest via ILDasm utility. 

 

 


 

April 20, 2007

Inside Vista Kernel

Most people, when hear Vista, think about Aero glass affect, great new set of icons and wallpapers and UAC. However there is more to Vista than this. Mark Russinovich in 3 part series on Technet Magazine covers key features of Vista Kernel. Gives good insight into the features and make really interesting reading. Check them out

  1. Part 1
  2. Part 2
  3. Part 3

VSTS (Orcas March CTP) Profiler - Comparing Performance Reports

I recently came across this blog by Ianhu and was interested to explore the comparsion of performance reports.

Being able to compare reports from two performance runs is very important since without it, it becomes very difficult to figure out if one has been able to make improvements or not post the code changes. Hence I created a dummy application that created an array of 200000 strings and then wrote it on the Console. I wanted to see the impact of using an object based ArrayList or a generics based List<T>.

Post the capturing of execution data, I started to look at the report generated. The UI for this has been changed a bit and considering this is March CTP, this may change further. I will hence not get too much into the UI apart from a few quick observations

  1. There is new query option with which you can search for specific items of interest in the report
  2. The various tabs for Summary, Functions, Call Tree, etc have now become drop down items
  3. The earlier Functions view is now same as Modules view. However Functions view is still there, but it no longer shows the parent modules. That is shown in the new Modules tab.
  4. There is a new view for displaying Marks. These can be useful to take a snapshot during the execution for some interesting events. By default it captures the start and end of the performance test session.
  5. There are new views for Process data and for showing the Event tracing for Windows (ETW). See more information on ETW on MSDN and Matt Pietrek's blog. The ETW view doesn't seem to work in March CTP so I couldn't really see what all values it will display.

An interesting addition to the Call Tree view is the support for finding and highlighting hot paths. This is very handy to quickly find out key areas that are most time consuming and can help shortlist areas to explore for performance tuning. The following figure shows how "hot path" look like (with highlighting enabled).


hotspots.JPG

To view hot paths, in the Call Tree view, collapse all the nodes below, keep focus on the top node and hit the "Expand Hot Path" icon in the toolbar.

Coming back to the comparison report. This shows how the time spent in the functions has changed between the two reports and there is visual indication of an increase in time or decrease in time, as seen in the following figure.

comparison.jpg 

There are however few issues that I have with this comparison report and maybe things will change by the time RTM is available.

1. A function taking more time has a positive delta and appears with green upward arrow (as seen in the figure above). This seems to be wrong since when I do performance tuning, I would expect time taken the function to come down.

2. Individual Function time comparison doesn't makes much sense. The comparison should really happen on the overall time basis. Consider a case where a function though is taking more time, but has impacted another function to take far less time and thus giving an overall improvement in the application's performance. This isn't easily understood in the comparison report.

3. In the Functions view, the "Elapsed Inclusive time" shows time spent in that function and all its children. If we look at the application's entry point function, we will get an idea of overall time it has taken for the code to execute. If this time decreases in the second run, it would mean an improvement in the performance. However the comparison report still shows this with negative delta (orange down arrow). There should probably be a mechanism to show overall time comparison for the entry point method separately.

4. In the current version there seems to be some problem in displaying the "Elapsed Inclusive time" comparisons. The values shown in old and new value columns didn't match up with the ones in the baseline and new report. Not only they didn't match, they seemed to be too high.

As I explore this further, I will post more entries here. If you have any comments/observations to share, do post your comments here.

April 18, 2007

WPF - Assigning Icon to Image control

When working with WPF applications, display images is a breeze. The Image control provides rich features to display images of various formats like JPEG, PNG, ICO, BMP, GIF etc. Displaying an image is as simple as setting the Image.Source property to the appropriate image file path. No special coding is required to work with different file formats. 

        <Image Name="icoDisplay" Source="myfile.jpg" />

Ofcourse you need to worry about other aspects like location of the Image control, its size and also setting the Stretch property to appropriately display the image. I haven't shown all that here for sake of simplicity.

However, this is all fine when working with image files directly. What happens when you don't have a direct file path, but an image in memory like an Icon or Bitmap? If you try to assign say an Icon directly to Image.Source, you get a type cast error stating that conversion from Icon to ImageSource isn't possible. ImageSource incidently is the type that Image.Source property expects.

So how do you get this working. I found some hints at the WPF forum. However this still deals with Icon files that are available as application resources.

I was actually building another example where I wanted to display icon associated with any file type, as displayed in the Windows explorer. I could use the Icon.ExtractAssociatedIcon method to get the required Icon and then display it.

Since I was working on a WPF application, I had to display this icon using the Image control and there is where I landed in trouble. Refering to the above forum question, I tried various options and the simplest of code that worked for me is as below. I am providing the complete code here.

Note that directly using Icon in the code conflicts with Window.Icon property and hence I used the IconImage alias to refer to System.Drawing.Icon class. This also requires adding the reference to System.Drawing assembly.

XAML Code

<Window x:Class="WPFWindowAPP.IconLoader"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WPFWindowAPP" Height="164" Width="405"

    >

    <Canvas>

        <TextBox Name="filePath" Canvas.Top="10" Canvas.Left="10" Width="375" ></TextBox>

        <Button Name="browse" Click="browseClick" Canvas.Top="40" Canvas.Right="10" Width="75">Browse</Button>

        <Button Name="btn" Click="btnClick" Canvas.Top="40" Canvas.Right="90" Width="75">Load Icon</Button>

        <Image Name="icoDisplay" Canvas.Left="10" Canvas.Top="80" Stretch="None" />

    </Canvas>

</Window>

Code behind code

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using IconImage=System.Drawing.Icon;
using Microsoft.Win32;
using System.IO;
 
namespace WPFWindowAPP
{
    /// <summary>
    /// Interaction logic for IconLoader.xaml
    /// </summary>
 
    public partial class IconLoader : System.Windows.Window
    {
 
        public IconLoader()
        {
            InitializeComponent();
        }
 
        void browseClick(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.ShowDialog();
            filePath.Text = dlg.FileName;
        }
 
        void btnClick(object sender, RoutedEventArgs e)
        {
            IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
            MemoryStream strm = new MemoryStream();
            ico.Save(strm);
            IconBitmapDecoder ibd = new IconBitmapDecoder(strm, BitmapCreateOptions.None, BitmapCacheOption.Default);
            icoDisplay.Source = ibd.Frames[0];
        }
    }
}

You can copy this code to your own WPF Windows application and try it out. Do also note that the .NET method to extract icon returns a large icon. In case you want to get the small icon, you will have to use p/invoke and call Win32 SHGetFileInfo API from Shell32. You can get a sample implementation of this API here.

There is a catch with this code however. If you implement and run it, you will see that the icons loose their color and are displayed as gray scale. Following code fixes this.

        void btnClick(object sender, RoutedEventArgs e)
        {
            IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
            Bitmap bmp = ico.ToBitmap();
            MemoryStream strm = new MemoryStream();
 
            bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
 
            strm.Seek(0, SeekOrigin.Begin);
 
            PngBitmapDecoder pbd = new PngBitmapDecoder(strm, BitmapCreateOptions.None, BitmapCacheOption.Default);
            icoDisplay.Source = pbd.Frames[0];
        }

Finally, there is yet another way to display the icon and that uses BitmapImage class as shown in the code below.

        void btnClick(object sender, RoutedEventArgs e)
        {
            IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
            Bitmap bmp = ico.ToBitmap();
            MemoryStream strm = new MemoryStream();
            bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);
 
            BitmapImage bmpImage = new BitmapImage();
 
            bmpImage.BeginInit();
            strm.Seek(0, SeekOrigin.Begin);
            bmpImage.StreamSource = strm;
            bmpImage.EndInit();
 
            icoDisplay.Source = bmpImage;
        }

Note that you can use the System.Drawing.Imaging.ImageFormat.Jpeg option as well, but you will loose the transparency effect and the icon will be displayed with a black background.

Comments welcome !

April 16, 2007

WPF/E is now Silverlight

Official name for WPF/E is now Microsoft Silverlight (http://blogs.msdn.com/mpowell/archive/2007/04/15/wpf-e-is-now-silverlight.aspx).

Interesting point on agHost.js name linking with silver and hosting - http://blogs.msdn.com/bardak/archive/2007/04/15/the-story-about-silverlight-and-aghost-js.aspx

Understanding .NET ThreadPool

We had some interesting discussions internally, post my earlier blog on 250 threads/CPU. There are some confusions also on default values and what comes from thread pool etc. I spent a little bit more time on basics and document them.

The ThreadPool contains threads marked as worker threads and IO threads (completion ports). The default max value for these are 25 threads / per process / per CPU. The default min values for these is #CPU, so on a single CPU machine it will be 1.

This means that each process has its own thread pool and not shared with other processes. However AppDomains loaded within a process share the threads in the pool. Do note that the default max and min are based on #CPU. On a dual proc box, the default max will be 50 and min will be 2.

The values can be altered by using ThreadPool.SetMinThreads and ThreadPool.SetMaxThreads. Obviously the min threads cannot be set to value higher than max threads. You can set this to a value lower than current #CPU, like you can set this to 0 on a single CPU box,  but doing that isnt' recommended and can cause performance impact, as also documented in the SDK.

Playing around with Min threads value is necessary sometimes to avoid delays in creating new threads for the thread pool. The delay is 500 ms per thread i.e. only 1 thread is added to the pool per 500 ms. Requests queued for threads will have to wait till a thread is created and is available for use. Idle threads in the pool die out with time.

The BackgroundWorker class introduced with .NET Framework 2.0 also uses threads from the thread pool class. The class has been added to easily work with background threads and on completion of the work, make updates to the UI controls. Note that UI controls can be accessed only on thread that they were created on.

ASP.NET also uses thread pool but has its own default values. The min remains the same, however with ASP.NET 2.0 the default max is 100 for worker and IO threads. These values are altered by appropriate setting the processModel tag in the machine.config file. Surprisingly the machine.config.comments file (available in <WINDIR>\Microsoft.NET\Framework\v2.0.50727\CONFIG) shows these as 20. This isn't entirely incorrect, since the machine.config file carries an auto configuration setting for process model, as below.

  <system.web>

    <processModel autoConfig="true" />
    ...

    ...

  </system.web>

If this auto configuration setting is removed, ASP.NET reverts to the max value of 20. With auto configuration enabled, on a dual CPU box, the max values will be 200.  New requests are handled by the IO threads. As the load increases, IO threads start to post the requests to internal queues and then worker threads take over and do the execution. Refer to this support webcast for more details on ASP.NET 1.0 and 1.0. For ASP.NET 2.0 you can check this blog post.

Comments are welcome !

April 12, 2007

Session 0 and 1 in Vista

Earlier today a colleague asked how do Services and Applications talk to each other in Vista and I said, "the way they used to earlier". I wasn't aware of Session 0 and Session 1 concept till now. He pointed me to this MSDN article that explains what this new concept of Session 0 in Vista is all about.

This essentially is to prevent direct access to services from applications and thus prevent hacker to elevate their own security priviledges. Some information around this is here and on this Channel 9 video. A white paper on impact of session 0 on services and drivers is also available.

[Edited April 16, 2007] Found some tips to communicating with Session 0 services here.

April 9, 2007

Inconsistent Behavior between Assembly.Load overloads

Recently while working on a project, I came across an interesting behavior of Assembly.Load method and its different overloads. I specifically tried with Assembly.Load(AssemblyName) and Assembly.Load(string) overloads.

My testing showed that the overload that accepted a string depended on the value of Environment.CurrentDirectory. Usually when using Assembly.Load method, one would expect the assembly to be loaded from the application's root folder.

In my case, I had a DLL (lets call it ClassLibrary1.dll) which I was trying to load via reflection. Since it was in the application's root folder and folder itself not known (will depend on Installation), I had decided to use Assembly.Load method. I could have used the Application.StartupPath to resolve the path to the assembly and then loaded it, but I decided to go ahead with Assembly.Load. The code looked like

    Assembly al = Assembly.Load("ClassLibrary1");
    Type t = al.GetType("ClassLibrary1.Class1");
    /*...further logic...*/

This worked fine till I had a need to introduce a OpenFileDialog before the call to the Assemly.Load method for some other requirement. The call to that caused the Environment.CurrentDirectory to be set to the path from where the file was loaded and the Assembly.Load call started to fail.

Alternatives exist and I could either use OpenFileDialog.RestoreDirectory option or set the Environment.CurrentDirectory to Application.StartupPath before calling the Assembly.Load method. However the interesting point is that if I used the other overload of Assembly.Load method, things worked fine without these alternatives.

    AssemblyName asmName = new AssemblyName();
    asmName.Name = "ClassLibrary1";
    asmName.Version = new Version(1,0,0,0);
    Assembly al = Assembly.Load(asmName);
    Type t = al.GetType("ClassLibrary1.Class1");
    /*...further logic...*/

The ClassLibrary1.dll wasn't strong named, but making it strong named didn't change this behavior. The setting of Version in the above code snippet is optional and it works fine without setting this also.

This clearly meant that the Assembly.Load(string) overload did something different than Assembly.Load(AssemblyName) and you can very well see this by using Lutz Roeder's Reflector. When you go the string overload method route, there is an extra call to an internal AssemblyName.nInit method, which isn't called when we use the AssemblyName overload route. This call looks like below (as shown by Reflector)

    if (assemblyRef.nInit(out assembly, forIntrospection, true) == -2146234297)
    {
        return assembly;
    }

When we use the string overload, it internally does creates the AssemblyName instance and assigns to the Name property, but due to this additional call to nInit method, the behavior seems to be different. I haven't yet figured out what really happens because this will require exploring the source code and understanding the AssemblyNameNative:Init method in assemblyname.cpp

Hence when using the Assembly.Load methods be careful about the Path from where you expect the files to get loaded and which overload you are using. Note that Activator.CreateInstance(string assemblyName, string typeName) internally uses the Assembly.Load(string) overload and hence it suffers from the same problem that i just described.

 

April 5, 2007

How many Threads have I got?

When working with multi-threaded applications, we all know that we should usually try and work with the ThreadPool class as the first option. In case we have a case where the work done by a thread is long (couple of seconds), we should then look at creating a new thread to avoid starving threads from the pool and behave like a good .net managed citizen.

However there have been issues with this due to the limit of 25 threads/CPU with .NET 1.1, especially for web based applications. The default limit for minimum threads was also set to be equal to #CPU. Note only this caused lot of contention issues, but also required people to play around with the values in the ASP.NET configuration files.

There have been recommendations by MS on what are good values, but it also later prompted MS to add new APIs to .NET CLR 1.1 that allowed one to configure the minimum threads programmatically. This had also became necessary since the addition of new threads to the pool is throttled and takes 500 ms. With the ability to set the minimum threads early on, one could avoid the time delays due to throttling.

Ability to set the minimum threads by itself isn't sufficient since one is still limited by the max threads. One could query this value using the ThreadPool.GetMaxThreads API. To give more flexibility to the developers, .NET 2.0 introduced a new API - ThreadPool.SetMaxThreads.

However with the release of .NET 2.0 SP1, the ThreadPool.SetMaxThread API will become less useful since the default value of threads in the pool has now been increased to 250 threads/CPU.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter