Saturday, September 18, 2010

Making custom trace listeners more configurable.

The .NET System.Diagnostics namespace provide some classes that can be used to trace the execution of your programm. There are some default listeners in the Diagnostics namespace which can be used to write the trace messages to a file, the event log, etc. You can also write your own trace listeners by extending/overwriting the TraceListener class. These trace listeners can be registered at runtime:
Trace.Listeners.Add(new ConsoleTraceListener());
Or you can specify listeners you want to use in the system.diagnostics section of your .config file:
<listeners>
  <add initializedata="MyEventLog"
        name="EventLogListener"    
        type="System.Diagnostics.EventLogTraceListener">
  </add>
</listeners>
If you use the .config file it would be nice to extend the xml tag by custom attributes. To do so you need to override the GetSupportedAttributes() method in your TraceListener-implementation. In this method you just need to return the names of the custom attributes you want to use in the .config file. For example if you have a custom trace listener that separates trace entries by a delimiter:
protected override string[] GetSupportedAttributes() {
  return new string[] { "delimiter" };
}
Now you can specify the delimiter in you .config file:
<listeners>
  <add delimiter=":"
    initializedata="delimitedOutput.txt" 
    name="delimitedListener"
    type="MyNamespace.MyDelimitedTraceListener">
  </add>
</listeners>
To get the value of the custom attribute you can use the Attributes property of the base class in your TraceListener implementation:
foreach (DictionaryEntry de in this.Attributes) {
  if (de.Key.ToString().ToLower() == "delimiter") {
    source = de.Value.ToString();
  }
}

Sunday, August 29, 2010

Reloaded

After a long time I decided to revive my blog. So here are some news and other stuff I found interesting during the last week:

Saturday, August 29, 2009

Windows Installer Transforms

If you have ever tried to install more than one instance of you application on a single windows machine you probably know that the windows installer permits only one instance of a product code to be installed for a machine or a user. The "brute force" solution is to create a second msi package and use this one for the installation of the second instance. But since the Windows Installer 3.0 there is another option. You can use the transforms feature to install multiple instances of an application using a single msi package. Below I've listed the steps to create and apply a transform using VS and the Windows SDK:
  1. Compile you setup project to generate the base msi package.
  2. Rename the generated msi file to say mykillerapp_base.msi and copy it to another location.
  3. Change the product code (or maybe also the product name) and recompile your setup project.
  4. Copy the first msi package (mykillerapp_base.msi) to the directory with the second msi file generated in previos step.
  5. Run msitran to generate the transform: msitran -g mykillerapp_base.msi mykillerapp.msi setup.mst
  6. Install the first msi package.
  7. Install the second instance: msiexec /i mykillerapp_base.msi TRANSFORMS=setup.mst MSINEWINSTANCE=1
That's it. ;)

Friday, November 28, 2008

Auto-incrementing version numbers with Visual Studio

There are lots of web sites describing how to achieve this. Surprisingly most of them are "roll your own" solutions including custom add-ins, MSBuild-tasks or even custom tools.
But there is an obviously little-known feature in Visual Studio that allready provides this functionality. All you have to do is to edit the AssemblyInfo.cs file in project. Just replace the line [assembly: AssemblyVersion( "1.0.0.0" )]; with [assembly: AssemblyVersion( "1.0.*" )]; and remove the line [assembly: AssemblyFileVersion( "1.0.0.0" )];. You still have the possibility to manually set the major and minor version numbers (first two numbers). The build and the revision number (the last two) will be incremented automatically after each build. Thanks to Marc Charbonneau for telling the world ;) about this feature in his blog.
Edit: It seem like the auto-incrementing the assembly version has an annoying side-effect when applied to an assembly with custom ui controls or WF activities: https://connect.microsoft.com/VisualStudio/feedback/details/568672. The Visual Studio fails to release the handle to that dll during the build.

Sunday, October 26, 2008

Synchronizing Workflow Instances

In a multi threaded program, where different threads use a shared resource, the access to this shared resource needs to be synchronized. Most if not all programming languages or parallel programming systems provide some kind of synchronization mechanisms which help the programmer to protect shared resources and avoid race conditions. Unfortunately the Workflow Foundation (a system that is inherently multi threaded) does not provide a way to synchronize activities across workflow instances out of the box. Of course there is the SynchronizationScopeActivity, but it's only usefull when you need to synchronize parallel activities running in the same workflow instance.
One good reason for the absence of this kind of feature is the fact that if you have a shared resource then you usually access it through a runtime service. Synchronizing the access to the resource is the responsibility of the runtime service and not the responsibility of the workflow.
But nevertheless if you need to synchronize workflow activities across multiple instances or even different workflows you may find this usefull. It's an activity similar to the SynchronizationScopeActivity provided by WF except it synchronizes its child activities between different instances of a workflow.
To use this activity in you workflows you need to add an instance of a runtime service (CustomWorkflowActivities.SynchronizationService) provided with the activity to the workflow runtime first:
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
workflowRuntime.AddService(
  new CustomWorkflowActivities.SynchronizationService(
    workflowRuntime));
Then just insert a RealSynchronizationScope activity into your workflow, set its SharingName property to some unique-within-the-workflow-engine string, and drag activities you wish to synchronize onto the RealSynchronizationScope activity. That's it! The workflow runtime will now serialize the execution of any activities inside your RealSynchronizationScope activity across workflow instances.

Saturday, September 13, 2008

Hello World

Hi there and welcome to my first blog. It seems to be common to start a new blog with a short opening post where the blogger tells the world who he are and what his blog is about. So I'm a software developer and this blog will be about my (main) hobbies: computer programming, music and maybe some other things which are worthwhile to mention. This should be enough for now but I promise, to make my future posts more substantial ;)