科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件Web Services Enhancements 管道技术内幕

Web Services Enhancements 管道技术内幕

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

摘要:Web Services Enhancements 1.0 for Microsoft .NET 工作原理;独立过滤器和过滤器管道的工作原理......

作者:佚名 来源:Microsoft 2007年11月17日

关键字: 软件

  • 评论
  • 分享微博
  • 分享邮件
自定义过滤器

  WSE 过滤器体系结构可以扩展。您或许已经注意到了,TimestampOutputFilter 类扩展了 Microsoft.Web.Services.SoapOutputFilter,而 TimestampInputFilter 类扩展了 Microsoft.Web.Services.SoapInputFilterSoapOutputFilterSoapInputFilter 都是抽象基类。如果您希望自己编写过滤器,只需要从相应的基类中派生出一个子类并重写抽象 ProcessMessage 方法。

  自定义过滤器有许多用途。以下是一个自定义过滤器,它检查 Web 服务生成的输出消息是否包含 SOAP Fault 元素。如果包含,则将错误内容写到 Windows 事件日志中。此输出过滤器不会修改消息。

public class SoapFaultOutputFilter : SoapOutputFilter
{
public override void ProcessMessage(SoapEnvelope envelope)
{
// 使用 XPath 在消息中查找错误
XmlNamespaceManager nsMgr =
new XmlNamespaceManager(envelope.NameTable);
nsMgr.AddNamespace("soap",
"http://schemas.xmlsoap.org/soap/envelope/");
XmlElement fault = (XmlElement)
envelope.Body.SelectSingleNode("soap:Fault", nsMgr);

// 如果有错误...
if (fault != null)
{
// 获取错误的内容
XmlNode faultcode = fault.SelectSingleNode("faultcode");
XmlNode faultstring = fault.SelectSingleNode("faultstring");
XmlNode faultactor = fault.SelectSingleNode("faultactor");
XmlNode detail = fault.SelectSingleNode("detail");

// 将错误的内容格式化为字符串
string msg = string.Format("{0}\n{1}\n{2}\n\n{3}",
((faultcode != null) ? faultcode.InnerText : ""),
((faultstring != null) ? faultstring.InnerText : ""),
((faultactor != null) ? faultactor.InnerText : ""),
((detail != null) ? detail.OuterXml : ""));

// 将原始的错误正文写入字节数组
MemoryStream stm = new MemoryStream();
StreamWriter sw = new StreamWriter(stm);
sw.Write(fault.OuterXml);
sw.Flush();
byte[] buf = stm.ToArray();

// 将错误数据写入事件日志
WriteToEventLog(msg, "WSE", buf);

sw.Close();
}
}

private void WriteToEventLog(string msg, string src, byte[] buf)
{
EventLog eventLog = null;
try
{
// 将错误数据写入事件日志,并在必要时创建
eventLog = new EventLog();
eventLog.Log = "WSEFaultLog";
eventLog.Source = src;
eventLog.WriteEntry(msg, EventLogEntryType.Error, 0, 0, buf);
}
finally
{
if (eventLog != null) eventLog.Dispose();
}
}
}

  SoapFaultOutputFilter.ProcessMessage 方法使用 XPath 来探测作为参数传递的 SoapEnvelope。它查找 SOAP Fault 元素。如果找到,则提取错误信息,将其格式化为字符串,然后传递给 WriteToEventLog 方法。WriteToEventLog 使用 System.Diagnostics.EventLog 类将错误信息写入名为“WSEFaultLog”的自定义事件日志中,并在必要时创建该文件。值得注意的是,此过滤器仅查看服务本身生成的 SOAP Faults。如果由于消息签名不正确,SecurityInputFilter 拒绝客户端发送的消息,则此过滤器不会查看该消息。

  SoapFaultOutputFilter 用于需要记录向客户端发送 SOAP Fault 情况的任意 Web 服务。它可以很容易地实现类似的输入过滤器,以记录客户收到来自服务的 SOAP Fault 的情况,但是由于不需要这样的实现,因此就没有什么意义。WSE 不要求所有的输出过滤器都有匹配的输入过滤器,也不要求所有的输入过滤器都有匹配的输出过滤器。许多任务(例如记录错误或按照架构验证消息正文的内容)都可以采用非对称的方式完成,即仅针对输入或输出消息,而不是同时针对两者。

  使用 SoapContext 与自定义过滤器通信

  内置 WSE 过滤器与应用程序其他部分的通信是通过附加到 SoapEnvelopeSoapContext 对象属性来实现的。对于自定义过滤器,可以使用相同的技术。SoapContext 类包含一个 System.Collections.Hashtable 对象,用于存储任意数据,因此以下方法间接公开了 Hashtable

public class SoapContext
{
public void Add(string key, object value);
public void Clear();
public bool Contains(string key);
public IDictionaryEnumerator GetEnumerator();
public void Remove(string key);
... // 省略其他属性和方法
}

  可以通过修改 SoapFaultOutputFilter 来使用 SoapContext,从而允许应用程序指定记录错误时所使用的源字符串。在上面的 SoapFaultOutputFilter.ProcessMessage 实现中,源字符串被“硬编码”为“WSE”:

// 将错误数据写入事件日志
WriteToEventLog(msg, "WSE", buf);

  下面是修改过的代码,如果 SoapContext 存在,则从中提取源字符串,字符串的值由 FaultSource 指定:

// 将错误数据写入事件日志
string src = "WSE";
if (envelope.Context.Contains("FaultSource"))
src = envelope.Context["FaultSource"];
WriteToEventLog(msg, src, buf);

  对于其他更复杂的自定义过滤器,您可以使用此技术来研究 SoapContext 的所有附加对象模型。

  配置自定义过滤器

  实现了自定义过滤器之后,必须配置 Pipeline 才能使用该过滤器。可以通过向应用程序的 .config 文件中添加一行来进行配置,如下所示。

<configuration>
<microsoft.web.services>
<filters>
<!-- 请注意,您可以不对称地添加自定义过滤器,
即仅添加输出过滤器或仅添加输入过滤器 -->
<output>
<add type="SoapFaultOutputFilter,WSEFilters" />
</output>
</filters>
</microsoft.web.services>
</configuration>

  采用这种方法配置的自定义过滤器被自动添加到默认过滤器集合的末尾,因而它始终比内置的 WSE 过滤器更“接近代码”。您也可以通过修改 AppDomain 默认过滤器集合,手动配置自定义过滤器,如下所示:

WebServicesConfiguration.FilterConfiguration.OutputFilters.Add(
new SoapFaultOutputFilter();

  如果您不希望将自定义过滤器附加到默认过滤器集合的末尾,则需要使用后一种方法。

  关于 DIME

  WSE 唯一不是通过输入和输出过滤器实现的重要功能是支持 DIME 和 WS-Attachments。DIME 规范定义了消息的二进制格式。WS-Attachments 规范说明了如何使用 DIME 将二进制数据附加到 SOAP 消息中。Pipeline 类使用的过滤器链将各个 SoapEnvelope 对象“就地”转换。SOAP 消息与 DIME 记录之间的映射要求进行从 SOAP 消息到二进制流或相反方向的不同格式转换。这反映了一个事实:DIME 与其他 Web 服务协议不同,DIME 实际上不是基于 SOAP 的。简而言之,当您使用 DIME 时,已超出了 SOAP 的范围,WSE 过滤器模型不支持这种转换,因此需要独立的机制。

  Microsoft.Web.Services.Dime 命名空间中的类实现了 WSE DIME 功能。DimeWriterDimeReader 类为 DIME 消息提供了基于流的 IO。两个类均使用 DimeRecord 对象来表示 DIME 消息中的各个记录。调用 Pipeline.ProcessOutputMessage 之后,可以使用 DimeWriter 将出站 SOAP 消息转换为 DIME 消息。与此类似,调用 Pipeline.ProcessInputMessage 之前,可以使用 DimeReader 将入站 DIME 消息转换为 SOAP 消息。

  大多数 Web 服务开发人员认为 DIME(与 WS-Attachments 一起)的功能是将二进制数据与 SOAP 消息一起发送,实际上 DIME 还有另一个更有趣的用途。如果您打算使用基于流的协议来发送一个 SOAP 消息,则需要某种方法来指定消息的大小,以便接收者了解消息何时结束以及下一个消息何时开始。当通过 HTTP 发送 SOAP 消息时,可以使用内容长度标头来指定消息的大小。如果使用其他方法发送 SOAP 消息,则可以使用 DIME。以下是一个用一条记录将 SOAP 消息转换为 DIME 消息的函数。

public void EnvelopeToDIMEStream(SoapEnvelope env, Stream stm)
{
// 为 DIME 消息创建写入器
DimeWriter dw = new DimeWriter(stm);

// 生成新的记录 id
Guid guid = Guid.NewGuid();
string id = string.Format("uuid:{0}", guid.NewGuid().ToString()));

// 创建新记录,指定内容将
// 为 SOAP 封装,长度应该
// 通过计算得出 (-1)
DimeRecord rec = dw.LastRecord(id,
"http://schemas.xmlsoap.org/soap/envelope/",
TypeFormatEnum.AbsoluteUri, -1);

// 将 SOAP 消息写入 DIME 记录
env.Save(rec.BodyStream);

// 清除
dw.Close();
}

  而下面是与之对应的将 DIME 消息转换为 SOAP 消息的函数。

public DIMEStreamToEnvelope(Stream stm, SoapEnvelope env)
{
// 为 DIME 消息创建读取器
DimeReader dr = new DimeReader(stm);

// 读取包含 SOAP 消息的记录
DimeRecord rec = dr.ReadRecord();

// 从 DIME 记录读取 SOAP 消息
env.Load(rec.BodyStream);

// 确认没有其他记录
Debug.Assert(rec.MessageEnd);
}

  如果您使用 DIME 向 SOAP 消息附加任意数据,进行读写操作的代码将变得更加复杂。WSE 的关键之处是它为作为 SoapEnvelope 对象中 SoapContext 的一部分的附件数据提供了保存场所。尤其是,DimeAttachmentCollection 类型的 SoapContext.Attachments 属性可以为您保存 DimeAttachment 对象。每个 DimeAttachment 与一个 DIME 记录相对应,包括 id、类型标识符、区块大小以及二进制数据流。

  小结

  Web Services Enhancements (WSE) 功能(主要)是通过使用处理入站和出站消息的过滤器来实现的。您可以单独使用过滤器或者在管道中使用过滤器,也可以控制进程中管道的默认配置。还可以创建自定义过滤器,添加您需要的功能。总之,WSE 提供了无比灵活且可扩展的体系结构。不管您是结合使用 WSE 与 ASP.NET Web 服务还是单独使用 WSE,深入理解过滤器和管道的工作原理将有助于充分利用 WSE 提供的强大功能。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章