How to Unit Test WF4 Workflows

Recently I asked you to vote on topics you want to see on endpoint.tv. Coming in at #3 was this question on how to Unit Test WF4 Workflows.

Because Workflows range from very simple activities to long and complex multi-step processes this can be a very challenging.  I found after writing many activities that I began to see opportunities to create a library of test helpers which became the WF4 Workflow Test Helper library.

In this post I’ll show you how you can test a simple workflow using one of the helpers from the library.

Testing Activity Inputs / Outputs

If you have a simple activity that returns out arguments and does not do any long-running work (no messaging activities or bookmarks) then the easiest way to test it is with WorkflowInvoker.

The Workflow we are testing in this case contains an activity that adds two Int32 in arguments and returns an out argument named sum

The easiest way to test such an activity is by using Workflow Invoker

[TestMethod]

public void ShouldAddGoodSum()
{
var output = WorkflowInvoker.Invoke(new GoodSum() {x=1, y=2});

Assert.AreEqual(3, output["sum"]);
}

While this test is ok it assumes that the out arguments collection contains an argument of type Int32 named “sum”.  There are actually several possibilities here that we might want to test for.

  1. There is no out argument named “sum” (names are case sensitive)
  2. There is an argument named “sum” but it is not of type Int32
  3. There is an argument named “sum” and it is an Int32 but it does not contain the value we expect

Any time you are testing out arguments for values you have these possibilities.  Our test code will detect all three of these cases but to make it very clear exactly what went wrong I create a test helper called AssertOutArgument.

Now let’s consider what happens if you simply changed the name of the out argument from “sum” to “Sum”.  From the activity point of view “Sum” is the same as “sum” because VB expressions are not case sensitive.

But our test code lives in the world of C# where “Sum” != “sum”.  When I make this change the version of the test that uses Assert.AreEqual gets this error message

Test method TestProject.TestSumActivity.ShouldAddBadSumArgName threw exception:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

If you have some amount of experience with Workflow and arguments you know that the out arguments are a dictionary of name/value pairs.  This exception simply means it couldn’t find the key – but what key?

Using WorklowTestHelper

  1. Download the binaries for WorkflowTestHelper
  2. Add a reference to the WorkflowTestHelper assemblies
  3. Add a using WorkflowTestHelper statement

To use AssertOutArgument we change the test code to look like this

[TestMethod]

public void ShouldAddGoodSumAssertOutArgument()
{
var output = WorkflowInvoker.Invoke(new GoodSum() { x = 1, y = 2 });

AssertOutArgument.AreEqual(output, "sum", 3);
}

Now the error message we get is this

AssertOutArgument.AreEqual failed. Output does not contain an argument named <sum>.

Wrong Type Errors

What if you changed the workflow so that “sum” exists but it is the wrong type?  To test this I made “sum” of type string and changed the assignment activity expression to convert the result to a string.

The Assert.AreEqual test gets the following result

Assert.AreEqual failed. Expected:<3 (System.Int32)>. Actual:<3 (System.String)>.

This is ok but you do look twice – Expected:<3 then Actual:<3 but then you notice the types are different.

AssertOutArgument is more explicit

AssertOutArgument.AreEqual failed. Wrong type for OutArgument <sum>. Expected Type: <System.Int32>. Actual Type: <System.String>.

Summing It Up

AssertOutArgument covers three things, make sure the arg exists, make sure it is the correct type and make sure it has the correct value.  Of course there is much more to the WF4 Workflow Test Helper that I will cover in future posts.

Los Angeles Web Camp

A few months ago I blogged about some Web Camp events that Microsoft is sponsoring around the world.  These events provide a great way to learn about ASP.NET 4, ASP.NET MVC 2, and Visual Studio 2010.  The events are free and the feedback from people attending them has been great.  We are working to setup many more web camps around the world in the months ahead.

This Friday (September 10th) we’ll be holding a free web camp in Los Angeles. Phil Haack, Jon Galloway, and James Senior will all be presenting at the event – so it will be really good.

Details on the Los Angeles Web Camp can be found here. We just got additional space so some extra seats are now available. They are filling up fast, though, and will be sold out soon.  Learn more and register here if you want to grab them and attend.

Hope this helps,

Scott

P.S. In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu

BizTalk 2010 Hands on Days

The BizTalk User Community in Australia & New Zealand have come together to present a community event around BizTalk Server 2010. The event will be a Saturday event in many cities around Australia and New Zealand showcasing the new features of BizTalk Server 2010. The day will consist of short talks about the new feature and then hands on labs to allow you first hand experience with the new features.

