March 2004 - Posts

Finding the Class that Implements an Interface

I have a program that performs a process I will call ClientProcess1.  This process is run for many different clients.  Most clients need the generic version of ClientProcess1, but some clients need something special.  Because new clients are being added all the time, there is no way to predict all the different variations of ClientProcess1 that might be needed.  To address this, I decided to provide a generic version of ClientProcess1, but to allow other versions of this process to be dynamically loaded as needed.

All versions of ClientProcess1 must implement an interface I will call ClientInterface.  Any custom versions of this process will exist in separate assemblies.  Each client can be configured with a path to an assembly that includes a specialized version of ClientProcess1.  I show how I dynamically load the specified assembly in a previous post.  Here is how I determine which class in this assembly I should call.

Assembly asm = Assembly.LoadFile("C:\\ProgramDirectory\\CustomAssembly.dll");

foreach (Type t in asm.GetTypes())
{
      Type[] Interfaces = t.FindInterfaces(new TypeFilter(MyInterfaceFilter),"MyNamespace.ClientInterface");

      if (Interfaces.Length > 0)
      {
            ClassToInstantiate = t;
        
    break;
      }
}

You need a delegate that determines how to compare your interfaces.  Here is the one that I use.

public static bool MyInterfaceFilter(Type typeObj,Object criteriaObj)
{
      if(typeObj.ToString() == criteriaObj.ToString())
            return true;
      else
           
return false;
}

XPath Performance in .NET (Revisited)

In a previous post, I mentioned the performance increase that can be had when using XPath queries in .NET.  As I said then, you need to use an XPathDocument instead of an XmlDocument.  Well, being the hard-headed person that I am, I had to learn this the hard way, AGAIN.

I needed to process an XML document that contains hundreds of nodes.  These nodes themselves are quite large.  (My test document was 11MB, but in real life, the documents could reach 80MB.)  I apparently lost my mind, and wrote some code similar to this:  (code changed to protect my client!)

ReturnValue = false;
foreach
(XmlNode Node in _SingleNodeList)
{
     if (<PSEUDOCODE: node contains required data?>)
     {
          ReturnValue = true;
          break;
     }
}


During testing, I found that processing my one test document required 22 minutes.  WAY TOO LONG!  I went home and slept on the problem.

The next day, I wrote something like this:

Result = XPathNav.Evaluate(count(<PSEUDOCODE: XPath expression that returns matching nodes>));
NodeCount = (double)Result;
ReturnValue = (NodeCount > 0);

I ran the test again.  It took at total of 12 seconds.  That's right, I reduced the processing time from 22 minutes to 12 seconds simply by using XPath queries properly instead of iterating over an XMLDocument.  When I ran the REAL test, processing 2,029 files, it took 54 minutes.  Looks like I learned a lesson again.  Hopefully, this will save someone else the time that I wasted.

Microsoft Security Summits

Microsoft is presenting a FREE full-day security summit in 20 cities across the country.  You can check out the specifics at the official web site.  There will be two tracks for the infrastucture types, and one for us developers.  I will personally be presenting all four sessions of the development track in three of the cities; Charlotte, St. Louis, and Seattle.  Come by and say hi!

In the development track, I will show you some common threats and how to defend against them.  We will discuss threat modeling and introduce some established best practices for writing secure code.  We will also discuss how to use features of the .NET framework to further secure your application.

Wouldn't you like to know what the hackers know?

Seriously, if you can attend, you should do so.  With all of the hackers out there, you need to learn how to protect yourself. 

Windows Service Installation Tip

When creating a Windows Service, you will find that you need to need to create an Installer class too.  This Installer class registers the service with the Service Control manager which, of course, allows the service to run properly.  Once your service is complete, you will want to create a Deployment project.  This project installs your service on other computers.  So, here's the tip:

To make the service usable on the new computer, your deployment project must invoke the service Installer class.  You do this by creating a custom install action that calls your service Installer class.  This is so that your service can be registered with the Service Control Manager.  Don't forget to also create a custom uninstall action so that the service Installer class can unregister your service from the Service Control manager too.

I forgot the custom uninstall action.  I then spent 30 minutes manually uninstalling the service entries from the registry.  Don't forget the uninstall action!

Overridden Properties handled differently in C# and VB (Correction)

In a previous post (see Overridden Properties handled differently in C# and VB) I wrote that C# and VB were handling overridden properties differently.  This is not the case.  Brian Orrell wrote:

In C# you have not created a readonly property. You have simply only chosen to override the get implementation of the property. Try it out. If you use the derived class, you will have no problem setting the property that seems to be readonly.

The only difference is that VB does not allow you to override just one of the two accessor methods.

You can never make the accessibility of a derived class LESS than the accessibility of the ancestor.

After a quick check, I found that he is correct.  I want to thank Brian for the heads-up, and to let everyone else have the correct information.

Thanks Brian!

Load Code Dynamically

I recently needed to programmatically load some code from a separate assembly.  I knew this could be done, but wasn't sure exactly how.  After spending 20 minutes searching the net for some examples, I decided to give up and try some things on my own.  Here is my solution.  Hopefully I will save someone the trouble that I experienced.

AppDomain CurrentDomain = null;
ICustom CustomObject = null;

// reference the current Application Domain
CurrentDomain = AppDomain.CurrentDomain;

// create the object
CustomObject = (ICustom)CurrentDomain.CreateInstanceAndUnwrap(“Assembly name goes here“,“Type name goes here“);

Using TraceSwitches

I've known about the TraceSwitch class for quite a while now.  However, I recently discovered how incredibly useful this really is.  I needed to create a Windows Service that invokes multiple threads of execution.  (When you have eight or ten processes executing simultaneously, you need LOTS of status information.)  In production, this information is not needed, and would waste a lot of space.  TraceSwitches provide a way to control the amount of log information that your application produces.

App.config
<configuration>
    
<system.diagnostics>
         
<switches>
              
<add name="General" value="4" />
         
</switches>
     </system.diagnostics>
</
configuration>

You define the switches in your app.config or web.config file.  The name will be used in your code to refer to the switch.  The value, which ranges from 0 to 4, indicates the level of logging you wish:

TraceLevel
0 = Off
1 = Error
2 = Warning
3 = Information
4 = Verbose

In your code, you create some switches, then use them to determine what to write:

Code
mySwitch = new TraceSwitch("General","Entire Application");
if (_Trace.TraceVerbose) { // write very wordy message }
if (_Trace.TraceInfo) { // write less wordy message }
if (_Trace.Warning) { // write warning message }
if (_Trace.Error) { // write error message }

Now I can easily vary my log output from EXTREMELY detailed to very sparse.  This has been a lifesaver.