September 2010 - Posts

In my previous blog about consuming WCF service from BizTalk orchestration I wrote about how we’d invoke a service based on a document coming in and mapping it into the service request schema.

This time I had the input for the service coming from a context, and not necessarily from the document itself, and needed to be able to perform same service invocation, yet constructing request document dynamically with-in the orchestration. To simplify the process, I still pass in a document, and distinguish a field with the value I want to pass into the service. This way I don’t actually have to waste time on property promotion. The key here is to invoke a custom .NET component (GAC-ed singleton) to construct the message with the value(s) coming from the original message context.

image

Where the code is quite simple – invoke singleton with the required value(s):

System.Diagnostics.Trace.WriteLine("Invoking factory.");
toServiceMsg = MessageFactory.RequestMessageFactory.CreateProcessMessage(originalMsg.Value);
System.Diagnostics.Trace.WriteLine("Done invoking factory.");

The interesting part is the CreateProcessMessage method itself. The message I am generating is of schema Process (service incoming schema, ProcessResponse is outgoing schema). I couldn’t use XLANGMessage since it’s an abstract class. Therefore needed something to allow BizTalk message construction. This is where I ran into this great blog post describing some of the options. I tried to look up more info, but honestly, this part of BizTalk is so badly documented IMO, that couldn’t get a lot. Not to mention that there’s no intellisense on these things… Anyways, this is what the method does:

namespace MessageFactory
{
	public static class RequestMessageFactory
	{
		private const string Namespace = "http://tempuri.org/";

		public static XLANGMessage CreateProcessMessage(int value)
		{
			var message = new GeneralMessage("Process");
			var memoryStream = new MemoryStream();
			using (var writer = XmlWriter.Create(memoryStream))
			{
				writer.WriteStartDocument();
				writer.WriteStartElement("Process", Namespace);
				writer.WriteStartElement("value", Namespace);
				writer.WriteString(value.ToString());
				writer.WriteEndElement();
				writer.WriteEndElement();
			}
			memoryStream.Seek(0, SeekOrigin.Begin);

			message[0].LoadFrom(memoryStream);
			return message.GetMessageWrapperForUserCode();
		}
	}

	[Serializable]
	public sealed class GeneralMessage : BTXMessage
	{
		public GeneralMessage(string messageName) 
			: this (messageName, Service.RootService.XlangStore.OwningContext)
		{}

		private GeneralMessage(string messageName, Context owningContext) 
			: base(messageName, owningContext)
		{
			owningContext.RefMessage(this);
			AddAnyPart("Body");
		}
	}

}

A lot of magic IMO. I wish Microsoft would provide a bit more on the subject, such as what Service.RootService.XlangStore.OwningContex is and why we need to Ref-a-Message (guessing is not knowing!).

Another “smell” is that now the factory (custom .NET component) had to be aware of the contract without being connected to the schema file itself or any visible link. So whenever the contract is changing, factory has to reflect that change. The only way I can capture that is a test that would generate the message and try to validate it against the schema.

Any thoughts on the subject? Don’t be shy.

Today Developer Edition for BT2010 was announced. Great news for anyone who does BT development/testing.

image

Wise move, IMO.

Sometimes trivial things in .NET are not so trivial in the BizTalk world. Especially for standard .NET developers with the mindset for routine .NET development. Recently, I was asked to give a hand with a simple task that was surprisingly taking too long (and good that was asked for, why to waste time if you can leverage someone to give a hand – always something I resort to). On the web, there are plenty of resources, yet nothing emphasizes the little things that are obvious to somewhat experienced BizTalk-ers and is brand new to mature .NET developers. Lets dive into example.

Lets say we have a business process that requires to involve a WCF service during a message processing, taking a piece of data from the message as a parameter for the service, and working with the returned value.

image

In a standard .NET project we’d define the contract (ISomeService)and implement the service (SomeService), testing that it adheres to the desired behavior. 

[ServiceContract]
public interface ISomeService
{
[OperationContract]
string Process(int value);
}

public class SomeService : ISomeService
{
public string Process(int value)
{
return string.Format("Processed: {0}", value);
}
}

Now the interesting part. To reference a service from a BizTalk project, the simplest way is to point to the service instance running somewhere. This is similar to generating a service reference for a regular .NET project, except that service configuration is stored not in (.NET traditional) configuration file, but in a binding file, typical to BizTalk. The key is to “just generate” this binding, and tweak it later for desired purposes.

