65.9K
CodeProject 正在变化。 阅读更多。
Home

BizTalk 中的确认

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2012年10月23日

CPOL

2分钟阅读

viewsIcon

16789

关于如何在 BizTalk 中发送确认,这可以通过使用或不使用编排来实现

引言

今天我想和大家谈谈如何在 BizTalk 中发送确认,这可以通过使用或不使用编排来实现。

背景

每当我们使用请求-响应接收适配器时,都需要在 BizTalk 接收到消息后向源应用程序发送确认。场景如下:

  • 双向 WCF-SAP 适配器
  • 双向 MLLP 适配器
  • 双向 WCF SQL 适配器

在某些情况下,消息只需要一个确认来确保消息已到达 BizTalk,并且可以发送下一条消息。而在其他一些情况下,所有发送的消息都在等待确认,以确保队列中的消息批次可以被删除。

在某些情况下,确认预计是静态响应,而在其他情况下,它们需要根据接收到的消息插入一些数据到响应中。还有许多其他场景,但只想在这里关注几个。

使用代码

如何创建确认并发送它?

使用编排

  1. 从请求-响应端口接收消息,端口绑定为“稍后指定”
  2. 在构造消息形状中创建响应(无论响应是静态的还是基于请求消息)
  3. 通过请求-响应端口发送响应消息,如图所示

这是最简单的方法,但这种方法的开销是使用 XLang 引擎进行确认。