For details on the Hands on Day in your city please visit www.biztalksaturday.com

Hope to see you at one of the Hands on Days

Bill Chesnut

DictionaryAdapter is Love (Part 2)

In our last installment, we learned the basics of how to use DictionaryAdapter to use an interface to access loosely structured data.  This time, we’re going to show a somewhat more complex scenario than simple properties.  Consider the following:

 

        static void Main(string[] args)
        {
            var dict = new Dictionary<string, object>()
                {
                    { "UserId", 1234567 },
                    { 
                        "UserName", new Dictionary<string,object>()
                        {
                            { "UserFirstName", "Tim" },
                            { "UserLastName", "Rayburn" }
                        }
                    }
                };
        }

As you can see, we’ve nested dictionaries this time, where the UserName key has a value of another dictionary, with two keys itself.  The simplest model for this is to simple add another interface, IUserName, which represents this nested data.  Here is a look at that code:

    public interface IUserData
    {
        [Key("UserId")]
        int Id { get; set; }

        [Key("UserName")]
        IUserName Name { get; set; }
    }

    public interface IUserName
    {
        [Key("UserFirstName")]
        string FirstName { get; set; }

        [Key("UserMiddleName")]
        string MiddleName { get; set; }

        [Key("UserLastName")]
        string LastName { get; set; }
    }

So lets see how DictionaryAdapter (it’s called DA by its friends, which if you’re still reading at this point you clearly are) so lets see how DA handles this scenario.  We’d hope that something like this would work:

        static void Main(string[] args)
        {
            var dict = new Dictionary<string, object>()
                {
                    { "UserId", 1234567 },
                    { 
                        "UserName", new Dictionary<string,object>()
                        {
                            { "UserFirstName", "Tim" },
                            { "UserLastName", "Rayburn" }
                        }
                    }
                };

            var data = new DictionaryAdapterFactory().GetAdapter<IUserData>(dict);

            Console.WriteLine(data.Name.FirstName);
        }

Does it? Nope.  Why?  Let’s look at the details:

System.InvalidCastException was unhandled
  Message=Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]' to type 'Part2.IUserName'.
  Source=Part2.Part2.IUserData.DictionaryAdapter
  StackTrace:
       at Part2.UserDataDictionaryAdapter.get_Name()
       at Part2.Program.Main(String[] args) in C:\source\BlogPosts\DictionaryAdapterIsLove\Part2\Program.cs:line 32
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

I have to give credit where credit is due, this make pretty darned clear what the problem is.  Our nested dictionary is not, itself, being wrapped so when DA tries to retrieve it and cast it to IUserName it, obviously, cannot.

That’s great Tim but how do I fix that?

Enter behaviors.  Dictionary adapter has an abstraction over anything that modifies how it does its work called Behaviors.  You can create behaviors for all sorts of things, but one of them is Property Getting.  To modify this behavior you need to do two things:

  1. Create a class which implements the IDictionaryPropertyGetter interface.
  2. Modify your request to the Factory to request your DA use that behavior.

If we take a peek at IDictionaryPropertyGetter you will see the following definition:

    public interface IDictionaryPropertyGetter : IDictionaryBehavior
    {
        object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue, PropertyDescriptor property, bool ifExists);
    }

As you can see this isn’t terribly complex.  But you’ll also notice that it implements IDictionaryBehavior, so lets take a peek at that shall we?

    public interface IDictionaryBehavior
    {
        int ExecutionOrder { get; }
    }

Again, not very complex at all.  So we need a class that will implement both of these, and which will examine the propertyDescriptor parameter to determine if the requested Type is itself an interface which is not assignable from the type of storedValue but that storedValue is assignable from IDictionary.  If those conditions are met, we can create another DictionaryAdapter to adapt to the new interface.  Here is a simple example of that class :

    public class NestedDictionaryGetterBehavior : IDictionaryPropertyGetter
    {
        public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue, PropertyDescriptor property, bool ifExists)
        {
            if (property.PropertyType.IsAssignableFrom(storedValue.GetType()))
            {
                return storedValue;
            }

            if (property.PropertyType.IsInterface && IsDictionary(storedValue.GetType()))
            {
                return dictionaryAdapter.This.Factory.GetAdapter(property.PropertyType, storedValue as IDictionary);
            }

            return storedValue;
        }

        public int ExecutionOrder
        {
            get { return 0; }
        }

        private bool IsDictionary(Type type)
        {
            return typeof(IDictionary).IsAssignableFrom(type);
        }
    }

