Sunday, May 24, 2009

What good is the BAM WCF Interceptor???

A colleague and I were discussing the difference between BizTalk default BAM interceptors and the WCF/WF BAM interceptors. The question came up as to what specifically can theBAM WCF provide that the default Pipeline interceptors can't.

Well I will first start with the overall purpose. The purpose of the BAM WCF Interceptor is to allow WCF Services and WCF Clients to take advantage of the BAM infrastructure. WCF Services and Clients can update BAM Checkpoints (KPI’s) for an already deployed BAM Activity Definition. It essentially can record the same data as the Receive and Send Ports of the BizTalk BAM Tracking profile. However, there are a few additions to the WCF Interceptors that the Receive and Send Ports cannot accomplish. For example, the WCF interceptor can record Client and Service Faults, Channel Faults and other conditions that can occur within the WCF Channel layer. Also, the WCF Interceptor can use XPath to navigate the message and parameters, to record plethora of aggregated values such as getting a “Sum”, “Avg”, “Min”, “Max”, or “Count” of repeating items. Any valid xpath expression can be used with the only limitation being that if an Xpath returns multiple nodes, only the first node out of the collection is used.

Wednesday, May 20, 2009

Tales from the Developers Crypt:
(Another one of those postings that never made it from about a year ago...)

Hosting XAML only workflows services in ASP.NET

Recently I was tasked with building a lab that showed how to build a XAML only based WCF service and host it inside of ASP.NET for the purpose of following the SOA pillar of service composition, and agility. I always taught that this could be done; quite frankly I have even heard various colleagues say this could be done. However I never actually saw it implemented, thus the reasoning for this blog. Below I describe the pains and glories of hosting declarative marked-up Xaml based workflows. My intention is that you read through this simple check list in hopes that you won’t run into any ‘gotchas’ when you implement this. So happy workflowin!!!

The easiest way to pass in a Xaml file is to use the WorkflowServicehostFactory inside a ASP.NET “.svc” file. All you have to do is apply the “service=”Filename.xoml” attribute and away you go… Well almost.
Depending on your XOML, you may need to include TypeProviders, something that can’t be done simply pointing to a XOML file, thus using this approach I was blocked. To solve this issue, I had to create my own XamlWFHostFactory class by simply deriving from the WorkflowServiceHostFactory class and overriding the CreateServiceHost method with code such as this:
public class XamlWFHostFactory : WorkflowServiceHostFactory
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{

TypeProvider typeProv = new TypeProvider(System.Web.HttpContext.Current);
typeProv.AddAssembly(System.Reflection.Assembly.GetExecutingAssembly());
typeProv.AddAssemblyReference("MovieFlowService.dll");

}
}
Once I had my typeProviders, any custom code behind or references to classes that exist inside other .Net assemblies can be resolved. However I didn’t come to this conclusion right away.

