Generate generic BizTalk messages from Dynamics CRM 2011

For the Word version, with some extra pictures and nicer formatting, see here

Generating BizTalk Messages from Dynamics CRM

Otherwise, here’s the quick copy/paste version. Enjoy.

BizTalk – Generating Outbound Messages from Dynamics CRM

[Author’s Note]: Please don’t judge me solely on the quality of this particular post. I’m trying to help someone out by posting this, and as a result I am rushing it far too quickly.

There are several ways you could approach this process, and depending on the requirements, your mileage may vary. In this particular post I’d like to outline one method I have found effective, which is to leverage CRM plugins to do the heavy lifting, and utilize BizTalk purely as a message routing mechanism via receive & send ports. If I were a ‘full-time’ BizTalk expert, it’s entirely likely I would be more comfortable letting more of the logic reside inside BizTalk (complex mappings, orchestrations, etc.) but I have found personally it is far easier FOR ME to keep the BizTalk side very simple and straightforward using simplified custom schemas and routing mechanisms in BizTalk, and leverage .NET to populate the BizTalk-compliant schema objects inside of CRM.

This example is based on a 4.0 implementation so any code snippets you see may not be up-to-date for CRM 2011, but the concepts are exactly the same.

  1. Utilize your existing (or new) custom BizTalk schemas

In your BizTalk project, you will have various schemas (.xsd) that you want to populate from CRM. For this example consider two schemas in our BizTalk project/application that we want to populate and send to BizTalk from CRM plugins – Account and Contact. These custom schemas containing the general fields we are interested in, with whatever data types we choose (irrelevant of CRM, we will have to translate/map them as necessary later in the plugin), are built/defined within a BizTalk project and are deployed to our chosen BizTalk application (beyond the scope of this example)

 

  1. Define the plugin component

The next thing we will do is create a ‘BizTalk Plugin’ that will do all the heavy lifting of populating and sending our BizTalk messages, and use our source control provider of choice to ‘share’ the schemas that we want to expose in the plugin from the BizTalk project. This will give us the hook to be able to refresh our plugin if the BizTalk Schema changes.

So, under our BizTalk Plugin source code, we might have a folder structure something like below:

 

SchemaBuilders: This is the set of classes containing logic that handles the population of the schema classes from CRM data. Each BizTalk schema you generate a class file for will have a corresponding ‘SchemaBuilder’ responsible for populating that schema with CRM data properly when passed the entity context. The schema builders leverage the generated schema classes by mapping and assigning properties from the entity context and returning a ‘populated’ schema class to be sent to BizTalk.

Here is a snippet of the kind of code that would be inside the schema builder’s primary method ‘BuildSchemaObject’:

//name fields

 

//Salutation

contactSchema.Contact_Detail.Name_Complete.Name_Salutation = contact[‘salutation’];

 

//first name

contactSchema.Contact_Detail.Name_Complete.First_Name = contact[‘firstname’];

 

//last name

contactSchema.Contact_Detail.Name_Complete.Last_Name = contact[‘lastname’];

 

Note that the left hand side corresponds to properties in the schema class, and the right hand side represents data in the triggering entity. We are just mapping one to the other.

Schemas: This folder contains the generated .cs files for each linked .xsd ‘source’ schema from the BizTalk project. In this case you see the BizTalk schemas under ‘SourceFiles/CRM Outbound’ and the generated .cs files CRM_Account.cs and CRM_Contact.cs in the root of ‘Schemas’.

GenerateClasses.bat: This file is a simple batch script that uses xsd.exe to regenerate the .cs files if the schema files change. When the underlying BizTalk project schemas are modified, you need to ‘get latest’ from those shared source schema files in the plugin, then use the batch script to regenerate the .cs files, and make any required logic changes to the logic and schemabuilder files. Each line of the batch script will look something like:

xsd.exe -c -n:CRM.Plugins.Schemas.CRM_Account -l:c# “CRM Outbound\CRM_Account.xsd” /outputdir:../

 

where CRM.Plugins.Schemas.CRM_Account is the desired namespace of the generated class, c# is the desired language of the class file, ‘CRM Outbound\CRM_Account.xsd’ is the relative path of the schema file, and the parent folder of the batch file location (../) is the desired output location for CRM_Account.cs

 