As you can see, some code, but not lots of code.  Our example should skip the first if statement and go into the second one, returning the new DictionaryAdapter.  Now we need to do step 2, modify our original request to the Factory to add our behavior.  Here is what the code looks like once we’ve done that:

        static void Main(string[] args)
        {
            var dict = new Dictionary<string, object>()
                {
                    { "UserId", 1234567 },
                    { 
                        "UserName", new Dictionary<string,object>()
                        {
                            { "UserFirstName", "Tim" },
                            { "UserLastName", "Rayburn" }
                        }
                    }
                };

            var data = new DictionaryAdapterFactory()
                .GetAdapter(typeof(IUserData),
                dict,
                new DictionaryDescriptor().AddBehavior(new NestedDictionaryGetterBehavior())) as IUserData;

            Console.WriteLine(data.Name.FirstName);
            Console.ReadLine();
        }

Now, that gets a little tedious to do every time, and I can assure you that Craig Neuwirt hates tedious.  As such, DictionaryAdapter will look for any attributes on your interface which implement IDictionaryBehavior and add them for you automatically.  So with a very simple refactoring of our class:

    public class NestedDictionaryGetterBehavior : Attribute, IDictionaryPropertyGetter

We can then modify our interface:

    [NestedDictionaryGetterBehavior]
    public interface IUserData
    {
        [Key("UserId")]
        int Id { get; set; }

        [Key("UserName")]
        IUserName Name { get; set; }
    }

And move back to a very simple DictionaryAdapterFactory request:

            var data = new DictionaryAdapterFactory().GetAdapter<IUserData>(dict);

And I think that’s enough for this time.

One-Click Publishing of .NET4 Workflow (XAML) Definitions for Services hosted in AppFabric – similar to the ’Activate’ Workflows in SharePoint Server 2010!

 

Simplifying publishing of the Workflow definitions

Typically Business Analysts (IT Pro) own the process of creating Workflow definitions while publishing this definition, particularly to production environments, is relegated to IT/Production Systems Staff. While this approach is acceptable in many commercial establishments, there is also the need for corporations with relatively smaller IT Org footprint to handover responsibility of publishing and managing Workflow definitions to the IT Pros.

SharePoint Server makes it possible for IT Pros and Business Analysts to seamlessly design and ‘activate’ Workflow definitions with ‘one-click’ http://technet.microsoft.com/en-us/library/cc262348.aspx; IT industry expects similar experiences to publish definitions while using .NET4 based Windows Workflow (WF) applications. IT Pros abhor the use of the Workflow Designer within Visual Studio 2008 and consequently, the re-hosted Workflow Designer Application (see this link for more on re-hosting Workflow Designer) with the ‘one-click’ publish function is required. Increasingly, developers are looking for samples to jump start the implementation of the ‘one-click’ publication of Workflow definitions to Windows Server AppFabric. This blog entry addresses this need.

Without this ‘one-click’ approach the publishing process (deploying Workflow definitions from a re-hosted Workflow Designer), is very tedious. Requiring manual file copy; creating the package on the re-hosted Designer; importing the package and running the configuration steps on the remote AppFabric Server. Another advantage of automating the process is that it is less prone to potential errors due to the manual steps. Investing in this ‘one-click’ feature will pay off in multiple ways for a long time.

Scenario

For this blog post, we define a scenario wherein an ISV Developer is building a Workflow Studio that re-hosts the Windows Workflow Designer. The ‘one-click’ method leverages Microsoft’s Web Deployment Framework to publish XAMLX Workflow definitions from the Workflow Studio to the designated Windows Server AppFabric Server (with IIS role enabled).

The Workflow Studio is a lightweight equivalent to the Visual Studio 2010 Workflow Designer experience. This Workflow Studio includes the ‘one-click’ publishing method in addition to other features that are required to manage the definition once deployed to the AppFabric Server.

Solution

Overview

One key requirement for performing the remote publishing of the Workflow definition is that the Workflow Studio Application needs to provide the IIS Server’s URI/location along with user account credentials. This is illustrated in the graphic below.

The other ‘steps’ in developing the ‘one-click’ method are presented below.

Step 1: Publish local project as an application on the remote IIS Server