Simply passing in a XOML file caused all kinds of errors, however I only saw one inside the browser when testing the WF/Service was XAML validation failed. Now prior to trying the host the XOML file inside the WorkflowServiceHostFactory, my workflow ran fine with a custom windows form based host. I just knew that the XOML file was fine and that the validation was a generic error.
So I said, this is no problem, I’ll just listen for the WF validation errors and write them out to an ASP.NET Trace. What I learned immediately for debugging is that there is no way to get the validation errors on the WorkflowServiceHostFactory, because the error events are caught by the internal WorkflowServiceHost that the factory creates by default. The default host isn’t bubbling up the events to the WorkflowServiceHostFactory where my Event handling code is listening thus I had to create my own WFHost. This was done easily enough by creating a class that derives from the WorkflowServiceHost and overrind the InitializeRuntime to listen for the WorkflowValidation errors:
Public class XamlWFHost : WorkflowServiceHost
{
public XamlWFHost(string wfPath, string rulesPath, ITypeProvider provider, Uri[] baseaddresses ): base (wfPath, rulesPath, provider, baseaddresses )
{ }

protected override void InitializeRuntime()
{
try
{
// HttpContext.Current.Trace.Warn("Trace is good- InitializeRuntime()");
base.InitializeRuntime();
}
catch (WorkflowValidationFailedException ex)
{

StringBuilder errors = new StringBuilder();
foreach (System.Workflow.ComponentModel.Compiler.ValidationError error in ex.Errors)
{
errors.AppendLine(error.ToString());
}
string errMsg = "Validation Errors: " + errors.ToString();
Debug.WriteLine(errMsg);
System.Web.HttpContext.Current.Trace.Write(errMsg);
}
}
In the overriden InitializeRuntime() method and catch the ValidationErrors here because they are not caught by default within your HostFactory. Also if something goes wrong with your WCF ServiceHost, like your channel faults for some reason it’s also not a bad idea to listen for the HostFaulted event as well. From WCF I’ve learned that when you set a break point inside the Faulted event method, you can see all the exceptions that have occurred from WCF's perspective.
Something else to note, when trying to write out Trace statements to the ASP.NET Trace context, found inside the HttpContext, it was null. The reason being was that WCF was not turned on to support ASP.NET compatibility, nor was the web configuration enabled to support this. This is equivalent to turning on all the ASP.Net intrinsic such as tracing, Request, Response, Sessions state and etc. You don’t need to turn on ASP.Net compatibility to use WorkflowServices, in my case I wanted to write out details simply out to the Browser using the TraceContext inside of ASP.NET.
To use the System.Web.HttpContext. we must specify in WCF to use the ASP.NET compatibility which posed another problem. The ASP.Net compatibility is enabled using a ServiceBehavior. Well first off, how do I get to the ServiceHost, after all this is a WorkflowServiceHost not simply a WCF ServiceHost.
Well that’s the answer, the WorkflowServiceHost allows you to access the description and ServiceEndpoints as if you’re working with the ServiceHost class yourself. In fact the workflow service host derives from the ServiceHostBase class. So just add the behaviors you’d like. Also if you wanted to access the workflow runtime, as long as you’ve configured a behavior for it such as within the configuration file upon startup:






You can access it inside of code such as this:

WorkflowRuntimeBehavior wfrBehavior =
wfSvcHost.Description.Behaviors.Find();
WorkflowRuntime wfr = wfrbehavior.WorkflowRuntime;

So going back to the ASP.NET compatibility issue, we can add this behavior through the ASPNetCompatibility attribute inside code such as this code here:
AspNetCompatibilityRequirementsAttribute behavior = new AspNetCompatibilityRequirementsAttribute();
behavior.RequirementsMode = AspNetCompatibilityRequirementsMode.Required ;
wfSvcHost.Description.Behaviors.Add(behavior);
As I was going through my code, I also noticed that in order to use the TypeProvider classes, I needed to pass in either null, or a class that implements the IServiceProvider interface. It just so happens the the System.Web.HttpContext actually implements this interface.
Some last pointers about hosting XOML Inside an ASP.NET workflowServiceHost, I had several problems when using Root names inside the XOML that contained some combination of NS.Class as the root node name. I also found that in order to get it to work properly, the Root node name inside the XOML file had to match the name of Root Activity, and the namespace prefix matched namespace within XmlDefinitionsAttribute inside the Host project assemblyinfo.cs file.


Inside you Hosting project inside the AssemblyInfo.cs file make sure that the ns0: prefix matches within the assemblyInfo XmlnsDefintion attribute:
[assembly: System.Workflow.ComponentModel.Serialization.XmlnsDefinition("clr-namespace:MovieFlowService", "MovieFlowService")]
Also note: that when using a custom host, I can leave off the Assembly part, while here inside the workflow service host, this didn't work when I left off the Assembly=... part off.
Another issue I ran into was that if you build the WF using the VS.NET WF designer with XAML separation, verify that within the WF Service Properties page you change the NameSpace.ServiceName to simply ServiceName, which should match the Xaml Root node name. Also make sure that this Servicename, and Xaml Root name all match the ServiceName inside the web.config for the WCF Service Model configuration.
Finally after all this was done, I came across another simple but really good and appreciated error, ASP.Net didn’t have permissions to read my XOML file from the disk. After adding the proper permissions, restarting the IIS App Pool and IIS respectively, VIOLA!!!! My XAML only workflow hosted within WCF through ASP.Net and the workflowServiceHostFactory.
How The BizTalk WCF Send Adapter works under the hood.

This posting is a follow up to the WCF Receive Adapter article posted last year. (Sorry it took so long, I wrote it at the same time of the Receive adapter article however it was never posted...)

The WCF Adapter can send messages to a WCF Service, effectively making the WCF Send Adapter a client or "Proxy" that can communicate with WCF Dispatchers “services”.

Normally in a WCF Client - Server solution, a client, or "Proxy" must match the Endpoint configuration for a Service. This means that the client must have an address, binding and contract that match the service. The client must use the same binding that the service expects. The same binding means that the client must use the same binding elements such as Security options, transactions, reliable sessions, and etc. The client must also match the same encoder-formatter and transport.

Client applications such as windows forms applications and asp.net web sites, can easily use the Add service reference utility that comes with the .Net 3.5 framework SDK. When using this utility, a proxy class is generated where a developer can simply include this auto-generated proxy class inside their solution. The WCF Send Adapter supports something similar. The WCF Send Adapter can import a WCF Configuration from a app.config-web.config file. The way to get a hold of this file is to use the SvcUtil.exe tool (Add Service Reference) and generate a proxy like normal, and uses the App.config-web.config that is generated from this tool. The way in which you use this configuration is to simply import the configuration using a WCF-Custom adapter. When you import the configuration file, the WCF creates a WCF Send Adapter configuration that matches what the Dispathcing Service expects.

But what happens to the contract attributes, such as the operation attributes like IsOneWay, TransactionFlow, and etc. These are not inside the configuration file, they are declared as attributes inside the service contract, and these must match too?

Alas, the WCF Send Adapter uses the binging configuration and options specified in each binding element to infer which attributes need to be applied to a generic contract.

The WCF Send adapters uses 2 generic service contracts- IOutputChannel, and IRequestChannel. These two interfaces are not actually marked up with the [ServiceContract] attribute however the WCF Framework at a very low level uses these interfaces to send messages. The difference between these two interfaces is simply IOutputChannel is used for One Way operations, while IRequestChannel is used for two way operations. Thus if you need to send a message and wait for a return acknowledgement from the service, the IRequestChannel will be used. This is the default for WCF Send adapters because BizTalk needs confirmation as to when to delete the message from the MessageBox DB. One way operations, a special case within BizTalk, would be used with transports such as the net.msmq bindings, where the underlying transport can send back a control message acknowledging its receipt. This control message is internal within the protocol, effectively keeping the pattern “One Way”, even though technically it’s not. Another point to add here with one way operations, WCF Send adapters do not support a Service whose contract specifies “IsOneWay=true”. The reason is quite simple, the BizTalk adapter framework needs to transactionally “commit” if the message is successfully send. Services marked with “IsOneWay=true” operations do not yield a way to determine this. No control message is sent back, thus the WCF Send adapter doesn’t support this option.

When these channels-contracts are being created, the binding configration is taken and read from SSO DB and the various attributes are dynamically added to the descriptions of either Operations or message contracts.

What's important to overstand here is that in a normal client application the client would match the contract by either sharing the service contract, or making a contract that is effectively wire compatible. Wire compatible simply means that any option can set, as long as the final output of the message contains all the appropiate elements and attributes that the Dispather can successfully process. Because the WCF Send adapters infer these settings from your configuration of a WCF Send Adapter, there is no room for error, the slightest property that is set incorrectly will cause the WCF send adapter to not successfully send data to a WCF Service. For example, just recently a colleague was trying to flow transactions across to a WCF service which was configured to NotAllow transactions to flow into it. Techinically this means that there should be no OLE or WSAT header propogating any transaction ID. The application was first tested using a Windows Client application. Within the Windows application, a transaction scope was created, and the binding used had transactions being flowed. The client proxy was sharing the Service contract of the service which specified that TransactionFlow set to NotAllowed. The Default behavior of the windows proxy client was to strip off the OLE-WSAT header information within the message, thus making it wire compatible, even though the binding options were otherwise specified. The windows client application worked successfully because the TransactionFlow attribute specified inside the proxy class caused the proxy stripped the transaction header information before being sent.

Now let's take the above scenario with BizTalk Server's WCF Send Adapters. If you use a WCF Send Adapter, there is no place where you specify how to share a contract, nor manually create a wire compatible one. It's left up to the dynamic creation of the Send Adapter using the configuration, to create a matching contract. If a binding contained the option to flow transactions, as outlined above, the WCF Send adapter would add the appropriate TransactionFlow attribute dynamically at run time. This would cause the dynamic proxy to create the OLE/WSAT transaction headers, and send them to the service. At this point, the service would yield an exception saying that the ServiceContract specified that TransactionFlow is not allowed, while the same binding options used inside a Windows Forms application works, simply because the ServiceContract is shared. To solve this challenge, the binding should specify not to flow transactions.

To be continued…
I've just officially joined the master minds of Tellago...
http://weblogs.asp.net/gsusx/archive/2009/05/12/dwight-goins-joins-tellago.aspx

First task: DELL Technican (Those who know can laugh it off...)
Second task: The Sr. BizTalk Documenter (If you only knew...)
Third task: TBD

I want to thank everyone over at Tellago for giving me this opportunity. So let's go write some code!!!