WCF 4 - SOAP和REST终结点

8
我在考虑使用WCF REST服务应用程序模板来托管所有的RESTful web服务,但是我也想能够使用SOAP端点公开我的WCF服务。我可以很容易地在WCF 4中通过以下示例使我的WCF RESTful服务工作:http://christopherdeweese.com/blog2/post/drop-the-soap-wcf-rest-and-pretty-uris-in-net-4。这是否可行?我想应该有一种方法在Global.asax中连接其他端点,并指定是否使用basicHttpBinding。我需要不使用WCF REST服务应用程序模板并创建标准的服务应用程序,并通过配置将其全部连接起来吗?感谢任何帮助。

你尝试过为那个模板添加一个“normal”服务吗? - H H
你能澄清一下你是想提供两个端点,SOAP和REST呢,还是想要一个发送SOAP的RESTful服务?如果你指的是前者,我的答案会改变,因为我认为你指的是后者。 - Aliostad
我的目标是拥有一个具有两个终结点的单一WCF服务,分别是SOAP和REST。 - Brandon
3个回答

6

虽然在大多数情况下我不会混合使用REST和SOAP端点,但我同意在某些情况下这是必要的。回答这个问题:是的,可以混合使用它们。您可以使用两个选项:

在Global.asax.cs中定义REST端点路由的调用

`RouteTable.Routes.Add(new ServiceRoute("Service1", new WebServiceHostFactory(),   typeof(Service1)))` 

定义了一个服务,其地址为/Service1。您可以添加一个新的“服务”,使用相同的服务实现,但使用不同的服务主机工厂(而不是使用定义REST端点的WebServiceHostFactory):

public class SoapServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
        ServiceMetadataBehavior smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (smb == null)
        {
            smb = new ServiceMetadataBehavior();
            host.Description.Behaviors.Add(smb);
        }

        smb.HttpGetEnabled = true;
        host.AddServiceEndpoint(serviceType, new BasicHttpBinding(), "soap");
        return host;
    }
}

在 global.asax.cs 文件中的 RegisterRoutes 方法:

    private void RegisterRoutes()
    {
        // Edit the base address of Service1 by replacing the "Service1" string below
        RouteTable.Routes.Add(new ServiceRoute("Service1", new WebServiceHostFactory(), typeof(Service1)));

        RouteTable.Routes.Add(new ServiceRoute("SoapService", new SoapServiceHostFactory(), typeof(Service1)));
    }
  • 如果您确实想要一个具有两个端点的“逻辑”服务(我不建议这样做,因为之前的方法已经足够简单),您可以再次创建自定义ServiceHostFactory,然后在该工厂中添加两个端点:一个用于REST(使用WebHttpBinding/WebHttpBehavior),另一个用于SOAP(例如使用BasicHttpBinding)。

这实际上非常完美,因为我有一个Global.asax文件,我正在其中连接我的REST服务。 - Brandon
我遇到了一个错误:“无法将该值添加到集合中,因为该集合已经包含了同一类型的项:'System.ServiceModel.Description.ServiceMetadataBehavior'。该集合仅支持每种类型的一个实例。”这是怎么回事? - fiberOptics
在这个例子中,SoapServiceHostFactory 添加了一个 ServiceMetadataBehavior 到描述中,但在你的情况下,你已经有它了(可能来自配置中的某个默认端点)。我更新了代码片段,使其即使在这种情况下也能正常工作。 - carlosfigueira

2

我不得不给carlosfigueira的工厂添加一个构造函数,这样它就可以从接口中构建终端而不是服务本身:

public class SoapServiceHostFactory : ServiceHostFactory
{
    private Type serviceInterfaceType;

    public SoapServiceHostFactory(Type serviceInterfaceType) 
    {
        this.serviceInterfaceType = serviceInterfaceType;
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.AddServiceEndpoint(serviceInterfaceType, new BasicHttpBinding(), "soap");
        return host;
    }
}

谢谢!我也遇到了一个异常,类似于“合同类型 MyClassSvc 没有带有 ServiceContractAttribute 属性。为了定义有效的合同,指定的类型(合同接口或服务类)必须带有 ServiceContractAttribute 属性。”很奇怪,因为我的服务继承自该接口,而该接口具有该属性。是框架的 bug 吗? - DeepSpace101

0

我有一个正在运行的 Web 服务,客户端需要同时使用 SOAP 和 REST 访问。您可以使用 WebGet 和 WebInvoke 属性定义您的 REST URL 模板。

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
    RS DoSomething(RQ request); 
}

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service : IService
{
    public RS DoSomething(RQ rq)
    {
        return new RS(rq);
    }
}

然后只需根据配置要求映射端点即可

  <system.serviceModel>
    <services>
      <service name="Service" behaviorConfiguration="defaultBehavior">
        <endpoint address="soap11" binding="basicHttpBinding" contract="IService" behaviorConfiguration="soapBehavior" />
        <endpoint address="rest" binding="webHttpBinding" contract="IService" behaviorConfiguration="restBehavior"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="restBehavior">
          <webHttp faultExceptionEnabled="true" />
        </behavior>
        <behavior name="soapBehavior">
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="defaultBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true"  />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接