【问题标题】:WCF, SOAP, Plain Old XMLWCF、SOAP、普通旧 XML
【发布时间】:2011-04-11 18:25:15
【问题描述】:

我对 Web Service 世界中的一些事情感到非常困惑,我希望有人能向我解释一下。

这就是我想要的:我想将一个 XML 文档 HTTPPost 到 https://www.whatever.com/myservice(.???)。在那个服务中,我想获取那个 XML 文档,做一些事情,然后用一个非常简单的 XML 文档做出响应——比如“<xml....><success>TRUE</success>

我不能做 SOAP 或 JSON 或其他任何事情。我必须符合已经存在的东西。有数百家不同的公司以我所描述的格式向我们发送数据,并且根本不可能添加将其全部包含在 SOAP 中的要求。

使用 WCF Web 服务时,似乎必须像这样发送给我的请求:

 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetData xmlns="http://tempuri.org/"><value>3</value></GetData></s:Body></s:Envelope>

当使用 .asmx 页面时,响应总是作为带有命名空间的 XML 文档发送(http://tempuri,或者如果我更改了它,那么我将其更改为任何内容)。这是不必要的,并且可能会破坏所有现有代码。

使用通用处理程序 (.ashx) 时,我绝对可以准确控制返回的内容,但有人告诉我要远离 .ashx 页面,因为它们带有完整的 ASP.Net 会话类型代码,而且它是慢得多。

我会用什么来解决这个问题并让我的代码尽可能快?

编辑:以防万一,每小时 10,000 个请求的问题是我们一年中的高峰流量。我们平均每天处理 50-60,000 个传入请求,但在 12 月,它可以达到每小时 10,000 个请求。我们希望增长,但要做到这一点,我会在 Rackspace 中添加一个负载均衡器和更多机器。

我们目前的这项服务提供商在这些时候不堪重负,因此我们错过了很多钱。因此,我的代理将在前端进行我们最基本的检查之一(对每小时更新的数据库进行重复检查),这将清除我们必须发送给当前提供商的 75% 的流量。当前的供应商为我们承保这些潜在客户,我不会替换它,只是添加一个看门人以减轻他们服务器的压力。

感谢大家的帮助。我最近在 StackOverflow 上提出了一系列 Web 服务问题,试图弄清楚我将面临的许多问题。

【问题讨论】:

  • 我相信处理程序 (.ashx) 只有在实现 IRequiresSessionState 时才使用会话状态。
  • 它是.ashx。也许我误解了我被告知的内容,但我不这么认为。感谢您的评论。

标签: asp.net xml wcf web-services


【解决方案1】:

您所说的是 POX 服务 -- 也称为普通旧 XML。

告诉你 IHttpHandler 携带会话代码的人是错误的——除非你 explicitly enable session state,否则他们不会。现在,它确实有 ASP.NET 管道开销,但除非您使用一些疯狂的边缘轻量级 Web 套接字服务器,否则这并不重要,因为任何形式的 IIS 托管服务都会有类似的开销。而且,如果这是一个面向公众的 Internet 服务,IIS 会为您做一些您可能想要的整洁的事情。诸如 SSL、请求日志记录以及与其他操作用于监视事物的集成之类的东西。

至于如何到达那里,因为您已经定义了格式,因此具有默认 (SOAP) 行为的 ASMX 和 WCF 已被定义。为了灵活性,服务的实际逻辑应该单独实现,让外部位负责接收请求、从 xml 转换并将响应以正确格式的 XML 发送回来。

这给你留下了几个选择:

  • 自定义 IHttpHandler 可能是最简单的,尤其是当它连接到现有的 .NET 站点时。与其他地方相比,您必须在堆栈的下方低很多,但如果这确实需要一组 XML 并返回响应,那么工作并非不可克服。一个很大的优势是您对输出端的控制有限,因此如果您有一项长时间运行的任务,您可以非常轻松地流式传输响应。

  • ASP.NET MVC Web 服务可能比 IHttpHandler 更简单,因为您不必深入研究 POST 变量,而且如果您正在使用 MVC 站点,这也是有意义的。

  • 如果 XML 以它不介意的方式格式化,则带有 webhttp 绑定的 WCF 可以工作。但是,根据我的经验,您将有一些堆栈笨蛋作为 WCF 被杀死,从不希望完全适合您希望在线上看到的某种 XML。

  • 替代品,例如OpenRasta,在这里可以很好地工作。它确实适用于这些 POX 风格的场景,并且可以很容易地让您使用您的 xml 格式等。

就速度而言,真正要回答的问题不是“这可能是最快的吗”,而是“这够快吗?”特别是考虑到 HTTP 和远程通信的性质意味着,在大多数情况下,您可能能够创建的任何服务器端效率都无关紧要,因为请求通过网络传输所需的时间是其数百倍得到处理。如果您确实有一个相对干净的服务逻辑实现,那么您将可以很好地切换通信堆栈,直到找到最适合您的那个。

【讨论】:

  • 这将是项目中唯一的事情。没有其他aspx页面,什么都没有。实际上,我正在接收 XML 文件,对其进行处理,将其发送给第三方,等待他们的响应,然后将其发送回原始提供商。我需要能够每小时处理 10,000 个请求。
  • 嗯,我要问的问题是当前解决方案的处理方式。 10k/小时似乎是一个高管的美梦。没关系,它不在您的控制范围内——瓶颈在于 3rd 方服务。我真的会关注消息队列,因为这里的挑战实际上是如何在不阻塞事物或以其他方式调用问题的情况下处理来自第 3 方的发送/接收。
【解决方案2】:

这几乎取决于您拥有什么样的应用程序?如果是 ASP.net WebForms,您可能只有标准 Page,带有 Page_Load 方法,您可以在其中处理请求并将您喜欢的任何内容放入 HttpCurrent.HttpContex.Response 对象中。

如果是 MVC,你应该有一个带有自定义 ActionResult 的操作。

但就我而言,我认为通用处理程序 .ashx 没有任何问题。我会去的。

【讨论】:

    【解决方案3】:

    尝试“裸”回复:http://msdn.microsoft.com/en-us/library/system.servicemodel.web.webmessagebodystyle.aspx

    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare)]
    

    或者在您的情况下,如果您的请求已包装但您想要一个简单的未包装响应:

    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    

    我通常使用 WrappedRequest

    【讨论】:

      【解决方案4】:

      在你 specify it 之前,作为通用处理程序的 Ashx 没有会话。您所描述的有时称为 XML 服务。 WCF 默认允许 SOAP 和 REST 服务。我不确定您是否可以使用每个资源(消息类型)的唯一 URL,这将允许您使用 REST 服务。这意味着您的 url 看起来像 https://www.whatever.com/myservice/something ,其中某些内容将用于映射到标记为 WebInvoke 属性的操作:

      [ServiceContract]
      public interface IService
      {
          [OperationContract]
          [WebInvoke(Method = "POST", UriTemplate="Something", 
                     BodyStyle = WebMessageBodyStyle.Bare, 
                     RequestFormat = WebMessageFormat.Xml,
                     ResponseFormat = WebMessageFormat.Xml)]
          CompositeTypeMessage GetData(CompositeTypeMessage composite);
      }
      

      您也可以使用不带 REST 的原生 WCF 来定义 XML 服务,但这需要付出很多努力:

      首先您必须定义自定义绑定,其中重要部分是messageVersion=None

      <bindings>
        <customBinding>
          <binding name="XmlService">
            <textMessageEncoding messageVersion="None"/>
            <httpTransport/>
          </binding>
        </customBinding>
      </bindings>
      <services>
        <service name="XmlService.Service">
          <endpoint address="" binding="customBinding" bindingConfiguration="XmlService" contract="XmlService.IService"/>
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:8732/XmlService"/>
            </baseAddresses>
          </host>
        </service>
      </services>
      

      然后你必须定义合约并移除默认命名空间:

      [ServiceContract(Namespace = "")]
      public interface IService
      {
          [OperationContract]
          CompositeTypeMessage GetData(CompositeTypeMessage composite);
      }
      
      // Now here you can make main decission. Do you want wrapper for data
      // or not. If you don't use message contract and use data contract directly
      // each request will be wrapped in the element with the same name as operation
      // and response will be wrapped in the element with the name of operation + 
      // Response suffix. Message contract allows you defining custom wrapper name
      // or turning it off.
      [MessageContract (WrapperNamespace = "", IsWrapped = false)]
      public class CompositeTypeMessage
      {
          [MessageBodyMember(Namespace = "")]
          public CompositeType Data { get; set; }
      }
      
      [DataContract(Namespace = "")]
      public class CompositeType
      {
          bool boolValue = true;
          string stringValue = "Hello ";
      
          [DataMember]
          public bool BoolValue
          {
              get { return boolValue; }
              set { boolValue = value; }
          }
      
          [DataMember]
          public string StringValue
          {
              get { return stringValue; }
              set { stringValue = value; }
          }
      }
      

      最后一点是实现自定义IDispatchOperationSelector 行为。删除所有 SOAP 相关功能会破坏当前 WCF 选择正确操作来处理消息的能力。您必须定义一个新的,例如,根据根请求元素通过某种约定选择操作。 Here 是 MSDN 示例如何构建和使用类似的行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        相关资源
        最近更新 更多