Share via


Calling a .NET Assembly from Orchestration with Schema Types

There I was today pointing at a customer at a past blog entry on this topic – when I realized I’d never got around to posting it, Doh! Apologies for sitting on this for the last few months!

I was running some BizTalk training earlier this year and got talking about how you can pass Messages from BizTalk to a .NET component. The typical approach is to define a parameter of XLANGMessage (Which is BizTalk’s in-memory representation of a message) and you can then “natively” pass the message from BizTalk to your .NET component.

You can then “crack” that XLANGMessage inside your .NET component and retrieve the underling Message body; as with everything inside BizTalk you can do this in a few ways! Typically you don’t want to load an entire message into memory (ala XmlDocument) especially if it’s a big message, so you might opt for a streaming approach that allows you to read parts of the message in as required.

XLANGMessage allows you to choose whichever approach suits you, e.g.:

      // XMLDocument approach
      void MyDotNetMethod( XLANGMessage msg )
      {
         XmlDocument doc = msg[0].RetriveAs(typeof(XmlDocument));
      }

      // Stream approach
      void MyDotNetMethod( XLANGMessage msg )
      {
         StreamReader reader = new StreamReader( msg[0].RetriveAs(typeof(Stream) );
      }

Now this works fine – but it’s a bit clunky and means the interface to your .NET components isn’t as clean as you would like – especially if other applications are likely to consume them (XLANGMessage won’t make any sense to non BizTalk solutions).

An approach that I tend to push is using XSD.EXE to generate C#/VB.NET classes based on Schemas, for those of you not familiar with XSD.EXE it’s a command line tool shipped with Visual Studio .NET that allows you to generate Classes or Typed DataSets based on XML Schemas, normally you might try to write code to create a XML Document (based on a schema), you end up writing pages and pages of painful code to construct a XML document by using the DOM (XmlDocument).

This is very brittle because if (heaven forbid) the schema was to change your constructing code may have to change a lot, plus it’s code you just don’t need or want to write. If you instead use an XSD.EXE generated class (XSD /c yourschema.xsd) you end up with a typed C# class which is dead easy to program against, e.g.

            CustomerSchemaClass Customer = new CustomerSchemaClass();
            Customer.Name = “Darren Jefford”;
            Customer.Address = “23 Railway Cuttings”;

When you then serialize this class an XML document is created which conforms to the XML Schema automatically, if you “return” one of these class instances from say WebService this is all done from you, in other scenarios you can use the XmlSerializer to serialize the class into a stream (File, Network, etc.).

So, let’s get back to BizTalk. These XSD generated classes are great and easy for the developer to use so it would be neat if we could use them in our .NET assemblies that BizTalk is calling. Obviously this may not be suitable for large messages when you’re only interested in parts of it.

We want to get to the stage where we can natively and easily exchange messages between BizTalk and .NET in such a way that it makes life easier for the developer (cracking XMLDocuments is not fun!).

This is what we want to achieve:

            xsd.exe /c CustomerSchema.xsd

            BizTalk Code:

            Message Assignment Shape: ANewBizTalkCustomerMsg = MyDotNetComponent.DoStuff( AnExistingBizTalkCustomerMsg)

            .NET Component:

      CustomerSchemaClass DoStuff (CustomerSchemaClass c )
      {
...

      CustomerSchemaClass NewCustomerClass = new CustomerSchemaClass();

         ...

        return NewCustomerClass;
}

After playing around with this idea I managed to very easily return one of these class instances to BizTalk without any problem, e.g.:

            .NET Code: return NewCustomerClass

            BizTalk MessageAssignment Shape: BizTalkMessage = DotNetComponent.GetMessage();

This is great, however I couldn’t get BizTalk to successfully call a .NET method passing a BizTalk message to a XSD generated class type, e.g.:

            DotNetComponent.HereIsAMessage( BizTalkMessage)

This is because BizTalk doesn’t really know how to convert a BizTalk message to our serialiable class type, so can’t do an automatic cast. We end up with a halfway house, If you recall the RetrieveAs method above that allows us to get at the BizTalk message in a variety of ways – we can use this to obtain the message as our serialized class, e.g.:

           CustomerSchemaClass c = MyXLANGMessage[0].RetrieveAs(typeof(CustomerSchemaClass);

You end up still requiring the XLANGMessage parameter type but it allows the Developer to use a much nicer way to access the message, you can still of course expose a non BizTalk specific interface to allow non BizTalk code to call your component with ease:

BTSSpecificCustomerMethod( XLANGMessage msg )
{
         CustomerSchemaClass c = MyXLANGMessage[0].RetrieveAs( typeof(CustomerSchemaClass) );

         CustomerMethod(c);
      }

      CustomerMethod(CustomerSchemaClass c)
      {

      }

Hope this helps!

Comments

  • Anonymous
    September 29, 2004
    I use a slight variation of this technique for large messages: multi-part messages. You can still use XSD.exe to generate the classes and then assign the class to a message part.

  • Anonymous
    October 01, 2004
    Cool Post!

  • Anonymous
    October 16, 2004
    Darren Jefford posted last month an entry called "Calling a .NET Assembly from Orchestration with Schema Types" on his weblog,...

  • Anonymous
    June 20, 2005
    BTS Diary 1 - The pain of an unparsed interchange

  • Anonymous
    February 08, 2007
    When I attempt this I get the following error when I try to compile: Cannot implicitly convert type 'object' to 'MyObjectFromXsdDotExe'. Has anyone else got this message and found a resolution?  I figured I could have the serialized object as the input parameter like I do on a webservice but that didn't work so I'm trying to implement something like this.

  • Anonymous
    February 28, 2008
    I'm just getting my feet wet with BizTalk and XML schemas, so maybe I just don't know what I'm doing yet. But the classes generated by XSD.EXE seem very primitive.  XSD.EXE may generate serializable classes, but it drops all of the element restrictions like "maxLength" and "pattern".  It's also defining repeating elements as simple arrays, again ignoring restrictions like "maxOccurs" and "MinOccurs".  Collections would have been a little nicer than arrays. Am I mis-using XSD.EXE, or is there a better tool for generating classes from schemas?

  • Anonymous
    June 09, 2008
    PingBack from http://jacobblogroll.45x.com/xlangmessageretrieveas.html

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/322323-referencing-schemas-as-c-classes

  • Anonymous
    August 20, 2010
    I have a schema Customer and half part of it has been "imported" from another schema "Address". When I use, xsd.exe /c Customer.xsd.. it gives me an error that the Address part is not defined. Any resolutions??