使用管道

  1. 管道组件的代码负责提升用于 Ack 的属性,并如下发送 Ack
  2. namespace PipelineComponents.Ack
    {
    using System;
    using System.IO;
    using System.Text;
    using System.Drawing;
    using System.Resources;
    using System.Reflection;
    using System.Diagnostics;
    using System.Collections;
    using System.ComponentModel;
    using Microsoft.BizTalk.Message.Interop;
    using Microsoft.BizTalk.Component.Interop;
    using Microsoft.BizTalk.Component;
    using Microsoft.BizTalk.Messaging;
    using Microsoft.BizTalk.Streaming;
      
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [System.Runtime.InteropServices.Guid("bbcf1287-f4fb-41f8-97b2-b329e5153658")]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    public class Ack : Microsoft.BizTalk.Component.Interop.IComponent, 
                       IBaseComponent, IPersistPropertyBag, IComponentUI
    {
        private System.Resources.ResourceManager resourceManager = 
            new System.Resources.ResourceManager(
            "PipelineComponents.Ack.Ack", Assembly.GetExecutingAssembly());
        private bool _IsEnabled;
        public bool IsEnabled
        {
            get 
            {
                return _IsEnabled;
            }
            set 
            {
                _IsEnabled = value;
            }
        }
        private bool _IsStaticResponse;
        public bool IsStaticResponse
        {
            get 
            { 
                return _IsStaticResponse;
            }
            set 
            {
                _IsStaticResponse = value;
            }
        }
    
        private bool _IsReceive;
        public bool IsReceive
        {
            get 
            {
                return _IsReceive;
            }
            set
            {
                _IsReceive = value;
            }
        }
    
        private string _StaticResponse;
        public string StaticResponse
        {
            get
            {
                return _StaticResponse;
            }
            set
            {
                _StaticResponse = value;
            }
        }
    
    #region IBaseComponent members
    
        /// <summary> 
        /// Name of the component 
        /// </summary> 
        [Browsable(false)]
        public string Name
        {
            get 
            {
                return “Ack”;
            }
        }
     
        /// <summary> 
        /// Version of the component 
        /// </summary> 
        [Browsable(false)]
        public string Version
        {
            get 
            {
                return “1.0”;
            }
        }
     
        // Author: Nihar Malali 
        /// <summary> 
        /// Description of the component 
        /// </summary> 
        [Browsable(false)]
        public string Description
        {
            get 
            {
                return “For Acknowledgment”;
            }
        }
    #endregion 
    #region IPersistPropertyBag members
    // Author: Nihar Malali 
    /// <summary> 
    /// Gets class ID of component for usage from unmanaged code. 
    /// </summary> 
    /// <param name="classid"> 
    /// Class ID of the component 
    /// </param> 
    public void GetClassID(out System.Guid classid)
    {
        classid = new System.Guid("bbcf1287-f4fb-41f8-97b2-b329e5153658");
    }
    
    /// <summary> 
    /// not implemented 
    /// </summary> 
    public void InitNew()
    {
    }
    
    // Author: Nihar Malali 
    /// <summary> 
    /// Loads configuration properties for the component 
    /// </summary> 
    /// <param name="pb">Configuration property bag</param> 
    /// <param name="errlog">Error status</param> 
    public virtual void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, int errlog)
    {
        object val = null;
        val = this.ReadPropertyBag(pb, "IsEnabled");
        if ((val != null))
        {
            this._IsEnabled = ((bool)(val));
        }
        val = this.ReadPropertyBag(pb, "IsStaticResponse");
        if ((val != null))
        {
            this._IsStaticResponse = ((bool)(val));
        }
        val = this.ReadPropertyBag(pb, "IsReceive");
        if ((val != null))
        {
            this._IsReceive = ((bool)(val));
        }
        val = this.ReadPropertyBag(pb, "StaticResponse");
        if ((val != null))
        {
            this._StaticResponse = ((string)(val));
        }
    }
     
    // Author: Nihar Malali 
    /// <summary> 
    /// Saves the current component configuration into the property bag 
    /// </summary> 
    /// <param name="pb">Configuration property bag</param> 
    /// <param name="fClearDirty">not used</param> 
    /// <param name="fSaveAllProperties">not used</param> 
    public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, 
                   bool fClearDirty, bool fSaveAllProperties)
    {
        this.WritePropertyBag(pb, "IsEnabled", this.IsEnabled);
        this.WritePropertyBag(pb, "IsStaticResponse", this.IsStaticResponse);
        this.WritePropertyBag(pb, "IsReceive", this.IsReceive);
        this.WritePropertyBag(pb, "StaticResponse", this.StaticResponse);
    }
     
    #region utility functionality
    
    /// <summary> 
    /// Reads property value from property bag 
    /// </summary> 
    /// <param name="pb">Property bag</param> 
    /// <param name="propName">Name of property</param> 
    /// <returns>Value of the property</returns> 
    private object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
    {
        object val = null;
        try 
        {
            pb.Read(propName, out val, 0);
        }
        catch (System.ArgumentException )
        {
            return val;
        }
        catch (System.Exception e)
        {
            throw new System.ApplicationException(e.Message);
        }
        return val;
    }
    
    /// <summary> 
    /// Writes property values into a property bag. 
    /// </summary> 
    /// <param name="pb">Property bag.</param> 
    /// <param name="propName">Name of property.</param> 
    /// <param name="val">Value of property.</param> 
    private void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
    {
        try 
        {
            pb.Write(propName, ref val);
        }
        catch (System.Exception e)
        {
            throw new System.ApplicationException(e.Message);
        }
    }
    
    #endregion 
    
    #endregion 
    
    #region IComponentUI members
    /// <summary> 
    /// Component icon to use in BizTalk Editor 
    /// </summary> 
    [Browsable(false)]
    public IntPtr Icon
    {
     get 
     {
      return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", 
               System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
     }
    }
    /// <summary> 
    /// The Validate method is called by the BizTalk Editor during the build 
    /// of a BizTalk project. 
    /// </summary> 
    /// <param name="obj">An Object containing the configuration properties.</param>
    /// <returns>The IEnumerator enables the caller to enumerate through a collection
    /// of strings containing error messages. These error messages appear as compiler
    /// error messages. To report successful property validation,
    /// the method should return an empty enumerator.</returns>
    
    public System.Collections.IEnumerator Validate(object obj)
    {
     // example implementation: 
     // ArrayList errorList = new ArrayList(); 
     // errorList.Add("This is a compiler error"); 
     // return errorList.GetEnumerator(); 
     return null;
    }
     
    
    #endregion 
    
    
    #region IComponent members
    public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(
      Microsoft.BizTalk.Component.Interop.IPipelineContext pc, 
      Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
    {
     if (IsEnabled)
     {
      int bufferSize = 0x280;
      int thresholdSize = 0x100000;
      IBaseMessageContext messageContext = inmsg.Context;
      IBaseMessagePart bodyPart = inmsg.BodyPart;
      string msgout = "";
      Stream inboundStream = bodyPart.GetOriginalDataStream();
      VirtualStream virtualStream = new VirtualStream(bufferSize, thresholdSize);
      ReadOnlySeekableStream readOnlySeekableStream = 
        new ReadOnlySeekableStream(inboundStream, virtualStream, bufferSize);
      if (IsReceive)
      {
       #region ReceiveLogic
      string sysproperty_namespace = "<a href="http://schemas.microsoft" + 
        ".com/BizTalk/2003/system-properties">http://" + 
        "schemas.microsoft.com/BizTalk/2003/system-properties</a>";
      try 
      {
       string EpmRRCorrelationToken = String.Empty;
       bool RouteDirectToTP = true;
       object objEpmToken = messageContext.Read("EpmRRCorrelationToken", sysproperty_namespace);
       if (objEpmToken != null)
        EpmRRCorrelationToken = (string)objEpmToken;
       else 
        EpmRRCorrelationToken = System.Guid.NewGuid().ToString();
       messageContext.Promote("EpmRRCorrelationToken", sysproperty_namespace, EpmRRCorrelationToken);
       messageContext.Promote("RouteDirectToTP", sysproperty_namespace, RouteDirectToTP);
       readOnlySeekableStream.Position = 0;
       bodyPart.Data = readOnlySeekableStream;
       readOnlySeekableStream.Position = 0;
       bodyPart.Data = readOnlySeekableStream;
      }
      catch (Exception ex)
      {
       throw (ex);
      } 
    
    
     #endregion 
      }
     
      else 
      {
       #region SendLogic
         if (IsStaticResponse)
         msgout = StaticResponse;
         else 
         {
          //comment the below line and add your Logic to create your Acknowledgement Message here    
          msgout = StaticResponse;
         }
         
       #endregion 
      }
     
      VirtualStream outStream = new VirtualStream();
      StreamWriter sw = new StreamWriter(outStream, Encoding.Default);
      sw.Write(msgout);
      sw.Flush();
      outStream.Seek(0, SeekOrigin.Begin);
      inmsg.BodyPart.Data = outStream;
      pc.ResourceTracker.AddResource(outStream);
     }
    
     return inmsg;
    }
    #endregion 
    }
    }
  3. 构建并部署此管道组件
  4. 将此组件添加到管道的任何阶段
  5. 接收管道的配置如下所示

发送管道的配置如下所示

它是如何工作的?

  1. 如果您查看订阅,您会观察到请求-响应接收位置有一个订阅用于响应消息,以下屏幕截图显示了订阅的详细信息。
  2. 因此,在请求-响应接收位置的接收管道中提升请求消息的以下两个属性:
  3. http://schemas.microsoft.com/BizTalk/2003/system-properties.EpmRRCorrelationToken

    http://schemas.microsoft.com/BizTalk/2003/system-properties.RouteDirectToTP

  4. 当请求消息到达消息框时,订阅将拾取等待响应消息的请求消息。
  5. 如果预计确认是静态的,则在发送管道中硬编码消息,否则编写业务逻辑来使用管道组件创建响应消息。

对于静态响应,这将无需性能开销地正常工作,并且如果您想根据请求消息或其他参数创建确认,则在您找到上述代码中的以下注释的部分添加创建确认的逻辑。

//comment the below line and add your Logic to create your Acknowledgement Message here

编码愉快!!!

关注点

无需编排即可实现确认,并且无需任何开销,并且非常注重性能。

© . All rights reserved.