使用 WCF 通道模型在 SAP 中流式传输 Flat-File IDOC
适用于 mySAP Business Suite 的 Microsoft BizTalk 适配器支持 SendIdoc 和 ReceiveIdoc 操作的节点值流式处理。 这些操作用于从适配器发送和接收平面文件 (字符串) IDOC。 在这两个操作中,整个 IDOC 的数据都包含在单个节点 (<idocData>) 下的字符串中。 对于大型 IDOC,在适配器和代码之间流式传输 IDOC 数据可能会节省大量内存资源。
有关适配器如何支持流式处理的背景信息,请参阅 流式处理和 SAP 适配器。 在继续之前,应先阅读本主题。
本主题中的各节介绍如何在使用 WCF 通道模型时为 SendIdoc 和 ReceiveIdoc 操作实现节点值流式处理。
将出站 Flat-File IDOC 流式传输到适配器
适配器支持对 SendIdoc 操作的请求消息进行节点值流式处理。
若要支持 WCF 通道模型中 SendIdoc 操作上的节点值流式处理,必须:
实现能够流式处理 IDOC 数据的 System.ServiceModel.Channels.BodyWriter , (对 IDOC 数据) 执行节点值流式处理。
创建用于调用操作的 System.ServiceModel.Message,方法是使用 Message.Create 方法的适当重载为此 BodyWriter 提供消息正文。
实现 BodyWriter
以下示例演示了执行节点值流式处理的 BodyWriter 的实现。
/// <summary>
/// This class overrides the OnWriteBodyContents function to do node-value streaming
/// </summary>
class StreamingBodyWriter : BodyWriter, IDisposable
{
XmlReader m_reader = null;
int m_chunkSize;
/// <summary>
/// Initializes the body writer
/// </summary>
/// <param name="reader">Reader for input</param>
/// <param name="chunkSize">The chunksize in which the data is passed to adapter</param>
public StreamingBodyWriter(XmlReader reader, int chunkSize)
: base(false)
{
m_reader = reader;
if (chunkSize <= 0)
throw new ApplicationException("ChunkSize should be a positive value");
m_chunkSize = chunkSize;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
if (m_reader == null)
throw new ApplicationException("Reader cannot be null");
while (m_reader.Read())
{
switch (m_reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(m_reader.LocalName, m_reader.NamespaceURI);
break;
case XmlNodeType.Text:
#region Streaming Code
char[] tempBuffer = new char[m_chunkSize];
int length = 0;
while ((length = m_reader.ReadValueChunk(tempBuffer, 0, m_chunkSize)) > 0)
{
writer.WriteString(new String(tempBuffer, 0, length));
}
#endregion
break;
case XmlNodeType.EndElement:
writer.WriteEndElement();
break;
}
}
}
#region IDisposable Members
public void Dispose()
{
if (m_reader != null)
{
m_reader.Close();
m_reader = null;
}
}
#endregion
}
使用 BodyWriter 创建消息
以下示例演示如何在前面的示例中使用 BodyWriter 创建 SendIdoc 请求消息。 从文件读取消息数据。
XmlReader readerIn = XmlReader.Create ("sendidoc.xml");
// StreamingBodyWrtier class is responsible for streaming
StreamingBodyWriter stBW = new StreamingBodyWriter(readerIn, chunkSize);
Message InputMsg = Message.CreateMessage(MessageVersion.Default,
"http://Microsoft.LobServices.SAP/2007/03/Idoc/SendIdoc",
stBW);
从适配器流式处理入站 Flat-File IDOC
在入站 ReceiveIdoc 操作中收到平面文件 IDOC。 适配器支持对 ReceiveIdoc 操作的请求消息进行节点值流式处理。
若要支持 WCF 通道模型中 ReceiveIdoc 操作上的节点值流式处理,必须:
实现 System.Xml。能够流式处理 IDOC 数据的 XmlDictionaryWriter (对 IDOC 数据) 执行节点值流式处理。
使用此 XmlDictionaryWriter 调用其 WriteBodyContents 方法来使用 Message。
实现 XmlDictionaryWriter
以下示例演示执行节点值流式处理的 XmlDictionaryWriter 的实现。
using System;
using System.Xml;
using System.Text;
class FileXmlWriter : XmlDictionaryWriter
{
XmlTextWriter xts;
public FileXmlWriter(string file)
{
xts = new XmlTextWriter(file, Encoding.UTF8);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
xts.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
xts.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
xts.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
xts.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
xts.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
xts.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
xts.WriteEndAttribute();
}
public override void WriteEndDocument()
{
xts.WriteEndDocument();
}
public override void WriteEndElement()
{
xts.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
xts.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
xts.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
xts.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
xts.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
xts.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
xts.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument(bool standalone)
{
xts.WriteStartDocument(standalone);
}
public override void WriteStartDocument()
{
xts.WriteStartDocument();
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
xts.WriteStartElement(localName);
}
public override void WriteString(string text)
{
xts.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
xts.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteWhitespace(string ws)
{
xts.WriteWhitespace(ws);
}
public override void Close()
{
xts.Close();
}
public override void Flush()
{
xts.Flush();
}
public override string LookupPrefix(string ns)
{
return xts.LookupPrefix(ns);
}
public override WriteState WriteState
{
get { return xts.WriteState; }
}
}
使用 XmlDictionaryWriter 使用消息
以下示例演示如何使用在前面的示例中实现的 FileXmlWriter 使用 ReceiveIdoc 请求消息。 (FileWriter 类是通过 子类 XmlDictionaryWriter.) 该示例使用 IReplyChannel 通道接收 ReceiveIdoc 操作。 已省略通道创建的详细信息。 ReceiveIdoc 请求消息将写入文件。
// Receive the ReceiveIdoc request message from the adapter.
RequestContext rc = channel.ReceiveRequest();
Message inputMsg = rc.RequestMessage;
// Stream the request message to received_idoc.xml using the custom XmlDictionaryWriter.
FileXmlWriter fileXmlWriter = new FileXmlWriter("received_idoc.xml");
inputMsg.WriteBodyContents(fileXmlWriter);
fileXmlWriter.Flush();
fileXmlWriter.Close();