Web Deploy is used to publish the project as an application on the IIS Server. The code below leverages the Web Deploy API to perform the remote publishing actions. This action synchronizes a project directory ‘source’ (e.g., Workflow Studio) with a destination application hosted on the target IIS Server. The source in this scenario is the Workflow Studio’s Workflow project directory containing XAMLX,.config files and supporting .NET assemblies. The destination is the remote IIS Server. Also required is a reference to Microsoft.Web.Deployment.dll in order to use the Web Deploy API in the Workflow Studio Application code. This assembly is available at %program files%/IIS/Microsoft Web Deploy/.

In scenarios where the IIS Server does not provide a trusted certificate, there is the need to provide a delegate to enable the Workflow Studio deployment code to trust any certificate from the server. The ‘one-click’ Publish operation in the Workflow Studio is very similar to that provided by Visual Studio 2010 via the Web Deploy command line switch: -allowUntrusted.

   1: using System.Net;

   2: ServicePointManager.ServerCertificateValidationCallback = (s, c, chain, err) =>

   3: {

   4:     return true;

   5: };

 In preparing the Web Deploy DeploymentObject for synchronization, some options are required to be set and these are: DeploymentBaseOptions, DeploymentProviderOptions and the DeploymentSyncOptions.

DeploymentBaseOptions define host information and DeploymentProviderOptions define provider info and key attribute data. The DeploymentSyncOptions provide settings for customizing the actions of the synchronization itself. The web deployment synchronization involves creating a Deployment Object from a source of information (project, website, application, app pool etc.) and synchronizing this info to a destination object. The source in this case is the project we want to publish as an IIS application on the server.

In the code sample below, we start by configuring the DeploymentBaseOptions for the source as well as the Destination. Setting TempAgent to true enables this synchronization operation to run from a temporary, “on demand” installation of Web Deploy. This is handy for cases where the Web Deploy Remote Agent Service may not be installed at the destination. Two notes: there are different Authentication Type settings used and the choice depends on needs of the destination; and the second is the string used for destinationBaseOptions.ComputerName which is the path to the Web Deployment handle and this is the Web deploy installation default.

Note: Web Deploy supports over 30 different providers out-of-the-box. These providers supply a useful set of tools that address a wide array of synchronizing needs. Resources that can be synchronized include: web sites, applications, content folders and files, databases, registry keys, assemblies in the GAC and more. A custom provider is built for this ‘one-click’ Application and is covered detail in the following section.

After creating the DeploymentBaseOptions, we create the DeploymentProviderOptions for the source and destination, setting the WellKnownProvider and Path for each. We use the IisApp WellKnownProvider because it will be able to use the project folder to create/update a copy of it as an IIS Application at the destination. The path of the source’s DeploymentProviderOptions points to the project’s directory, and the path for the destination’s DeploymentProviderOptions direct the IisApp Provider to the website and application that will be the target of this sync.

Next DeploymentSyncOptions are created, setting DoNotDelete switch to true. The DoNotDelete switch is important; this leaves any un-matching files at the destination alone. Without this setting turned on, these files would be deleted during the sync which is detrimental to this and follow-on projects.

With all knobs for the synchronization created; the Deployment Object, created, is configured with the source information. We call a SyncTo operation on this Object, passing in the Destination and Sync options. The return value of this Operation is a structure that contain information useful to provide the status on the publish process to the IT Pro.

   1: DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions()

   2: {

   3: ComputerName = "localhost";

   4: TempAgent = true;

   5: };

   6: 

   7: string deploymentServer = Server;

   8: DeploymentBaseOptions destinationBaseOptions = new DeploymentBaseOptions()

   9: {

  10: ComputerName = "https://SERVER.COM:8172/msdeploy.axd"; 

  11: UserName = Username;

  12: Password = Password;

  13: AuthenticationType = "Basic"; 

  14: };

  15: 

  16: if (deploymentServer.Equals("localhost"))

  17: {

  18:     destinationBaseOptions.ComputerName = "localhost";

  19:     destinationBaseOptions.AuthenticationType = "NTLM";

  20: }

  21:         

  22: DeploymentProviderOptions sourceProviderOptions = new DeploymentProviderOptions("IisApp");

  23: sourceProviderOptions.Path = @"C:\projectDirectory";

  24:  

  25: DeploymentProviderOptions destinationProviderOptions = new DeploymentProviderOptions("IisApp");

  26: destinationProviderOptions.Path = "Default Web Site/ExampleApp";

  27:  

  28: DeploymentObject projectSourceObject = DeploymentManager.CreateObject(

  29:     sourceProviderOptions,

  30:     sourceBaseOptions);

  31:  

  32: DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();

  33: syncOptions.DoNotDelete = true;             

  34:  

  35: DeploymentChangeSummary results = projectSourceObject.SyncTo(

  36: destinationProviderOptions,

  37: destinationBaseOptions, syncOptions);

  38: 

  39: if (results.Errors > 0)

  40: {

  41: MessageBox.Show(

  42: String.Format("Publish Failed. {0} errors. {1} warnings.",

  43: results.Errors, results.Warnings), "Publish Failed",

  44: MessageBoxButton.OK, MessageBoxImage.Error);

  45: }

  46: else

  47: {

  48: MessageBox.Show(

  49: String.Format("Publish Succeeded. Added {0} objects. Deleted {1} objects. Updated {2} objects. Transferred {3} bytes.",

  50: results.ObjectsAdded, results.ObjectsDeleted, results.ObjectsUpdated, results.BytesCopied), "Publish Succeeded",

  51: MessageBoxButton.OK, MessageBoxImage.Information);

  52: 

  53: System.Diagnostics.Process.Start("http://" + deploymentServer + "/" + dirName + "/" + System.IO.Path.GetFileName(fileNames[0]));

  54: }

 The above synchronization is a quick sample that does the job, which can be modified in a number of ways to suit your deployment needs. For your reference, there are a few links at the end of this post to elaborate on the MSDeploy API scenarios.

