BizTalk 中的确认





5.00/5 (2投票s)
关于如何在 BizTalk 中发送确认,这可以通过使用或不使用编排来实现
引言
今天我想和大家谈谈如何在 BizTalk 中发送确认,这可以通过使用或不使用编排来实现。
背景
每当我们使用请求-响应接收适配器时,都需要在 BizTalk 接收到消息后向源应用程序发送确认。场景如下:
- 双向 WCF-SAP 适配器
- 双向 MLLP 适配器
- 双向 WCF SQL 适配器
在某些情况下,消息只需要一个确认来确保消息已到达 BizTalk,并且可以发送下一条消息。而在其他一些情况下,所有发送的消息都在等待确认,以确保队列中的消息批次可以被删除。
在某些情况下,确认预计是静态响应,而在其他情况下,它们需要根据接收到的消息插入一些数据到响应中。还有许多其他场景,但只想在这里关注几个。
使用代码
如何创建确认并发送它?
使用编排
- 从请求-响应端口接收消息,端口绑定为“稍后指定”
- 在构造消息形状中创建响应(无论响应是静态的还是基于请求消息)
- 通过请求-响应端口发送响应消息,如图所示
这是最简单的方法,但这种方法的开销是使用 XLang 引擎进行确认。
使用管道
- 管道组件的代码负责提升用于 Ack 的属性,并如下发送 Ack
- 构建并部署此管道组件
- 将此组件添加到管道的任何阶段
- 接收管道的配置如下所示
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
}
}
发送管道的配置如下所示
它是如何工作的?
- 如果您查看订阅,您会观察到请求-响应接收位置有一个订阅用于响应消息,以下屏幕截图显示了订阅的详细信息。
- 因此,在请求-响应接收位置的接收管道中提升请求消息的以下两个属性:
- 当请求消息到达消息框时,订阅将拾取等待响应消息的请求消息。
- 如果预计确认是静态的,则在发送管道中硬编码消息,否则编写业务逻辑来使用管道组件创建响应消息。
http://schemas.microsoft.com/BizTalk/2003/system-properties.EpmRRCorrelationToken
和
http://schemas.microsoft.com/BizTalk/2003/system-properties.RouteDirectToTP
对于静态响应,这将无需性能开销地正常工作,并且如果您想根据请求消息或其他参数创建确认,则在您找到上述代码中的以下注释的部分添加创建确认的逻辑。
//comment the below line and add your Logic to create your Acknowledgement Message here
编码愉快!!!
关注点
无需编排即可实现确认,并且无需任何开销,并且非常注重性能。