Tuesday, January 09, 2007

I came across a pretty neat program yesterday.  After looking around the net for a good image editing program, I found Paint.NET.  It’s an open source project written in C# by some guys at Washington University in collaboration with Microsoft.  Check it out here.

 

posted on 1/9/2007 12:11:58 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
 Wednesday, March 22, 2006

I recently found a great, 45 minute video of a presentation Microsoft’s Rico Mariani gave to some Microsoft developers regarding CLR Performance.  It doesn’t specifically go into details about the ins and outs of the CLR, but rather stresses a mentality that all developers should adopt to make performance something they think about on a daily basis.  Its certainly motivating and I advocate all developer watch.  Its 45 minutes well spent.

CLR Performance Training

 

posted on 3/22/2006 9:45:15 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
 Tuesday, February 28, 2006

Which App Pool goes with what Worker Process?

Have you ever been in a situation where you have multiple IIS 6.0 worker processes running and had to determine which one belonged to which application pool?  On the surface there aren’t too many tools that will show you this, but I’ve had good luck with the Process Explorer utility from www.sysinternals.com.

By double-clicking on the process and looking all the way to the right of the command line, you’ll see the –ap parameter contains the name of the Application Pool associated with this worker process instance.

 

 

posted on 2/28/2006 10:29:21 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1] Trackback
 Saturday, February 18, 2006

I've installed the new dasBlog software to run a blog site on one of my servers.  It's been a while since I last blogged, but hope to make it a habit.  Hopefully I can pass along some things I know and learn over the coming months.

Thanks for checking in!

 

posted on 2/18/2006 7:17:17 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3] Trackback
 Monday, May 09, 2005

Loading and Unloading Assemblies in AppDomains with Shadow Copying

 

The sample code for this post can be found here.

 

When designing a distributed application infrastructure, I like to build as much “plug-n-play” into the design.  By creating and implementing interfaces into many of components and leveraging System.Runtime.Reflections, I can build a system that dynamically loads assemblies to process the incoming requests from the presentation layer.  By using interfaces, if I want to change the functionality in the mid-tier, I don’t have to worry about changing anything in the presentation layer as long as I implement the interface in the business component that the presentation layer is expecting.  One problem that still remains with this approach of dynamically loading assemblies and calling the contained types through the interfaces is being able to change the implementation on the fly without having to restart any middleware components.  Once you load an assembly into a domain, it remains there until you unload that domain or you restart the process.  If you load assemblies into your default domain, that means you have to restart the process you are executing in.   Until that process is started, you can not copy or update the loaded assembly on disk until you restart.  It would be nice to dynamically load and execute assemblies and update those assemblies in your deployment directory whenever you needed a newer version to take effect the next time it is loaded.

 

Enter “AppDomains” and their “ShadowCopyFiles” property.  By creating new AppDomains and setting particular properties on the type, you now gain the ability to dynamically load and unload assemblies from memory along with being able to physically update the assembly on disk even if it’s loaded into memory.  This now adds a tremendous amount of flexibility with deployment efforts and provides you with an infrastructure to keep your applications up and running while making changes.  In the following text, I’ll show you how to enable your applications to take advantage of these techniques.  Mind you, you need to perform some up-front planning and design work with your application to allow for dynamically loading assemblies even if you don’t create your own AppDomains.  This post further assumes you already have an application/component that dynamically loads assemblies and executes methods on those types through interfaces (if not, I’ll provide some sample code to so you how do that).

 

The first thing we want to do is setup the interface the calling component will utilize to call the method implementation provided in the dynamically loaded assemblies.  In this sample “plug-n-play” architecture, the calling component does not care about what’s in the pluggable components just as long as they implement the interface it knows about.  Here’s what the sample interface looks like.

 

public interface IProcess

{

      bool Execute(String xml);

}

 

All components that will plug-in to the application architecture will implement this interface.  There will be code in the calling component to ensure all assemblies loaded implement it.

 

Now we have to provide to the calling component some configuration information that defines the available plug-in components it can call.  For this sample, we simply use the App.config file to store the key and the assembly name and type we want to dynamically load.  Here’s what the sample uses to get the corresponding assembly type and name for a particular key.

 

<appSettings>

      <add key="Assem1" value="AssemToLoad.Class1, AssemToLoad" />

</appSettings>

 