Step 2: Enable Net.Pipe Protocol

Since these Workflow Services are hosted in Windows Server AppFabric, each application requires the net.pipe protocol enabled so that AppFabric can manage instances of the published service.

These changes are required to be applied on the server at applicationHost.config file (%windows%\ System32\inetsrv\config\ ). In order to modify these settings, a Deployment Object is created using the Application on the Server, add the DeploymentSyncParameter that will set the Enabled Protocols and Synchronize this Object to the Application on the Server. Here another Publish is being processed using Web Deploy, using Provider AppHostConfig and DeploymentSyncParameter is added to the Deployment Object before the Sync.

   1: DeploymentObject iisAppObject = DeploymentManager.CreateObject(

   2: DeploymentWellKnownProvider.AppHostConfig,

   3: "Default Web Site/WorkflowApplication",

   4: destinationBaseOptions);

   5: 

   6: DeploymentSyncParameter protocolParameter =

   7: new DeploymentSyncParameter("EnableProtocols", 

   8: string.Empty, string.Empty,

   9: string.Empty);

  10: 

  11: protocolParameter.Add(

  12: new DeploymentSyncParameterEntry(

  13: DeploymentSyncParameterEntryKind.DeploymentObjectAttribute,

  14: @"application", "application/@enabledProtocols", string.Empty));

  15: 

  16: protocolParameter.Value = @"http,net.pipe";

  17:  

  18: iisAppObject.SyncParameters.Add(protocolParameter);

  19: 

  20: DeploymentProviderOptions destinationOptions = new DeploymentProviderOptions(

  21: DeploymentWellKnownProvider.AppHostConfig);

  22: 

  23: destinationOptions.Path = "Default Web Site/WorkflowApplication";

  24:  

  25: iisAppObject.SyncTo(

  26: destinationOptions, destinationBaseOptions, new DeploymentSyncOptions());

 

Summary

Earilier in this post, we have demonstrated the ease with which we are able to provide the re-hosted Workflow Designer client, a lightweight application that handles a complicated remote publishing process, in a relatively simple manner. Overall, we achieved the ‘one-click’ publication of the Workflow definitions.

References

Below are a compilation of resources that could be useful as you build these interesting features on the re-hosted Workflow Designer.

1. Microsoft.Web.Deployment Namespace

2. Web Deploy Command Line Reference

3. Web Deploy Providers

4. Web Deployment Tool Official Forum on IIS.net

5. Server Manager Class

6. ASP.NET Configuration File Hierarchy and Inheritance

7. “MSDeploy API Scenarios”, James Coo

8. “..connection to a IIS server with self-issued certificate ..“, Kateryna Rohonyan

9. “MSDeploy Custom Provider Take 1”, Sayed Ibrahim Hashimi

10. “Writing Extensible Providers for WebDeploy V1 RTM”, Web Deploy Team Blog

11. “Search your configuration sections in web.config files using IIS 7.0 APIs”, CarlosAg

12. “How to read/write administration.config”, Kanwaljeet Singla

ACSUG September Meeting: BizTalk Solution Patterns with Quoc Bui from the BizTalk Customer Advisory Team

