Geekdojo

Tech people talking tech things
Welcome to Geekdojo Sign in | Join | Help
in Search

Richard Case

  • MsDtc error & BTS Configuration Wizard

    Whilst trying to setup a small multi-box BizTalk environemnt within Virtual Server 2005 this week i've encountered a really annoying error whilst applying my BizTalk configuration settings. The configuration wizard would fail with the following error

    "Failed to Deploy BizTalk system assembly "C:\Program Files\Microsoft BizTalk 
    Server 2004\Microsoft BizTalk.GlobalPropertySchema.dll". 
    
    A Microsoft Distributed Transaction Coordinator Problem prevented Connection
    to the Configuration Database. The transaction has already been implicitly or
    explicitly committed or aborted. 
    
    [MicrosoftBizTalk.Deployment.DeploymentException] Cannot opent database 
    BizTalkMgmtDb on server BTSDB 

    It turns out this is because i had copied the same virtual hard disk for use as the base for each of the virtual machines in my environment. Essentially MsDtc on each of the virtual machines has the same identifiers and therefore cannot communicate with each other. Does anyone know of the internals at all?

    To overcome this i re-installed MsDtc on each of the virtual machines before i installed anything. This is done by running the following within a command prompt (after which i rebooted):
    msdtc -uninstall
    msdtc -install

  • Creating a custom NAnt task

    I've been using NAnt quite a bit lately for automated builds on projects that I have been working on. If like me you require functionality that isn't already within NAnt (or NAntContrib) then you need not worry as it's really easy to write your own custom NAnt tasks to accomplish pretty much anything you could want.

    This post will take you through the creation of a task that I recently wrote called xmllist . I created the task as I wanted to be able to read a list of port names from a BizTalk binding file (which is an xml document) and then loop round this list starting/stopping the ports:

        <xmllist property="ports.list" doc="${binding.file}" selection="//SendPort/@Name" />    
        <foreach item="String" delim="," in="${ports.list}" property="port.name">    
            <exec program="cscript.exe" failonerror="false" commandline="/nologo ${scripts.path}\StartSendPort.vbs ${port.name}"/>   
        </foreach>
    


    The steps required to create the task are:

    1. Create a new Class Library project
    2. Change the project properties so that the name of the output assembly ends with Tasks.dll (i.e. Solidsoft.Build.Tasks.dll). If you don't do this NAnt will not find your tasks.
    3. Add a reference to NAnt.Core.dll found in the NAnt bin directory. This assembly contains the base classes and attributes that are required to build a NAnt task.
    4. Rename the class file to XmlListTask.cs
    5. At the top of the class file add the following using statements:

      using NAnt.Core;
      using NAnt.Core.Attributes;
      

    6. We need to inherit our class from one of the NAnt base task classes. There are a number that we can use depending on our requirements - for our task we will use Task (I will be covering using TaskContainer in a future posting).
    7. Next we need to add the TaskName attribute to our class definition. The purpose of this is to specify the tag name used for our task in a NAnt script. In our case we will use xmllist:

        [TaskName ("xmllist")]
        public class XmlListTask : Task
        {
      

    8. Each NAnt task can have a number of properties. These are represented in the NAnt build file as attributes of the task element. We will have the following properties:

    property Used to specify the name of the property that the list of values should
    be stored in
    doc The document that should be used
    selection The XPath expressions that is used to select the values for the list.

    Adding a property to your task is easy. For example, for the 'doc' property we would define a string property within our class. Then we use the TaskAttribute attribute to specify the name of the attribute that will be used in the NAnt build file to map back to the property in the class that we just created:

        [TaskAttribute ("doc", Required = true)]
        [StringValidator (AllowEmpty = false)]
        public string XmlDocument
        {
          get
          {
            return m_xmldoc;
          }
          set
          {
            m_xmldoc = value;
          }
        }
      
    Properties can be optional or mandatory. To mark a property as required (the user must use the attribute in the build file) you can add Required = true to the attribute - as we have done above. By default properties are optional.

    You will also see that I have used the StringValidator attribute. This allows us to catch the situation where the attribute has been defined without a value (e.g. <xmllist doc="" />). NAnt will see that no value has been supplied and will stop the build with an error.

    Add code to create the property and selection properties - both of which are strings.

    9. Now we get to the interesting bit - the part that actually performs the task. When you run your NAnt build file and it encounters your task it will first read the attributes of the task and populate the relevant properties in your class. Then it will execute your task by calling ExecuteTask. You will need to override the ExecuteTask method of the base Task class. Within this method you place the code to do what ever it is that your task does. In our case create a comma delimited list of values from an xml document. The code I used is below:

     protected override void ExecuteTask()
        {
          //Check the file exists
          string docPath = Project.ExpandProperties(m_xmldoc, Location);
          if (File.Exists(docPath) == false)
          {
            throw new BuildException("The xml document specified does not exist");
          }
          // Load the document and run the selection
          XmlDocument doc = new XmlDocument();
          doc.Load(docPath);
          XmlNodeList list = doc.SelectNodes(m_selection);
          Project.Log(Level.Info, "Found " + list.Count.ToString() + " nodes");
          System builder = new System.Text.StringBuilder();
          foreach (XmlNode node in list)
          {
            builder.Append(node.InnerText);
            builder.Append(",");
          }
          if (builder.Length > 0)
          {
            builder.Length -= 1;
          }
          if (Project.Properties.Contains(m_property) == true)
          {
            Project.Properties[m_property] = builder.ToString();
          }
          else
          {
            Project.Properties.Add(m_property, builder.ToString());
          }
        }
     


    I won't take you through every line as it should be self explanatory. The main thing to note is the use of the Project class throughout the method. The Project class is used to represent the project that is being run and it's what we use to access most project related stuff (i.e. project properties).

    The ExpandProperties method is used to ensure that any properties (not sure what NAnt properties are then go here) that are included as expanded to their actual value. For example, ${nant.project.basedir} will be replaced with the path to the directory where the NAnt script is located.

    The Log method is used to output messages to the log file / screen - useful for informing the user what is happening and for debugging purposes. You can specify a log level - for example you can have messages that are only shown if are running NAnt in verbose mode.

    10. Build the project and copy the assembly to the NAnt bin directory. If you plan to debug it then additionally copy across the pdb file. That's it.


    I use 2 methods to debug my custom tasks:

    1. Copy the assembly (and pdb) file to the NAnt bin directory. Open your solution in Visual Studio that contains the source for your task. Place your breakpoints. Go to the project properties and open the Debugging page. Change the Debug Mode to Program and the Start Application to the path to the NAnt executable (e.g. C:\Program Files\NAnt\bin\NAnt.exe). Then set the working directory and/or command line arguments so that NAnt will pick up your build file. Click run and away you go.
    2. Place System.Diagnostics.Debbugger.Break(); in your code before the line you want to break on. Re-compile the project and copy the assembly (and pdb) to the NAnt bin directory. When you run your NAnt script you should get a popup box asking you to choose a debugger.

This Blog

Post Calendar

<August 2008>
SuMoTuWeThFrSa
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

Post Categories

Syndication

Powered by Community Server, by Telligent Systems