In this particular example, the key we will use is hard-coded into the program.  We could have just as easily provided a list box or other UI component to allow a key to be selected from a collection.  In middleware, we could have used an XPATH expression into an XML document being passed around to extract some information to be used as our key.  It all depends on the application, but you get the point.

 

As mentioned earlier, all plug-in components must implement the interface because this is the “contract” the calling component will use to execute the implementation code.  The sample simply creates a class that implements the interface.  It’s pretty generic and does nothing more than echo the passed in string with a wrapper to the debugging console.  Here’s the class.

 

public class Class1 : MarshalByRefObject, AssemInterface.IProcess

{

      public Class1()

      {

      }

 

      #region IProcess Members

 

      public bool Execute(string xml)

      {

            Debug.WriteLine("----> Execute: "+xml+" <----");

            return true;

      }

 

      #endregion

}

 

You’ll notice this class implements the interface we defined earlier.  It guarantees us the calling program/component will be able to load this assembly and call the Execute method which is a member of the IProcess interface.  Notice also this class is derived from the MarshalByRefObject class.  Most of the time you see this class used when deriving objects that will be remoted from one process to another.  It will become more apparent later why we need to derive from this class.

 

Now that we have our interface, or “contract” that both the caller and callee know about and understand, we can move onto the calling component.  The implementation of this component is a simple WinForm application as it provides an easy way to show and test how this pluggable architecture works.  When requested to load and execute the assembly, this code will:

 

1.)   Create a new AppDomain with ShadowCopyFile turned on

2.)   Lookup the assembly to load from a configuration file

3.)   Load it into the new AppDomain

4.)   Call the implementation method through the interface

5.)   Unload the assembly by unloading the AppDomain

 

Here’s the code that creates the AppDomain.

 

AppDomainSetup setup = new AppDomainSetup();

setup.ShadowCopyFiles = "true";

setup.ShadowCopyDirectories =

Path.GetDirectoryName(Application.ExecutablePath);

setup.ApplicationName = "TheAppDomain";

AppDomain domain = AppDomain.CreateDomain("myAppDomain", null, setup);

 

The first thing we do is create a new instance of the AppDomainSetup object.  With this object, we can configure the creation parameters of the new AppDomain we will create.  The ShadowCopyFiles property is set to “true”.  Notice this is a string and not a bool (not sure why they did it that way :->).  Next, we set the ShadowCopyDirectories property to the directory the calling component is executing from.  In this sample, all pluggable components will also reside in this directory.  We did this to make sure that all assemblies loaded from this directory would be part of the Shadow Copy.  The string can have multiple directories all separated by a semi-colon.  In this case, when an assembly is loaded into the domain we are creating, a copy will be made in another directory and loaded from there.  This directory is the shadow copy directory.  There are other properties that you can change to define where the files will be shadow copied to, but I left that off as an exercise for the reader.

 

To finish up, we assign an application name to this setup object and then call the static method AppDomain.CreateDomain to create the domain we will start loading assemblies into.  We pass the AppDomainSetup object we created so the AppDomain is created with the settings we want, in particular, the ShadowCopyFiles settings.

 

Now that are AppDomain is created, we need to find our assembly and load it into the new AppDomain.  Here’s the code that does that.  It simply takes information from the App.Config file.

 

String assemKey = ConfigurationSettings.AppSettings["Assem1"];

string[] s = assemKey.Split(new char[] { ','} );

String assemType = s[0].Trim();

String assemName = s[1].Trim();

 

This reads the assembly information from the configuration file and splits out the name and type to be loaded.  Now, we just need to load the assembly into our new domains.  One line of code does that.

 

object obj = domain.CreateInstanceAndUnwrap(assemName, assemType);

 

The assembly has been loaded into our new domain and is ready to be called.  You would think at this point we have a reference to an object running another AppDomain.  However, since AppDomains isolate and logically partition assemblies,  we can’t call objects across AppDomains boundaries.  So what is this “object”.  It’s actually a proxy similar to a client proxy that’s generated when you’re working with remoted objects.  Thus the reason for having our class that’s loaded dynamically being derived from the MarshalByRefObject class.  This allows the class to be remoted across AppDomain boundaries.

 

We’ll now use the interface we created earlier to call the implementation method.  Before blindly calling the method on the interface, we’ll check it to ensure the type implements the interface we’re going to use.  If it doesn’t, we could throw an exception at this point or gracefully display a message to the user.

 

