Darren Jefford

Principal Consultant, Application Development Consulting, Microsoft UK

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!

Published Wednesday, September 29, 2004 6:24 AM by darrenj

Filed under: BizTalk 2004

Source: Darren Jefford : Calling a .NET Assembly from Orchestration with Schema Types

posted on 2007-04-07 22:00  Joey Liang  阅读(953)  评论(0编辑  收藏  举报