Archive

Archive for the ‘BizTalk’ Category

RESTifing BizTalk – Part I

August 9, 2011 Leave a comment

Recently, I and Leandro Diaz Guerra had a chance to teach BizTalk speak REST. With introduction of the webHttpBinding, this, previously challenging task, has become much easier. However, the communication over HTTP stack doesn’t make it RESTful. REST is an architectural style that requires careful design of resources, resource navigation and their relations. Translating a trivial BizTalk’s de-batching task into RESTful terms will make the “Batch” a parent resource of the individual messages with following addressable schema:

The information in curly braces represents dynamic parameters which creates a challenge for BizTalk WCF port configuration. The solution to this problem was to modify WebManualAddressingBehavior.cs  WCF custom extensions very well described in Leandro’s blog here. But first, a little bit about of the BizTalk’s process, discipline and Uri template to model REST resources.

By the time the batch picked up by BizTalk process the batch resource already exist with unique {InterchangeId}. The batch gets de-batch within a receive pipeline and produces bunch of messages with unique {MessageId}and the same {InterchangeId}. The Send port , pickups these messages and calls external RESTFul service. It is also solely responsible for building HTTP header, define payload, injecting values into the dynamic resource Uri template and make a POST call. There are three places within Send Port configuration where you could specify URI template:

  • Address (URI) on general tab
  • SOAP action header

image

  • Defining ManualAddress property of the WebManualAddressing custom WCF extension

image

The rules of thumb I use are following:

  • use Address URI only to specify service endpoint. In our case it always will be http://host/batches
  • Use SOAP action header to specify location of resource, reserving WebManualAddress property to override SOAP action header in some rare cases.

Here is a summary of logical changes I need to make within WebManualAddress behavior:

  • Check if WebManualAddress property is defined and if not get it from SOAP action
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
     try
       {
        if (String.IsNullOrWhiteSpace(ManualAddress.OriginalString))
         {
          this.ManualAddress = new Uri(request.Headers.Action);
         }
       request.Headers.To = new Uri(ApplyManualAddressMacro(ManualAddress.OriginalString
                                    , request.Properties));
        }
      catch (Exception ex)
          {
            Debug.Write(ex.Message, AppDomain.CurrentDomain.FriendlyName);
          }
      return request;
     }
  • Substitute dynamic parameter with their values 
    private string ApplyManualAddressMacro (string manualAddress, 
                                            MessageProperties messageProperties)
            {
                var uriAddress = HttpUtility.UrlDecode(manualAddress);
                const string regexExpression = @"%(\w*)%";
                try
                {
                    var regex = new Regex(regexExpression);
                    var matchCollection = regex.Matches(uriAddress);
                    for (var i = 0; i < matchCollection.Count; i++)
                    {
                        var captures = matchCollection[i].Captures;
                        foreach (var capture in captures)
                        {
                            string value = capture.ToString();
                            var replacement = GetCachedValue(value.Replace("%", "")
                                , messageProperties).Replace("{","").Replace("}","");
                            uriAddress = uriAddress.Replace(value, replacement);
                        }
                    }
                    return uriAddress;
                }
                catch (Exception ex)
                {
                    Debug.Write(ex.Message , AppDomain.CurrentDomain.FriendlyName);
                    return manualAddress;
                }
            }

The GetCachedValue is just an optimization method which caches relation between template keys %InterchangeId% retrieved from http://host/batches/%InterchangeID%  in this case   and  BizTalk fully qualified named context properties  ( namespace + name  http://schemas.microsoft.com/BizTalk/2003/system-properties/#InterchangeId). I use standard .NET Cache and store them for 10 minutes

public string GetCachedValue(string key, IEnumerable<KeyValuePair<string, object>> messageProperties)
       {
           var cache = MemoryCache.Default;
           var cacheKey = string.Format("WebManualAddressingBehavior_{0}", key);
           if (!cache.Contains(cacheKey))
           {
               var item = messageProperties.Where(p => p.Key.Contains(key)).FirstOrDefault();
               if (item.Value != null)
               {
                   cache.Set(cacheKey, item.Value, 
                       new DateTimeOffset(DateTime.Now.AddSeconds(60 * 10)));
               }else
               {
                   return key;
               }
           }
           return cache[cacheKey].ToString();
       }
Advertisements
Categories: BizTalk, REST Tags:

Configuring BizTalk 2006 R2 with Enterprise Library

February 5, 2009 Leave a comment

BizTalk is a powerful tool with a lot of out of the box features. However, there are varieties of tasks you would prefer to de-couple from BizTalk and delegate to an external framework specifically built for it. When I design software, I always pay attention to the post-deployment configurability of an application.  I always choose an approach that lets me easily change connection information, logging, exception handling, inject some logic, etc. The Microsoft Enterprise library resolves such issues perfectly. So, how would one configure BizTalk to recognize and use Enterprise library?  The answer is trivial and this blog’s purpose is just to document steps I performed to make it happen.

The first step was to install Microsoft Enterprise Library in the GAC. You can find detailed instructions in the help. I would also suggest reading Tom Hollander’s blog about managing Enterprise Library in your organization.

The second step is optional and is related to my habit to have a wrapper around 3rd party framework or solution. I have two libraries Common.Application.Exception with multiple ApplicationException descendents

and Common.EntLib.Logging in order to encapsulate some logic.

Here is an example of ErrorLogEntry with Category and Severity setting.

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Logging;
namespace Common.Logging
{
///<summary>
/// A log entry of category Error. Default priority is High.
///</summary>
public class ErrorLogEntry : LogEntry
{
public static LogPriority DefaultPriority = LogPriority.High;
///<summary>
/// Default constructor. Default priority is High.
///</summary>
///<param name=”message”></param>
public ErrorLogEntry(string message) : this(message, DefaultPriority) { }
///<summary>
/// Constructor with basic log entry information.
///</summary>
///<param name=”message”>Message to be logged.</param>
///<param name=”priority”>Priority of the log entry (low, high, etc.).</param>
public ErrorLogEntry(string message, LogPriority priority)
: base()
{
this.Categories.Add(LogCategories.Error);
Priority = (int)priority;
Severity = TraceEventType.Error;
Message = message;
}
}
}

Obviously, these Libraries has to be signed and deployed to the GAC 

The next step is to configure BizTalk run-time.  Before you do it, DO MAKE A COPY of BTSNTSvc.exe.config. Then open Enterprise Library Configuration console pointing to the BTSNTSvc.exe.config under C:\Program Files\Microsoft BizTalk Server 2006 folder and configure application blocks you intend to use within yours BizTalk applications.

To test an enterprise library call, I have created a simple orchestration with a receive shape and trigger message.

I also added Expression shape to call Enterprise Library.

Dropping trigger message into configured location produces expected Event log message.

I modified configuration by adding new Flat file trace listener

Then I added new trace listener to the Debug category .

The result appeared in two different destinations without modifying any BizTalk artifacts.

Enjoy

Technorati Tags: ,

Categories: BizTalk