AssemInterface.IProcess iAppReqProc = null;

if (obj is AssemInterface.IProcess)

{

       iAppReqProc = obj as AssemInterface.IProcess;

       bool retVal = iAppReqProc.Execute("<root></root>");

}

 

The last bit of cleanup we now want to perform after calling the method is to unload the assembly from memory.  Although you can’t do this directly, you can do it by unloading the AppDomain you’ve created earlier.  Unloading the AppDomain will also unload all the assemblies that are in the AppDomain.  The sample has this line of code in a finally block to ensure it gets called no matter what happens.  It’s just a one line call to a static method, like so.

 

AppDomain.Unload(domain);

 

Now, because we’ve created a new AppDomain, we can load and unload assemblies dynamically.  But more important, we can also update those images on disk while they are loaded and executing as well.  This is because the files, prior to being loaded, were copied to another directory and loaded from there.  It makes for a real nice deployment scenario.  Just XCOPY the files to your deployment directory and the next time it gets loaded, the new version is used.

 

If you want to know more about AppDomains and how to set them up, I highly recommend the MSDN library and to read through the AppDomain class along with the AppDomainSetup class.   Here’s some additional links to other blogs that delve further into more detail than what I’ve provided here.

 

Good luck with your pluggable architectures!

 

http://msdn.microsoft.com/asp.net/community/authors/royosherove/default.aspx?pull=/library/en-us/dncscol/html/csharp05162002.asp

 

http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx

 

http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx

 

 

 

posted on 5/9/2005 4:56:44 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
 Sunday, March 20, 2005

I recently found one of the best add-on .NET managed code libraries for doing any system level coding.  It’s a library created by Renaud Paquay of Microsoft that provides a bunch of .NET C# classes that wrap all of the Win32 APIs for security.  All those calls to create/modify/delete ACLs, DACLs, SACLs, SIDs and Security Descriptors are abstracted away in C# classes.

 

I just completed a project that was a Windows Service written in C# that would launch configured applications under different security contexts needing access to the interactive desktop.  The library saved me a ton of work and made it almost enjoyable to work with the security objects surrounding Window Stations and Desktop.  I highly recommend this library to anyone who needs to work with the security of Window objects (I would hope that’s everyone who considers themselves a developer :->).

 

http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=e6098575-dda0-48b8-9abf-e0705af065d9

 

 

posted on 3/20/2005 6:15:09 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
 Wednesday, February 23, 2005

In one of the C# custom actions in an MSI installer project I’ve been working on, I needed a way to set a system wide environment variable and have it take effective immediately.  There are plenty of methods in the System.Environment namespace, but most are for reading the environment.  So, we need to turn to the good ole P/Invoke technology to make calls directly to the underlying Win32 API layer.  With a few DllImport statements and letting all the active windows know something has changed in the environment, we can accomplish this with a relatively small amount of code.  Here’s a small method you can use to add a new directory to the system wide PATH environment variable (Error checking as been removed for brevity).

 

       const UInt16 WM SETTINGCHANGE = 0x001A;

       const int SMTO ABORTIFHUNG = 0x00000002;

 

       [DllImport("User32.dll", SetLastError=true)]

       public static extern Int32 SendMessageTimeout(IntPtr hWnd,

              UInt32 Msg,

              UInt16 wParam,

              IntPtr lParam,

              Int32 fuFlags,

              Int32 uTimeout,

              ref UInt32 lpdwResult

              );

 

       public void AddPathToSystemPath(String pathToAdd)

       {

              String path = "PATH";

              // To set a Global environment variable

              String registryKey = @"System\CurrentControlSet\Control\Session Manager\Environment";

              Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( registryKey, true);

              String retVal = (String)rk.GetValue( path);

              // concatenate the new path

              retVal += ";"+pathToAdd;

              rk.SetValue( path, retVal);

              rk.Close();

              // notify all top level windows to make this change immediate

              UInt32 result = 0;

              IntPtr pEnv = Marshal.StringToHGlobalAnsi("Environment");

              SendMessageTimeout(new IntPtr(-1), WM SETTINGCHANGE, 0, pEnv, SMTO ABORTIFHUNG, 3000, ref result);

              Marshal.FreeHGlobal(pEnv);

       }

 

 

 

posted on 2/23/2005 2:05:16 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback