November 2009 - Posts

I really like working with StructureMap. Today I had to write a quick Factory that would leverage StructureMap to create returned instances. The Factory would look like this:

public class HttpListenerFactory : IHttpListenerFactory
{
  private readonly IConfigurationManager configurationManager;
 
  public HttpListenerFactory(IConfigurationManager configurationManager)
  {
    this.configurationManager = configurationManager;
  }
 
  public ICustomHttpListener CreateListenerForMessagesComingFromX()
  {
    var listener = ObjectFactory.GetInstance<ICustomHttpListener>();
    listener.Prefix = configurationManager.GetListenerPrefixForMessagesComingFromX();
    return listener;
  }
 
  public ICustomHttpListener CreateListenerForMessagesComingFromY()
  {
    var listener = ObjectFactory.GetInstance<ICustomHttpListener>();
    listener.Prefix = configurationManager.GetListenerPrefixForMessagesComingFromY();
    return listener;
  }
}

Factory has no parameterized constructor and it’s heavily relies on ObjectFactory provided by StructureMap.

I wanted during testing to keep it as a spec (unit test) and not integration test, heaving all interfaces and implementers hooked up, so bootstrapping StructureMap was not an option. What I could do, is inject mocked implementation in conjunction with the interface. That worked really slick.

protected readonly Mock<ICustomHttpListener> listener;
 
// Arrangement stage
ObjectFactory.Inject(typeof(ICustomHttpListener), listener.Object);
 
// Tear down stage
ObjectFactory.ResetDefaults();

Clean and simple.

I needed to merge a few a few assemblies into one, and tried pretty much what the author of this blog did. I also wanted to be able to “hide” the namespaces merged into main assembly, so that in case there are 2 identical classes in final assembly, only the class from the primarily assembly would be showed by Visual Studio. In my case, it was custom Logger vs. log4net Logger, which I wanted to “hide”.

ILMerge does support it, but providing /internalize switch. Official documentation explains it better:

This controls whether types in assemblies other than the primary assembly have their visibility modified. When it is true, then all non-exempt types that are visible outside of their assembly have their visibility modified so that they are not visible from outside of the merged assembly.

The version of NAnt task I ended up is slightly different:

[TaskName("ilmerge")]
public class ILMergeTask : ExternalProgramBase 
{
  private FileSet m_assemblies;
  private string m_logFile;
  private string m_outputFile;
  private string m_primaryFile;
  private bool internalize;
  
  [TaskAttribute("internalize")]
  [BooleanValidator()]
  public virtual bool Internalize
  {
    get { return internalize;}
    set { internalize = value;}
  }
 
 
  [TaskAttribute("program", Required = true)]
  [StringValidator(AllowEmpty = false)]
  public override string ExeName
  {
      get { return base.ExeName; }
      set { base.ExeName = value; }
  }
 
 
  public override string ProgramArguments
  {
      get { return string.Empty; }
  }
 
  [BuildElement("assemblies", Required=true)]
  public virtual FileSet InputAssemblies
  {
        get
        {
            return this.m_assemblies;
        }
        set
        {
            this.m_assemblies = value;
        }
  }
 
  [TaskAttribute("logfile")]
  public virtual string LogFile
  {
        get
        {
            if (this.m_logFile == null)
            {
                return null;
            }
            return this.Project.GetFullPath(this.m_logFile);
        }
        set
        {
            this.m_logFile = StringUtils.ConvertEmptyToNull(value);
        }
  }     
 
  [TaskAttribute("primary", Required=true), StringValidator(AllowEmpty=false)]
  public virtual string PrimaryFile
  {
      get
      {
          if (this.m_primaryFile == null)
          {
              return null;
          }
          return this.Project.GetFullPath(this.m_primaryFile);
      }
      set
      {
          this.m_primaryFile = StringUtils.ConvertEmptyToNull(value);
      }
  }                 
 
  [TaskAttribute("outputfile", Required=true), StringValidator(AllowEmpty=false)]
  public virtual string OutputFile
  {
      get
      {
          if (this.m_outputFile == null)
          {
              return null;
          }
          return this.Project.GetFullPath(this.m_outputFile);
      }
      set
      {
          this.m_outputFile = StringUtils.ConvertEmptyToNull(value);
      }
  }                 
 
 
  protected override void ExecuteTask()
  {
      try
      {
          Log(Level.Info, "Executing ILMerge.exe");
          Log(Level.Info, string.Format("/out:\"{0}\"", m_outputFile));
          Log(Level.Info, string.Format("/log:\"{0}\"", m_logFile));
          Arguments.Add(new Argument(string.Format("/out:\"{0}\"", m_outputFile)));
 
          Log(Level.Info, string.Format("assembly[{0}]: {1}", "primary", m_primaryFile));
          Arguments.Add(new Argument(string.Format("\"{0}\"", m_primaryFile)));
 
          for (int i = 0; i < m_assemblies.FileNames.Count; i++)
          {
              Log(Level.Info, string.Format("assembly[{0}]: {1}", i, m_assemblies.FileNames[i]));
              Arguments.Add(new Argument(string.Format("\"{0}\"", m_assemblies.FileNames[i])));
          }
 
          Arguments.Add(new Argument(string.Format("/log:\"{0}\"", m_logFile)));
          
          if (Internalize)
          {
            Log(Level.Info, "/internalize");
            Arguments.Add(new Argument("/internalize"));
          }
 
          base.FailOnError = false;
          base.ExecuteTask();
      }
      catch (Exception ex)
      {
          throw new BuildException(string.Format("Error executing ILMerge {0}", "test"), Location, ex);
      }
  }
}

