WCF,SOAP,Plain Old XML

时间:2011-04-11 18:25:15

标签: asp.net xml wcf web-services

我对Web服务世界中的一些事情感到非常困惑,我希望有人可以向我解释。

这就是我想要的:我想将HTTP文档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-60k个传入请求,但在12月期间每小时最多可处理10,000个请求。我们希望增长,但为此,我将在Rackspace中添加负载均衡器和更多机器。

我们目前的这项服务提供商在这段时间内不堪重负,因此我们错过了很多钱。因此,我的代理将在正面执行我们最基本的检查之一(对每小时更新的数据库进行重复检查),这将清除我们必须发送给当前提供商的75%的流量。当前的提供商为我们承销这些线索,我不会替换它,只是添加一个网守以减轻其服务器上的压力。

感谢所有帮助。我最近在StackOverflow上询问了一系列Web服务问题,试图了解我将面临的许多问题。

4 个答案:

答案 0 :(得分:2)

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

谁告诉你IHttpHandlers携带会话代码是错误的 - 除非你explicitly enable session state,否则他们不会。现在,它确实具有ASP.NET管道开销,但除非您使用一些疯狂的边缘轻量级Web套接字服务器,否则这并不重要,因为任何形式的IIS托管服务都会有类似的开销。而且,如果这是一个面向公众的互联网服务,IIS会为您做一些你想要的整洁的事情。像SSL,请求记录和与其他东西操作的集成之类的东西用来观察事物。

至于如何到达那里,因为你有一个定义的格式ASMX和默认(SOAP)行为的WCF根据定义。为了灵活性,应该单独实现服务的实际逻辑,使外部位负责接收请求,从xml转换并将响应作为格式正确的XML发回。

这为您提供了一些选择:

  • 可能最简单的,特别是如果这是一个现有的.NET站点,将是一个自定义的IHttpHandler。你需要在堆栈中比在其他地方低很多但是如果这真的采用了一组XML并且吐出响应,那么工作并非不可克服。一个很大的优点是你可以对输出端进行有限的控制,所以如果你有一个长期运行的任务,你可以很容易地传输响应。

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

  • 如果XML以不介意的方式进行格式化,那么使用webhttp绑定的WCF就可以工作。但是根据我的经验,你会有一些堆栈boogeymen要杀死,根据我的经验,它永远不想完全适合你想要在线上看到的某种XML。

  • 替代方案,例如OpenRasta,在这里可以很好地运作。它真的适用于这些类型的POX风格场景,并且很容易让你使用你的xml格式等。

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

答案 1 :(得分:1)

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

如果是MVC,则应该使用自定义ActionResult进行操作。

但至于我,我没有看到Generic Handlers .ashx有什么问题。我会配合它。

答案 2 :(得分:1)

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

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

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

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

我通常使用WrappedRequest

答案 3 :(得分:1)

作为通用处理程序的Ashx在您specify it之前没有会话。您描述的内容有时称为XML服务。默认情况下,WCF允许SOAP和REST服务。我不确定您是否可以使用每个资源(消息类型)的唯一URL,这将允许您使用REST服务。这意味着您的网址看起来像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示例如何构建和使用类似的行为。