ACSUG September Meeting: BizTalk Solution Patterns with Quoc Bui from the BizTalk Customer Advisory Team

The next Auckland Connected Systems User Group meeting is set for Thursday the 23th of September at 5:30pm. Presentation starts at 6:00pm. This month we have a member of the famous BizTalk and Windows Server AppFabric Customer Advisory Team (http://blogs.msdn.com/b/appfabriccat) presenting about the best practices and patterns around building BizTalk Server solutions. Don’t forget to […]

Thinking about WS* and REST

Thinking about WS* and REST

In a previouspost I highlighted a great webcast by Scott Hanselman on OData and discussed the metaphor he used to explain OO and SO (the Librarian Service). I’d like to continue discussing that webcast and this time turn my attention to REST and WS*. To paraphrase Scott’s explanation,” SOAP is great for (that kind of) […]

Learning BizTalk Server: How to start?

On BizTalk Server General forum I sometimes see people asking how to start learning BizTalk. Responses to these questions vary a little and links are provided to numerous resources, but what would be a good starting point? In my view the Microsoft BizTalk Server site and BizTalk Server Developer Center are good starting points. A successful  learning path for BizTalk Server depends on:

  • Knowledge of .NET and Visual Studio (BizTalk artefacts);
  • Knowledge of SQL Server since BizTalk depends on SQL Server (see BizTalk Architecture picture below);

For publish/subscribe, see patterns/practices article and understanding BizTalk Server 2009.

  • Invest in time and money, a good training from experienced professionals can speed up the process of learning BizTalk. Spend time to build up routine and experience.

Knowledge of .NET and Visual Studio

Development for BizTalk Server is done through Visual Studio. Visual Studio has templates for BizTalk artefacts like orchestration, pipelines, schemas and maps, so a BizTalk solution can be created (design time) and deployed to the BizTalk runtime. Besides artefacts .NET development can be done in creating pipeline components, custom functoids, custom adapters, and .NET helper classes to aid in orchestrations. As a BizTalk professional Visual Studio is your friend and required to build BizTalk solutions.

Knowledge of SQL Server

BizTalk Server depends on SQL Server and Microsoft BizTalk Server databases and their health is very important for a successful BizTalk Server messaging environment. How to achieve this is explained in How to maintain and troubleshoot BizTalk Server databases and if you review that article it will become obvious that you need SQL Server knowledge.

Invest in time and money

When you start learning BizTalk you will need to invest in time and get hold of some budget to get training, books (Amazon, see list here), software (MSDN) and hardware (you need at least a laptop/desktop with enough memory, disk and processor power). Learning can be done at a local training facility or you can go to Quicklearn and Pluralsight. If you do not have enough resources as in software/hardware you still can learn/experience BizTalk through BizTalk Server Virtual Labs.

I have explained the success factors for a successful learning path for BizTalk and if you have the necessary prerequisites as in software and a machine (laptop/desktop) you can start cracking. Best way to proceed is to build your own BizTalk environment with the installation guide in your hand (I assume you start with the latest version available, currently BizTalk Server 2009) .

A BizTalk development environment can best be installed and configured on a Virtual PC or Hyper-V (see this post BizTalk Virtual Machines with Windows 2008 R2 Hyper V). As soon as you have your environment available, download the BizTalk help file and follow the tutorials  described in there(which can be viewed online too or downloaded). Through self study you setup your own environment, do tutorials, try virtual labs and read books. If that is not enough you can get training:

QuickLearn offers BizTalk training classes and Pluralsight also offers BizTalk training classes ranging from introductory to advanced. If you’re just getting started, you might want to check out their self-paced BizTalk Developer Fundamentals class. Finally, visit QuickLearn’s Technical Library for resources and articles on BizTalk.

Besides that, there are several good resources available online:

ESB Toolkit

It is possible that after gaining experience- and building/strengthen your knowledge in BizTalk you want to take it a step further by learning the ESB Toolkit. If you have your BizTalk environment available you can download and then install and configure ESB Toolkit 2.0 (targeted for BizTalk 2009, while version 2.1 is target for new BizTalk 2010). For reading you can start with a whitepaper by Jon Flanders. In general you will find a lot of resources at BizTalk Server Development Center -> BizTalk ESB Toolkit 2.1.

I hope with this post it will be clear to people how to start with learning BizTalk Server. Although you my find it a long learning path, you will find that there are plenty of resources at your disposal.

Technorati: BizTalkBizTalk Server 2009