News

My Stats

  • Posts - 26
  • Comments - 25
  • Trackbacks - 55

Twitter










Recent Comments


Recent Posts


Archives


Post Categories


June 2009 Entries

BAM Typed API alternative


The previous BAM portal post reminded me of some BAM classes I re-use but never blogged about...
 
Here is my small-scale proven semi-automated alternative based on the mapper pattern and nullable fields.

The core functionality comes from a 'BAM gateway class' which is composed with a IMapper<A,B> instance, responsible for mapping strongly typed activities to an object array. This object array contains the activity property names and corresponding values just like the eventstreams likes them, ready to be writen. Here is my favorite mapper:

public class NonDefaultValuesMapper : IMapper<IActivity, object[]>

It is generic in the sense that it just checks if the activity instance properties are set or not. It also maps class' property-name to the activity field-name. The activity class of-course has to support this and use nullable fields/properties for the value typed fields.

For every activity I write a state-only class that derives from my IActivity interface (a DTO object if you like).

public class TrainWaybillActivity : IActivity
{

    const string _activityName = "TrainWaybill";

    string _activityId;

    public TrainWaybillActivity(string activityId)
    {
            this._activityId = activityId;
    }

    string FromStationName { get;set;}
    string ToStationName { get;set;}

    DateTime? Start { get;set;}
    DateTime? Sent { get;set;}
    DateTime? Approved { get;set;}
    DateTime? Denied { get;set;}
    DateTime? Ready { get;set;}

}

A gateway class (per activity) contains specific methods which cover all activity interaction necessary and that all BAM clients must use.

Some of the gateway methods are intended for orchestration and accept a class based message parameter (created with xsd.exe, for XmlSerializer).


class TrainWaybillActivityGateway
{
    public readonly string _activityID;    
    IActivityWriter _writer;
    private IMapper<TrainWaybillActivity, object[]> _fieldMapper;
    private IMapper<IFTTOI, TrainWaybillActivity> _mapperIFTTOI;
    private IMapper<APERMS, TrainWaybillActivity> _mapperAPERMS;

    public void Start(IFTTOI waybill) {}

    public void WaybillSent() {}

    public void SetAcknowledged(APERMS acknowledgment)
}

This way messages can be passed in and be used to extract activity field values.
I again use the mapper pattern for transforming messages to activities (such as IMapper<APERMS, TrainWaybillActivity>).

I also wanted the gateway classes to be universally usable: from orchestration, pipelines as well as from custom code.
Therefore BizTalk has different evenstream classes with different behavior targeting different scenarios.
Unfortunately they do not all derive from a common base EventStream interface so in order to make the gateway universal I had to create a custom 'IEventStream' interface. I had to create these 2 adapters:

The OrchestrationEventStreamAdapter delegates calls to the BizTalk static OrchestrationEventStream methods.
The EventStreamAdapter is composed with a BizTalk EventStream instance and delegates all calls to this instance.

The OrchestrationEventStreamAdapter has an empty Flush() implementation. It also throws an exception when  StoreCustomEvent is called. I could have removed this method from the interface (especially because I have no clue why anybody would want to use it). From MSDN documentation I learned that custom events are objects of type DelayedSpCall: A serialized stored-procedure call, which is just a form of a serialized command-object, queued for later execution (by the event bus in this case). Anybody??
 
This approach was used on several small-scaled BAM projects (well, large projects with small BAM requirements).
I am not sure if things have moved on since the GenerateTypedBAMAPI xsl based code generator.
Maybe I should make a generator too?

All feedback is welcome.
If the picture is not totally clear: here is some code.

posted @ Tuesday, June 23, 2009 10:31 AM | Feedback (0) | Filed Under [ BizTalk - EAI - B2B ]


Configuring a Static WCF Port to Behave as a Dynamic Port


Yesterday I've tried to reproduce the scenario 'Configuring a Static Port to Behave as a Dynamic Port' from the excellent MSDN article 'Consuming and Hosting WCF Services with Custom Bindings in BizTalk Server' but with a twist: instead of writing the BTS.OutboundTransportLocation context property inside a custom pipeline component I've tried doing this from inside orchestration.

It didn't work. I had to do it differently. Let me explain...

If you manually promote a custom value for the BTS.OutboundTransportLocation on your outgoing message inside an orchestration message construct and send the message to a static send port, the BTS.OutboundTransportLocation property is magically overwritten with the address from the statically configured send port. The fact that this property is automatically set by the engine seems logical because it is necesarry for a regular static send. I only hoped it wouldn't be overriden when already present. 
Why magically? Because it doesn't show up like that in HAT! If you look into HAT the message-context 'before pipeline execution' you can see that the custom value is there: it was successfully written to the context inside the orchestration.
But by adding some traces to a dummy pipeline component I can CONFIRM that those custom values are indeed already erased and reset to the address from the send port configuration @pipeline-execution. This indicates that there is an additional step after tracking and before the adapter triggers the pipeline execution, where the engine adds all sorts of properties from the port configuration. So e
ven when you are using a passthru send pipeline the message 'after pipeline execution' has a different context then 'before pipeline execution'. Another clear case of opacity ;-) And that's where my confusion came from. One might wonder why they didn't choose to track the 'before pipeline execution' right after the engine added its properties. There is probably a good reason for that...

Anyway, I needed to take a step back and reconsider the approach from the article ie setting the value inside a pipeline component. But hardcoding or configuring an address inside a pipeline isn't really 'dynamic'.

So here is the final piece of the puzzle:

Roll in your own 'address' property that is written on the message context inside orchestration and is re-written into the BTS.OutboundTransportLocation property during pipeline execution.

posted @ Tuesday, June 16, 2009 4:26 AM | Feedback (0) | Filed Under [ BizTalk - EAI - B2B ]