The easiest way to get the service running, is to create a simple self-hosting console application (no need in IIS or windows service).

 

static void Main(string[] args)
{
using (var serviceHost = new ServiceHost(typeof(SomeService)))
{
serviceHost.Open();

Console.WriteLine("Running service (press ESC to finish).");

while(true)
{
if (!Console.KeyAvailable)
continue;

var pressedKey = Console.ReadKey(true);
if (pressedKey.Key == ConsoleKey.Escape)
break;
}

serviceHost.Close();
Console.WriteLine("Service finished.");
}
}

Again, how service is exposed in self-hosted console runner is not important, the generated binding file (once service is referenced from BizTalk application) can be changes as desired. For simplicity, I hosted it with basic HTTP binding and enabled MEX.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="SomeService.SomeService" behaviorConfiguration="SomeService.SomeServiceBehavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost/SomeService" />
</baseAddresses>
</host>
<endpoint address ="" binding="basicHttpBinding" contract="SomeService.ISomeService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SomeService.SomeServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

From BizTalk project, added Generated Item –> Consume WCF Service, used self-hosted service URL (http://localhost/SomeService). Just before hitting the Next button, don’t forget to run the self-hosted service runner.

Once service is referenced, there are a few items that are auto-generated. The important ones are:

  • SomeService_tempuri_org.xsd
  • SomeService_BindingInfo.xml

The schema file contains all the schemas for arguments and return type schemas for all the service operations exposed by service. Since SomeService exposes a single operation with arguments coming in and return values, these are the generated schemas:

image Since the name of the operation is Process, arguments and return schemas use the name. Returned type is string, yet in order to work with the value in orchestration, I recommend to make it a distinguished field.

Next step is to define a map, that would take the message we process and map into the message of a type that Process operation accepts (can be constructed from a scratch, but mapping is easier, cleaner, and easily testable).

image

Once in place, we can finalize the orchestration

image

Trace just to ensure that the service is executed as expected.

 

System.Diagnostics.Trace.WriteLine(System.DateTime.Now.ToString());    
System.Diagnostics.Trace.WriteLine(msgFromService.parameters.ProcessResult);

 

 

Deploying and executing this process results in the next output for the given input of 123:

<ns0:Message xmlns:ns0="http://InvokerApp">
<Value>123</Value>
</ns0:Message>

image

The console runner has to be there for the time of BizTalk application execution since the binding file (that is supposed to be deployed into BizTalk along with the BT Application) contains information about that service configuration. Quick review of the binding information shows that it’s just a service configuration, and should be re-written to meet the real service configuration.

<?xml version="1.0" encoding="utf-8"?>
<BindingInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Assembly="Microsoft.BizTalk.Adapter.Wcf.Consuming, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Version="3.5.1.0">
<Timestamp>2010-09-20T09:53:57.2895-06:00</Timestamp>
<SendPortCollection>
<SendPort Name="WcfSendPort_SomeService_BasicHttpBinding_ISomeService" IsStatic="true" IsTwoWay="true" BindingOption="0">
<Description>service "SomeService" port "BasicHttpBinding_ISomeService"</Description>
<TransmitPipeline Name="Microsoft.BizTalk.DefaultPipelines.PassThruTransmit" FullyQualifiedName="Microsoft.BizTalk.DefaultPipelines.PassThruTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Type="2" />
<PrimaryTransport>
<Address>http://localhost/SomeService</Address>
<TransportType Name="WCF-BasicHttp" Capabilities="899" ConfigurationClsid="467c1a52-373f-4f09-9008-27af6b985f14" />
<TransportTypeData>&lt;CustomProps&gt;
&lt;MaxReceivedMessageSize vt="3"&gt;65536&lt;/MaxReceivedMessageSize&gt;
&lt;MessageEncoding vt="8"&gt;Text&lt;/MessageEncoding&gt;
&lt;TextEncoding vt="8"&gt;utf-8&lt;/TextEncoding&gt;
&lt;SecurityMode vt="8"&gt;None&lt;/SecurityMode&gt;
&lt;MessageClientCredentialType vt="8"&gt;UserName&lt;/MessageClientCredentialType&gt;
&lt;AlgorithmSuite vt="8"&gt;Basic256&lt;/AlgorithmSuite&gt;
&lt;TransportClientCredentialType vt="8"&gt;None&lt;/TransportClientCredentialType&gt;
&lt;UseSSO vt="11"&gt;0&lt;/UseSSO&gt;
&lt;ProxyToUse vt="8"&gt;Default&lt;/ProxyToUse&gt;
&lt;StaticAction vt="8"&gt;&amp;lt;BtsActionMapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&amp;gt;
&amp;lt;Operation Name="Process" Action="http://tempuri.org/ISomeService/Process" /&amp;gt;
&amp;lt;/BtsActionMapping&amp;gt;&lt;/StaticAction&gt;
&lt;InboundBodyLocation vt="8"&gt;UseBodyElement&lt;/InboundBodyLocation&gt;
&lt;InboundNodeEncoding vt="8"&gt;Xml&lt;/InboundNodeEncoding&gt;
&lt;OutboundBodyLocation vt="8"&gt;UseBodyElement&lt;/OutboundBodyLocation&gt;
&lt;OutboundXmlTemplate vt="8"&gt;&amp;lt;bts-msg-body xmlns="http://www.microsoft.com/schemas/bts2007" encoding="xml"/&amp;gt;&lt;/OutboundXmlTemplate&gt;
&lt;PropagateFaultMessage vt="11"&gt;-1&lt;/PropagateFaultMessage&gt;
&lt;OpenTimeout vt="8"&gt;00:01:00&lt;/OpenTimeout&gt;
&lt;SendTimeout vt="8"&gt;00:01:00&lt;/SendTimeout&gt;
&lt;CloseTimeout vt="8"&gt;00:01:00&lt;/CloseTimeout&gt;
&lt;/CustomProps&gt;</TransportTypeData>
<RetryCount>3</RetryCount>
<RetryInterval>5</RetryInterval>
<ServiceWindowEnabled>false</ServiceWindowEnabled>
<FromTime>2000-01-01T00:00:00</FromTime>
<ToTime>2000-01-01T23:59:59</ToTime>
<Primary>true</Primary>
<OrderedDelivery>false</OrderedDelivery>
<DeliveryNotification>1</DeliveryNotification>
<SendHandler xsi:nil="true" />
</PrimaryTransport>
<ReceivePipeline Name="Microsoft.BizTalk.DefaultPipelines.XMLReceive" FullyQualifiedName="Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Type="1" />
<ReceivePipelineData xsi:nil="true" />
<Tracking>0</Tracking>
<Filter />
<OrderedDelivery>false</OrderedDelivery>
<Priority>5</Priority>
<StopSendingOnFailure>false</StopSendingOnFailure>
<RouteFailedMessage>false</RouteFailedMessage>
<ApplicationName xsi:nil="true" />
</SendPort>
</SendPortCollection>
</BindingInfo>

Behind the scenes, BizTalk generates a proxy that is getting deployed along with the BizTalk application. I wish ChannelFactory option would be available with BizTalk as well, so that the contract is enough to spin of a dynamic service proxy. On the flip side, having BizTalk to generate all the schemas is very handy.

  is attached.

I really like the concept. Wish Hudson build server would have this option…

JetBrains has implemented the idea with TeamCity.

image image

AOP

I am looking at the code for Silverlight application and there’s something that just bugs me… INotifyPropertyChanged. This is not the first time, and yet again I see this interface implemented again, and again, and again. This violates several good principles (Single Responsibility and Duplicated Code). It also pollutes the code with cross cutting concerns (change notification). My choice of solution for this is simple – buy, do not build. Yes, it is possible to write a base class that would scan for a custom attribute and will do the wiring. But why? Why not to look into something like PostSharp and take advantage of the hard work the author(s) put into it to make it work.

For myself a lot of times it was the pride – how come I will buy something that I can build myself. Well, satisfy the ego on a spike, and move on. AOP should solve problems, not introduce new ones. Understanding is important, and I will provide a simple example how AOP for simple tracing can be done. But the goal of the post is to encourage people to use dedicated tools to solve business problems, and not pride issues.

How AOP works? Poor mans’ explanation – IL re-write. Post-processing of the generated IL code. Let’s say I have a code that looks like this:

public sealed class Greeting
{
  public string SayHello()
  {
    Console.WriteLine("Inside Greeting::SayHello() method");
    return "Hello";
  }
}

I would like to trace each time the method SayHello is invoked (when we enter and about to leave it). The original MSIL looks like the following:

0000:   nop
0001:   ldstr   Inside Greeting::SayHello() method
0006:   call    System.Void System.Console::WriteLine(System.String)
000B:   nop
000C:   ldstr   Hello
0011:   stloc.0
0012:   br.s    0014
0014:   ldloc.0
0015:   ret

By using reflection (in my case I used Mono.Cecil) the original code is re-written into this:

0000:   ldstr   [TRACE] Started SayHello
0005:   call    System.Void System.Console::WriteLine(System.String)
000A:   nop
000B:   ldstr   Inside Greeting::SayHello() method
0010:   call    System.Void System.Console::WriteLine(System.String)
0015:   nop
0016:   ldstr   Hello
001B:   stloc.0
001C:   br.s    001E
001E:   ldloc.0
001F:   ldstr   [TRACE] Finished SayHello
0024:   call    System.Void System.Console::WriteLine(System.String)
0029:   ret

Which is affectively equivalent to the following C# code:

 

public sealed class Greeting
{
  public string SayHello()
  {
    Console.WriteLine("[TRACE] Started SayHello");
    Console.WriteLine("Inside Greeting::SayHello() method");
    Console.WriteLine("[TRACE] Finished SayHello");
    return "Hello";
  }
}

The output:

[TRACE] Started SayHello
Inside Greeting::SayHello() method
[TRACE] Finished SayHello

 

The quick and dirty code to re-write the original assembly:

var var assembly = AssemblyFactory.GetAssembly(assemblyFilename);
var type = assembly.MainModule.Types["Library.Greeting"];
var method = type.Methods.OfType<MethodDefinition>()
                           .Where(x => x.Name.Equals("SayHello") && x.Parameters.Count.Equals(0))
                           .Single();

var worker = method.Body.CilWorker;
var trace = worker.Create(OpCodes.Ldstr, "[TRACE] Started " + method.Name);
var writeLineMethod = assembly.MainModule.Import(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
worker.InsertBefore(method.Body.Instructions[0], trace);
worker.InsertAfter(trace, worker.Create(OpCodes.Call, writeLineMethod));

trace = worker.Create(OpCodes.Ldstr, "[TRACE] Finished " + method.Name);
worker.InsertAfter(method.Body.Instructions[method.Body.Instructions.Count - 2], trace);
worker.InsertAfter(trace, worker.Create(OpCodes.Call, writeLineMethod));

AssemblyFactory.SaveAssembly(assembly, assemblyFilename);

This is all great, but the true value in leveraging the tools created for this purpose to get the real value – resolve problems unique to your business efficiently. AOP is your friend, leverage it.

For most of our projects we use StructureMap as a Container. Silverlight seems to change this a little. From preliminary review looks like StructureMap is not yet ready for Silverlight, so we started to look into a different container. The one that looked good was Ninject. Simple, straight forward, and elegant.

Binding module defines components:

public class BindingModule : NinjectModule
{
  public override void Load()
  {
    Bind<IPrinter>().To<ConsolePrinter>();
    Bind<IFooter>().To<Footer>();
    Bind<IHeader>().To<Header>();
  }
}

(there are ways to define some complex scenarios).

Kernel can load binding module(s) by scanning one or more assemblies:

var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());

Ninject has a few extension projects. Among those one that allows scanning with conventions.

What do I miss from StructureMap? That probably would be the ObjectFactory singleton. Not a biggie, and can be implemented, but very convenient to have it in place from the beginning.

And what are you using as a container for Silverlight?

I am getting involved in another project, that looks like has its own testing challenges (last project I was involved was a BizTalk based project, quite a few testing challenges!).

What have I seen so far with Silverlight (version 4.0):

  1. TDD with the toolset we always utilized is no longer possible (Gallio, TestDriven.NET, NCover) partially due to the nature of Silverlight, partially because of the tools support that is not yet in place
  2. MVVM pattern – developers wrapping around the idea
  3. Explosion of Microsoft technologies that are just “out of college” and not yet applicable in TDD case
  4. Limited resources on .NET code detours (I only encountered Moles and TypeMock, but for commercial Silverlight product both are commercial)
  5. Natural limitations of Silverlight (sandbox, static DependencyObject properties, inheritance from the system)

Looks like this is going to be an interesting journey. Feel free to share your experiences and findings.

More Posts