映射器管道组件






2.45/5 (7投票s)
一个包含映射器的管道组件,提供一个 GUI 用于输入 XSLT。在运行时,接收管道将 XSLT 作为输入,并将源消息映射到目标消息。
映射简介
在传统的 BizTalk 项目中,我们使用现成的 BizTalk 映射器将源消息映射到目标消息。Biztalk 映射器为我们提供了此映射任务的图形界面。但有时,我们实际上只需要 XSLT 来转换消息。因此,我们创建一个包含源消息和目标消息的映射。但实际的映射将来自项目中包含的 XSLT 文件。在这种情况下,创建映射是实现简单转换过程的漫长步骤。这给了我一个想法,即在管道组件中开发转换概念,这样您就不必实际创建映射来进行消息转换。
目标读者
- 这里没有处理更复杂的内容。对 BizTalk 管道组件开发有充分的理解
- 具备 XML、XPath、XSLT 编程(C#)的良好知识
了解管道组件的背景
我已将此组件设计得尽可能简单。如果您可以查看开发简单解码器管道组件的代码,然后浏览我的代码,您会更好地理解它。有很多文章介绍了开发简单的解码器管道组件。因此,我不再深入解释组件开发的基础知识。
实际实现
对于自定义组件开发,正如我们目前所知,我们需要实现一些接口。因此,要开发解码器组件,我们需要实现 IComponent
、IBaseComponent
、IPersistPropertyBag
和 IComponentUI
接口。在我们的场景中,我们需要显示一个自定义对话框来输入 XSLT。此对话框应能够从自定义接收管道中自定义管道组件的属性窗口触发。要实现这一点,我们需要设计一个派生自 UITypeEditor
的类。您在管道编辑器中看到的属性网格是 .NET 属性网格。默认情况下,网格只能识别字符串值。要通知属性网格您需要一个对话框而不是默认的文本编辑器,您必须执行以下步骤:
实现 UITypEditor
类。
[System.Security.Permissions.PermissionSet
(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
class CustomXSLTUITypeEditor : UITypeEditor
{
}
重写 GetEditStyle
方法以返回一个 Modal
对话框。
public override UITypeEditorEditStyle GetEditStyle
(ITypeDescriptorContext context)
{
// Indicates that this editor can display a Form-based interface.
return UITypeEditorEditStyle.Modal;
}
在这里,我们重写 EditValue
方法并提供显示自定义对话框的实现。
public override object EditValue(
ITypeDescriptorContext context,
IServiceProvider provider,
object value)
{
// Attempts to obtain an IWindowsFormsEditorService.
IWindowsFormsEditorService edSvc =
(IWindowsFormsEditorService)provider.GetService
(typeof(IWindowsFormsEditorService));
if (edSvc == null)
{
return null;
}
// Displays a StringInputDialog Form to get a user-adjustable
// string value.
using (CustomXSLTPanel form = new CustomXSLTPanel((string)value))
{
XmlDocument xdoc = new XmlDocument();
if (edSvc.ShowDialog(form) ==
System.Windows.Forms.DialogResult.OK)
{
try
{
xdoc.LoadXml(form.txtXSLT.Text);
return form.txtXSLT.Text.Replace("\n","");
}
catch (XmlException ex)
{
System.Windows.Forms.MessageBox.Show
("The XSLT is invalid. Please try again",
"Error", System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
return value;
}
}
}
// If OK was not pressed, return the original value
return value;
}
CustomXSLTPanel
类是一个自定义 Windows 窗体,其中包含一个 RichTextBox
控件,可用于从用户那里获取 XSLT 输入。这是一个非常简单的窗体。
在提供了自定义组件所需的所有基本功能后,我们深入实现它。继续开发我们的组件的第一件事是实现基本接口。代码如下所示:
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Decoder)]
[System.Runtime.InteropServices.Guid("9d0e4103-4cce-4536-83fa-4a5040674ad6")]
public class MapperGUI : IBaseComponent,
IComponentUI,
Microsoft.BizTalk.Component.Interop.IComponent,
IPersistPropertyBag
{
}
我们需要实现 IBaseComponent
成员,以获取我们组件的基本信息。
#region IBaseComponent Members
public string Description
{
get
{
return "Pipeline component used as a BizTalk Mapper";
}
}
public string Name
{
get
{
return "MapperComponent";
}
}
public string Version
{
get
{
return "1.0.0.0";
}
}
#endregion
我已将其简化,因为我没有创建任何图标,也没有添加任何验证逻辑。如果您想玩一下,请继续。
#region IComponentUI Members
public IntPtr Icon
{
get
{
return new System.IntPtr();
}
}
public System.Collections.IEnumerator Validate(object projectSystem)
{
return null;
}
#endregion
我们将有一个属性来获取 XSLT 作为 string
值。因此,我们创建一个 private
变量和一个 public
属性。创建属性时有一个技巧。我们需要将 EditorAttribute
类添加到属性中。实际目的是我们需要调用一个对话框来填充此属性。我们将我们的自定义 UITypeEditor
类作为参数传递。我们还需要实现 Load
和 Save
方法。我在这里没有展示。但您可以在本文提供的源代码中找到它们。
#region IPersistPropertyBag Members
private string _customXSLT = string.Empty;
[EditorAttribute(typeof(CustomXSLTUITypeEditor),
typeof(UITypeEditor))]
public string CustomXSLT
{
get
{
return _customXSLT;
}
set
{
_customXSLT = value;
}
}
public void GetClassID(out Guid classID)
{
classID = new Guid("655B591F-8994-4e52-8ECD-2D7E8E78B25C");
}
public void InitNew()
{
}
public void Load(IPropertyBag propertyBag, int errorLog)
{
}
public void Save(IPropertyBag propertyBag, bool clearDirty,
bool saveAllProperties)
{
}
#endregion
现在到了我们组件开发中最重要的部分。我们实现了 Icomponent
接口的唯一方法。我已将实现保持得非常简单。这实际上涉及一些 XML、XPath 和 XSLT 编码来将输入消息转换为输出消息。我一直在代码中使用内存 stream
。
#region IComponent Members
public IBaseMessage Execute(IPipelineContext pContext,
IBaseMessage pInMsg)
{
IBaseMessagePart bodyPart = pInMsg.BodyPart;
Stream xmlData = bodyPart.Data;
Stream transformedMsg = TransformMessage(xmlData);
pInMsg.BodyPart.Data = transformedMsg;
pContext.ResourceTracker.AddResource(transformedMsg);
return pInMsg;
}
#endregion
这个 private
方法接收一个作为 stream
的输入消息并处理该消息。在转换消息后,它将其转换为 stream
并 return
返回。如果您浏览代码,您会发现它非常简单。
#region private members
private Stream TransformMessage(Stream inputMessage)
{
XslCompiledTransform transformer = new XslCompiledTransform();
byte[] outBytes = System.Text.Encoding.ASCII.GetBytes
(CustomXSLT);
MemoryStream memStream = new MemoryStream();
memStream.Write(outBytes, 0, outBytes.Length);
memStream.Position = 0;
XPathDocument xsltDoc = new XPathDocument((Stream)memStream);
MemoryStream destnStream = new MemoryStream();
transformer.Load(xsltDoc);
XPathDocument doc = new XPathDocument(inputMessage);
transformer.Transform(doc, null, destnStream);
return (Stream)destnStream;
}
#endregion
是否有任何背景信息对本文有所帮助,例如对所介绍的基本概念的介绍?
我发现 Saravanan 撰写的一篇关于自定义管道组件中设计时属性的白皮书。您可以在 此处 找到该文档。
关注点
由于这是我第一次发表文章,我可能遗漏了一些更重要的解释内容。请谅解。或者,您可以通过 shankar.sekar@gmail.com 发送电子邮件给我,这将有助于我改进组件开发或演示文稿。所有评论都欢迎。
我还要讨论使用此控件的缺点。由于我将此控件设计为解码器组件,因此我们无法使用它来验证 XML 消息。因此,我们只能在发送端口中使用直通发送管道。我计划将来扩展此控件以参与管道的所有阶段。请提供宝贵的意见以进一步开发。