扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
问:何时应该将 WSE 与 ASMX 结合使用,何时应该单独使用 ASMX?我希望将这个问题弄得更清楚些。
答:ASMX 2.0 支持 WS-I Basic Profile 1.1 和 SOAP 1.2。这意味着,它支持 XML 1.0、XML 架构定义 (XSD)、Web 服务描述语言 (WSDL)、SOAP 1.1、SOAP 1.2 以及编译时的基本配置文件一致性验证。WSE 3.0 通过提供对某些更高级的 WS-* 协议的支持,来补充 ASMX 2.0 的功能。目前,当您需要使用以下一个或多个功能来增强 ASMX 服务时,通常会使用 WSE 3.0:
基于消息的安全性和 MTOM 是人们在 ASMX 项目中启用 WSE 的两个主要原因。还有一个好消息是,您不必修改服务逻辑就可以这样做。WSE 3.0 通过 ASMX 提供的扩展点来利用 ASMX。这使您能够利用各种 WSE 3.0 功能,而不必学习新的编程模型 — 您需要做的就是运行 WSE 设置工具并选择所需的选项。
在 ASMX 项目中启用 WSE 3.0 的另一个原因是,要利用它的策略管道扩展性模型。WSE 使您能够插入对进入和离开终结点的 SOAP 消息执行预处理和后续处理的筛选器。该扩展点比 ASMX SOAPExtension 框架更易于使用,因为它提供的功能可以创建能够与 WSE 提供的现有声明性安全策略相结合的自定义声明性策略。您决定“启用”WSE 可能只是为了具有该扩展选项,或者至少是为了使用改进的 SOAP 消息诊断跟踪功能。
有了 WSE 2.0,大多数开发人员在需要进行自定义宿主时就抛弃了 ASMX。现在,WSE 3.0 使您能够执行 ASMX 类型的自定义宿主,这就更没有问题了。导致您单独使用 WSE 消息处理 API 的主要情况是,需要实现可选的消息交换模式,例如,双工通信、多播或发布/订阅情况。消息处理类 SOAPSender 和 SOAPReceiver 使您能够实现任何类型的高级消息处理模式。问:当我在 Web 站点中启用 WSE 3.0 后,在配置文件中再也看不到 WSE SOAPExtension 了。相反,我看到了一个 SOAPServerProtocolFactory。那是什么?
答:默认情况下,可以使用几个不同的服务器协议调用 ASMX 终结点,包括 HTTPSOAP、HTTPSOAP12、HTTPGet、HTTPPost、HTTPPostLocalhost 和 Documentation。您可以在 Web.config 中启用或禁用其中任何一个协议。.NET Framework 2.0 中的默认 ASMX 配置如下所示:
<WebServices> <protocols> <clear /> <add name="HTTPSOAP12" /> <add name="HTTPSOAP" /> <add name="HTTPPostLocalhost" /> <add name="Documentation" /> </protocols> ... </WebServices> |
每个协议都期望不同类型的 HTTP 消息,并实现不同的 ASMX 调用协议。例如,对于 HTTPSOAP,传入的 HTTP 有效负载将始终包含 ,而对于 HTTPGet,数据在查询字符串中传入且 HTTP 有效负载为空。前者在响应中返回 SOAP 信封,而后者只返回纯 XML。
为了处理这些差异,ASMX 处理程序 (System.Web.Services.Protocols.WebServiceHandler) 使用名为 ServerProtocol 的类来处理传入的消息。还有几个派生自 ServerProtocol 的类,包括 SOAPServerProtocol 和 HTTPGetServerProtocol。这些类将映射到配置文件中的不同协议。ASMX 处理程序会检查传入的 HTTP 消息,并选择合适的 ServerProtocol 类型。从那时起,ServerProtocol 实例就开始管理调用操作的过程。在调用过程中,SOAPExtension 框架就是它管理的内容之一。
SOAPExtension 框架是一个扩展点,以便开发人员在 ASMX 处理程序和目标 WebMethod 之间插入代码。实际上,它提供了一种用于转换传入消息流和传出消息流的机制。如果您需要修改 SOAPExtension 中的消息,则必须提供一个将传递到链中下一个扩展的新流(在一开始即与 SOAPExtension.ChainStream 绑定在一起)。因此,将重复以下过程:SOAPExtension 接收流,进行分析,执行它的任务,然后写入下一个 SOAPExtension 将读取的流。
WSE 2.0 完全作为 SOAPExtension 而实现的。在该级别实现 WSE 的一个问题是,它会在流级别导致大量的序列化/反序列化系统开销。移到 WSE 3.0,WSE 小组希望通过将抽象层上移并编写自己的 SOAPServerProtocol 实现来优化他们的 SOAP 处理模型。因此,他们询问 ASMX 小组是否能够通过 ASMX 2.0 中的配置来替换默认的 SOAPServerProtocol。ASMX 开发人员提供一个名为 的新配置元素,任何人都可以使用它来提供自己的实现(虽然我们不鼓励这么做)。ASMX 处理程序会读取该类型,并用它来创建相应 SOAPServerProtocol 类型的实例以处理新的请求。WSE 3.0 将使用该挂钩,并使用 Microsoft.Web.Services3.WSEProtocol 来替换默认的 SOAPServerProtocol 类。
WSEProtocol 可以在同一个类中管理 SOAPExtension 机制和 WSE 管道,从而减少了一些流摩擦。WSE 3.0 仍然使用 SOAPExtension(名为 WSEProtocolExtension),但它从来不在配置文件中出现,这是因为 WSEProtocol 在启动时动态插入它(以确保它始终存在)。WSEProtocolExtension 只负责识别和分析 MTOM 和 XML 1.0 流;其他事情均由 WSEProtocol 实现来完成。
因此,简单说, 是 WSE 3.0 将自身融入 ASMX 2.0 的方式。WSE 3.0 仍然使用 SOAPExtension,在该版本中,它只是不在执行任务的决策地。 问:如果在我自己的应用程序中承载 ASMX 类,会对 HTTPContext.Current 造成什么影响?SOAPExtension 又如何呢?
答:遗憾的是,ASMX 设计与 ASP.NET 紧密地耦合在一起。例如,当 Visual Studio® 创建新的 ASMX 类时,在默认情况下会从 System.Web.Services.WebService 派生。这会通过新的 ASMX 类上的属性来公开各种 System.Web.HTTPContext 属性,从而鼓励它们在 WebMethod 中的使用。某些开发人员还习惯于通过 HTTPContext.Current 显式使用 HTTP 上下文。
当您使用 WSE 3.0 中的 SOAPReceivers 承载一个 ASMX 类时,这种类型的代码就不再工作了。本例,您的代码在 IIS 和 ASP.NET HTTP 管道之外执行。HTTPContext.Current 将始终为空,因此这可能要求您修改现有的 WebMethod 逻辑。通常,如果您打算在 ASP.NET 之外的宿主环境中重用该类型,则应该避免在 WebMethod 代码中依赖 HTTP 管道中的任何内容。
此外,在使用 SOAPReceivers 作为宿主时,就不能再依赖 HTTPModule 或 SOAPExtension 为您执行任务了。因为现在您在 ASMX 处理程序之外执行,所以这些媒介将不再起作用。
问:我在 WSE 3.0 设置工具中找不到 Filters 选项卡。如何访问它呢?
答:Filters 选项卡不再位于 WSE 3.0 设置工具中,因为 元素已经从 WSE 3.0 配置部分中移除了。在 WSE 2.0 中,您使用 元素来定义通过筛选器构建管道的方式。默认情况下包含的一个筛选器是策略筛选器。策略筛选器查看另一个配置文件(策略文件),以便根据其断言(类似于筛选器)来决定如何处理传入和传出的消息。
在 WSE 3.0 中,这两个概念已统一。因此,现在的策略由断言组成,并且每个断言都会在管道中插入 WSE 筛选器。您将断言放到策略中,以控制筛选器管道在运行时如何构建和组织。因此,如果您希望在管道中插入自定义筛选器,则应该编写筛选器类,编写使用新筛选器的策略断言类,在策略中使用断言类,然后将该策略应用于服务。在 WSE 3.0 中,正是策略框架驱动着管道,因此就不再需要部分。 问:WSE 3.0 支持哪些传输?编写自定义传输很难吗?
答:WSE 3.0 支持 HTTP 和 TCP。WSE 提供一个自定义传输框架,以允许第三方插入自己的传输实现。自从 WSE 2.0 发布以后,一些开发人员提供了示例 WSE 传输来演示如何完成此操作。其中一个可用于 Microsoft 消息队列服务器 (MSMQ)、SMTP和 UDP。所有这些传输均针对 WSE 2.0 编写,但是将它们移植到 WSE 3.0 也没什么问题。
以下代码提供一个使用 SMTP 传输在控制台应用程序中宿主服务的示例:
SOAPReceivers.Add(new Uri("SOAP.SMTP://test@skonnard.com"), typeof(ExpenseReportService)); Console.ReadLine(); |
然后,在客户端,您只需在调用方法前指定 SMTP 地址即可,如下所示:
ExpenseReportServiceWSE svc = new ExpenseReportServiceWSE(); svc.Url = "SOAP.SMTP://test@skonnard.com"; svc.Submit(report); |
现在,客户端将向 test@skonnard.com 电子邮件地址发送消息,接收器将从同一个地址接收消息。该示例中比较有趣的是,客户端和接收器不再需要同时运行。请注意,在使用自定义传输时,开发人员体验不会受到影响。您必须做的一件事是,通过将 映射添加到 WSE 配置部分来告诉 WSE 如何处理“SOAP.SMTP”协议方案,如下所示:
<Microsoft.Web.services3> <messaging> <transports> <add scheme="SOAP.SMTP" type="SOAPSMTPTransport,SOAPSMTP"/> </transports> </messaging> ... </Microsoft.Web.services3> |
该元素将协议方案映射到一个从 ISOAPTransport 派生的类。当调用 SOAPReceivers.Add 时,它会从配置部分查找映射到指定协议方案的类型。然后,它会实例化指定的类型,并使用 ISOAPTransport 方法生成输入和输出通讯信道。客户端也会发生同样的操作。这些信道会对其余 API 隐藏所有传输实现的细节。
因此,编写自定义 WSE 传输需要实现三个类:一个用于建模传输 (ISOAPTransport),另外两个用于建模输入/输出信道(ISOAPInputChannel 和 ISOAPOutputChannel)。传输可提供信道并管理所有信道共享的资源,而信道主要用于通过传输发送/接收消息。这里,您处理的是低级别传输细节,因此有点困难。了解其工作方式的最佳方法是,演练我在前面提到的现有 WSE 传输示例。问:我能使用“Add Web Reference”为自定义宿主的 WSE 3.0 服务生成代理吗?
答:如果您在使用 TCP 进行通讯的 Windows 服务中承载服务,则检索 WSDL 的唯一方法就是使用 WSEWSDL3.exe 工具。该工具会向请求其元数据的服务发送 SOAP 消息,并根据在 SOAP 响应消息中返回的 WSDL 生成代理。
但是,如果相同的服务也通过 ASP.NET (HTTP) 来承载,则可以使用 Visual Studio 中的标准“Add Web Reference”命令(或 WSDL.exe)来生成代理(在此之前,请确保您在客户端应用程序中启用了 WSE,以便获得 WSE 代理)。生成的 WSE 代理可以用于任何 WSE 传输,而不仅仅是 HTTP。只需通过 Url 或 Destination 属性将代理的地址更改为 TCP 地址,它就可以像通过 WSEWSDL3.exe 生成的代理一样工作了。
问:应该如何组织解决方案,以便在不同的宿主间共享 ASMX 类型呢?
答:如果您需要在不同的宿主间共享 ASMX 类型,则应该将 ASMX 类放到共享类库中。起初,这看上去有些奇怪,因为您的 ASMX 代码可能始终在 Web 项目中,但是它们也可以分解到库中。我甚至可以更进一步,将所有消息序列化类组织到它们自己的单独类库中,因为您可能希望与客户端和代码生成器共享这些类型(例如,使用架构导入程序扩展)。
通过该配置,只需在每个宿主项目(包括 Web 站点宿主)中添加对类库的引用。然后,您的 Web 站点宿主将不再需要 App_Code 中的服务代码。相反,您的 .ASMX 文件将根据名称引用共享服务类。并且,在调用 SOAPReceivers.Add 时,自定义宿主可以提供相同的服务类型。
问:我的小组开发了一个常用的 XSD 序列化类库,我们希望所有开发人员在实现或使用我们的服务时都使用这个类库。当他们运行“XSD.exe /c”或“WSDL.exe”时,代码生成器应该使用我们的类型,而不是生成新的类型。这可以实现吗?
答:可以。通过实现所谓的架构导入程序扩展(.NET Framework 2.0 提供的一个新扩展点)即可做到。下面讨论一下它的要点。您编写了一个从 SchemaImporterExtension 派生的类,并重写了 ImportSchemaType。在该方法的实现中,您定义了传入的 XSD 类型如何映射到现有的 .NET 类型。如下 显示一个示例。
class CommonTypesSIE : SchemaImporterExtension { public override string ImportSchemaType( string name, string ns, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider) { if (name.Equals("StockQuote") && ns.Equals("http://example.org/stocks")) { mainNamespace.Imports.Add( new CodeNamespaceImport("CommonTypes")); return "CommonTypes.StockQuote"; } return null; } } |
然后,将架构导入程序扩展配置为由 XSD.exe 或 WSDL.exe 使用。您可以在 配置部分的 元素中进行配置。或者,您可以在运行 XSD.exe 或 WSDL.exe(通过 /parameters 选项)时,通过提供要使用的架构导入程序扩展列表来完成。问:能告诉我 /parameters 在 XSD.exe 和 WSDL.exe 中的文件格式吗?
答:XSD.exe 和 WSDL.exe 引入了一个新开关 /parameters,用于打包您要在单个 XML 文件中使用的所有命令行选项。XML 文件的格式由本专栏的下载中提供的 XML 架构定义来定义。该文件必须包含顶级 元素,该元素将包含所有选项。如下 显示一个示例。
<!-- options.xml --> <wsdlParameters xmlns='http://microsoft.com/webReference/'> <language>c#</language> <sharetypes>true</sharetypes> <webReferenceOptions xmlns="http://microsoft.com/webReference/"> <codeGenerationOptions>newAsync </codeGenerationOptions> <verbose>true</verbose> <schemaImporterExtensions> <type>CommonTypesSIE, CommonTypesSIE</type> </schemaImporterExtensions> </webReferenceOptions> </wsdlParameters> |
然后,您应该将该文件传递给 WSDL.exe,如下所示:
C:\demos> WSDL.exe /parameters:options.XML HTTP://localhost/stocks/quoteservice.ASMX |
每次使用其中的一个代码生成工具时,该方法有助于确保一组一致的选项。有趣的是,某些 XSD.exe 和 WSDL.exe 功能只能通过该机制访问。
问:我听说 3.0 版可能是最后一个 WSE 版本。这是真的吗?
答:在 WCF 发布以后,WSE 很可能会停止发展新功能,从而转向支持模式(修补程序、service pack 等)。WCF 定位为新的 .NET Web 服务平台,该平台可以完全替代现在对 WSE 所提供功能的需要。并且,由于 WCF 已经临近它的发布日期,因此 WSE 3.0 很可能是最后一个发布版本。WSE 开发小组已经重组到 WCF 小组,以巩固该小组内开发人员的实力。
但是,很可能会使用类似于 WSE 的工具扩展和“增强”WCF,虽然没人知道它们将被称为什么。此类工具可用于合并新的协议和行为,因为它们能够使用各种 WCF 扩展点。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者