Plugin.cs: The main body of the plugin now simply implements branching logic to determine what the triggering entity is, and based on the triggering entity, invoke the appropriate schema builder and send the result to biztalk. [In this example, ‘send to Biztalk’ means pushing an XML message into an MSMQ queue that BizTalk has been configured to monitor]

//Based on the entity that is triggering the plugin, we will need to generate different

//BizTalk messages. This switch statement allows us to branch to the appropriate Builder

//based on the triggering entity.

switch (this.EntityName)

    {

        case “contact”:

        //Step 1: Contact message

        //create the Schema Object and populate it

        Schemas.CRM_Contact.Contact_Information contactObject = Builder_CRM_Contact.BuildSchemaObject(this,context);

 

        sendToBizTalk(BuildSchemaXml(contactObject));

                  …

Helpful Tricks:

I borrowed most of these from a series of blogs and trial and error – apologies to anyone I am referencing without attribution, any links I used are long lost to me

  • BuildSchemaXml method – BizTalk is extra-picky about namespaces in your xml. As it should be. In order to serialize our populated schema classes properly to put the message in MSMQ, we found the following approach very VERY helpful when turning the schema class into an XML string to be pushed to MSMQ.

/// <summary>

/// Handles the serialization of our schema classes to the underlying xml text for transmission to BizTalk

/// We use this to modify a couple of the default behaviors of the schemas with respect to serialization

/// </summary>

/// <param name=”schemaObject”>The populated schema class we wish to serialize</param>

/// <returns></returns>

public string BuildSchemaXml(Object schemaObject)

{

    StringWriter output = new StringWriter(new StringBuilder());

 

    //Create our own namespaces for the output

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

    //Add an empty namespace and empty value

    ns.Add(“”, “”);

    //Serialize the object with our own namespaces (notice the overload)

    XmlSerializer serializer = new XmlSerializer(schemaObject.GetType());

 

    //we use this to extract some of the header data we don’t want to be serialized.

    XmlWriter writer = new XmlTextWriterFormattedNoDeclaration(output);

 

    serializer.Serialize(writer, schemaObject, ns);

 

    return output.ToString();

}

 

  • XmlTextWriterFormattedNoDeclaration class: This goes along with the BuildSchemaXml serialization method to suppress all the ‘stuff’ that typically gets written into the serialized xml and helps the schemas be recognizable to BizTalk.

    /// <summary>

    /// This is a special custom override class to assist with the formatting of the serialized xml going to BizTalk

    /// Specifically, to eliminate header/namespace overhead in the message body.

    /// </summary>

    public class XmlTextWriterFormattedNoDeclaration : System.Xml.XmlTextWriter

    {

        /// <summary>

        /// Constructor

        /// </summary>

        /// <param name=”w”></param>

        public XmlTextWriterFormattedNoDeclaration(System.IO.TextWriter w)

            : base(w)

        {

            Formatting = System.Xml.Formatting.Indented;

        }

 

        /// <summary>

        /// Do Nothing (instead of the default behavior)

        /// </summary>

        public override void WriteStartDocument() { } // suppress

    }

 

  • SendToBizTalk method (MSMQ-based) – this is what pushes the serialized xml generated from our populated schema class into a message and drops it into a monitored MSMQ queue, where BizTalk can now pick it up, see it as a recognized schema, and process it accordingly within BizTalk. Don’t be frightened if you manually look at the message from within the MSMQ queue and the content appears to be a foreign language, that is a side effect of BodyType = 8, but that’s what we had to do in order to make things align.

void sendToBizTalk(string serializedXml)

{

   try

   {

       //declare a new message queue object pointing to our configured queue

       MessageQueue crmBTMQ = new MessageQueue(QueuePath);

 

       //since we are writing our own message content, we need to use a message

       Message crmXmlMessage = new Message();

 

       //to avoid re-formatting our nice xml message, we write directly to the bodystream of the message

       crmXmlMessage.BodyStream = new MemoryStream(Encoding.UTF8.GetBytes(serializedXml));

 

       //and tell the message it’s content is a string

       crmXmlMessage.BodyType = 8;

 

       //now send the message to the configured queue where biztalk will soon go and grab it.

       crmBTMQ.Send(crmXmlMessage);

 

                …

I know this may seem woefully inadequate, but hopefully it will help point someone in the right direction and avoid some of the issues that we had to work through the first time.

Leave a Reply

Your email address will not be published. Required fields are marked *


× four = 28

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>