Now Internalized property can be utilized:

<ilmerge outputfile="${main.assembly.name}"
         primary="${temp.assembly.name}"
         program="${ilmerge.dir}\ilmerge.exe"
         logfile="${log.file}"
         internalize="true">
  <assemblies>
    <include name="${build.compile.dir}\log4net.dll" />
  </assemblies>
</ilmerge>

 

I was quiet surprised to learn that C#2.0 is used to compile an inline NAnt task, and not 3.0 (auto property did not work).

As I have already mentioned, I am involved in a project that uses BizTalk 2009. With this beast, you have to develop on the machine that has BizTalk installed and configured. This is vey unfortunate, especially when so many things can go wrong. From my experience in the past I have decided to work in virtual machine. Boy that paid off back so quick. While working on a custom adaptor, something went wrong during deployment and BizTalk 2009 was not responsive anymore. But I had nothing to worry about – I had a snapshot I could go back to.

image

Now the real question I am asking myself – why don’t I do entire development on VM? WPF is not something I do, so no worries about hardware acceleration. VMWare workstation supports mode that will lock you in VM and prevent keystrokes to get out of sandbox. Devices are all recognizable and easily connecting. And with Windows 7 (which has less RAM/CPU requirements than the fabulous Windows XP) it’s even simpler. Another option is to use Windows 7 bootable VHD. Either way, developing on host machine is just not worth it.

I am starting a project that involves a lot BizTalk 2009. Since this is a completely new territory for myself, I decided to blog about it. There a lot of resources available out there, especially from MSDN.

First thing I decided to look at was a Custom pipeline. Two types of pipeline exist – sending and receiving. To understand better pipelines, I read BizTalk 2004: A Message Engine Overview on MSDN. It provides more information than just pipelines that is very useful for general BizTalk understanding (which I find a vital if you plan to develop for BizTalk).

A typical receive pipeline has 4 sections (or “component areas”) and send pipeline 3.

image

image

In BizTalk project these pipelines are presented as a flow, with designated areas where you can drop  components designed especially for any given stage in a pipeline of a certain type. image You can develop pipeline custom components in managed code, but you have to link it to the designer. How that is done? Each component has to be marked with a ComponentCategory attribute to indicate where in pipeline it can be assigned. A component that should be only assigned to Decoding section would be marked as:

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Decoder)]
[System.Runtime.InteropServices.Guid("9D0E4103-4CCE-4536-83FA-4A5040674AD6")]

The interoperability GUID 9D0E4103-4CCE-4536-83FA-4A5040674AD6 stands for “receive pipeline, decode section” and it is used to indicate to Visual Studio designer where the component can be dropped. For this purpose, I have create a component called “CustomPipelineComponent” and decorated with these attributes. Dragged and dropped the component and this is how the BizTalk pipeline looks like after that (XML view):

<?xml version="1.0" encoding="utf-16"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" PolicyFilePath="BTSReceivePolicy.xml" MajorVersion="1" MinorVersion="0">
  <Description />
  <Stages>
    <Stage CategoryId="9d0e4103-4cce-4536-83fa-4a5040674ad6">
      <Components>
        <Component>
          <Name>SimplePipeline.CustomPipelineComponent</Name>
          <ComponentName>SIMPLE Pipeline component</ComponentName>
          <Description>CustomPipelineComponent</Description>
          <Version>1.0.0.0</Version>
          <CachedIsManaged>true</CachedIsManaged>
        </Component>
      </Components>
    </Stage>
    <Stage CategoryId="9d0e4105-4cce-4536-83fa-4a5040674ad6">
      <Components />
    </Stage>
    <Stage CategoryId="9d0e410d-4cce-4536-83fa-4a5040674ad6">
      <Components />
    </Stage>
    <Stage CategoryId="9d0e410e-4cce-4536-83fa-4a5040674ad6">
      <Components />
    </Stage>
  </Stages>
</Document>

If you look close, each section in pipeline (or Stage) has a designated GUID. Decoder has 9D0E4103-4CCE-4536-83FA-4A5040674AD6, same as we used to decorate our component with.

Now the saucy part – how do I debug and test it?

To debug (which is NOT testing) I used BizTalk 2009 SDK utility called Pipeline.exe and located in %ProgramFiles%\Microsoft BizTalk Server 2009\SDK\Utilities\PipelineTools. One disadvantage I found with this utility is the fact that you have to deploy your custom pipeline component assembly to BizTalk 2009 designated location (%ProgramFiles%\Microsoft BizTalk Server 2009\Pipeline Components). Well, at least you can debug your custom component. For that I had to update the project settings of my custom pipeline component project and setup 3 things:

  1. Specify Output for build artifact (Figure 1)
  2. Set Start Action to Pipeline.exe (Figure 2)
  3. Specify Command Line Arguments to use pipeline that contains custom component

image Figure 1

image

Figure 2

When a new instance of Debugger is invoked on component project, debugger will kick in and stop at breakpoints.

image

 

To test a custom component you will have to dig dipper. I have figured a few things:

  1. You cannot do unit testing. BizTalk has integration testing baked in.
  2. You have to include BizTalk test assemblies, located in %ProgramFiles%\Microsoft BizTalk Server 2009\Developer Tools (I wish other blogs would mentions this folder!)
  3. You will have to cast your objects to BizTalk base classes (the ones your maps/pipelines/schemas) in order to invoke testing methods (such as map.TestMap(…), schema.ValidateInstance(…), and pipeline.TestPipeline(…) accordingly)

I found one good blog post about how actually to write a state based testing, so I will not reproduce it here.

PS: an attempt to test pipeline components as unit testing is showed in this blog.

More Posts