0

我试图让我的 WCF 服务具有可以通过代理客户端和 REST 调用调用的操作,我正在使用以下配置:

<services>
  <service behaviorConfiguration="SecureBehavior" name="Payment">
    <endpoint address="" binding="wsHttpBinding"  bindingConfiguration="secureWS" contract="IPayment"/>
    <endpoint address="rest" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="IPayment"/>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
  <bindings>
    <mexHttpBinding>
      <binding name="userMex"/>
    </mexHttpBinding>
    <wsHttpBinding>
      <binding name="secureWS">
        <security mode="Message">
          <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
        </security>
      </binding>
      <binding name="publicWS">
        <security mode="None"/>
      </binding>
    </wsHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="SecureBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
        <serviceCredentials>
          <windowsAuthentication allowAnonymousLogons="false"/>
        </serviceCredentials>
      </behavior>
      <behavior name="PublicBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
        <serviceCredentials>
          <windowsAuthentication allowAnonymousLogons="true"/>
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="webBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
</services>

这是我的代码:

[ServiceContract]
public interface IPayment
{
    [OperationContract]
    PaymentResult Finalize(string TransactionID, string CertificatePath);

    [OperationContract]
    [WebGet(UriTemplate = "rest")]
    System.IO.Stream GetPayment();
}

现在,每当我运行我的服务时,我都会收到此错误:

合约“IPayment”的“Finalize”操作指定要序列化的多个请求主体参数,而无需任何包装器元素。最多一个 body 参数可以在没有包装元素的情况下被序列化。删除额外的正文参数或将 WebGetAttribute/WebInvokeAttribute 上的 BodyStyle 属性设置为 Wrapped。

在这里,我希望仅通过 .NET 客户端调用 Finalize 操作,并通过任何浏览器调用 GetPayment 操作。

4

1 回答 1

0

如果您不希望从通过 webhttp 端点连接的客户端调用您的 Finalize 方法,并且您不希望从通过 wshttp 连接的客户端调用 GetPayments,您可以简单地将合同一分为二。

假设您在 IIS 中托管,您可能需要做一些小技巧来确保它正常工作。让我举一个例子,使用问题中的细节......

首先是这两个服务的代码......

[ServiceContract]
public interface IPayment
{
    [OperationContract]
    [WebGet(UriTemplate = "rest")]
    System.IO.Stream GetPayment();
}

[DataContract]
public class PaymentResult
{
}

[ServiceContract]
public interface IMakePayment
{
    [OperationContract]
    PaymentResult Finalize(string TransactionID, string CertificatePath);
}

// Maybe you really should have the two services separate but if you do
// want to implement them both in a single class you can do this
public abstract class PaymentBase : IMakePayment, IPayment
{
    // ... Implement both interfaces here
    public PaymentResult Finalize(string TransactionID, string CertificatePath)
    {
        return null;
    }

    public System.IO.Stream GetPayment()
    {
        return null;
    }
}

public class MakePayment : PaymentBase
{
    // Empty
}

public class Payment : PaymentBase
{
    // Empty
}

现在创建两个 .svc 文件,如下所示:

MakePayment.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WebApplication1.MakePayment"  %>

付款.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WebApplication1.Payment" %>

最后是 system.servicemodel 配置:

<system.serviceModel>
  <services>      
    <service behaviorConfiguration="SecureBehavior" name="WebApplication1.MakePayment">        
      <endpoint binding="wsHttpBinding" bindingConfiguration="secureWS" contract="WebApplication1.IMakePayment"/>
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" bindingConfiguration="userMex"/>
    </service>
    <service behaviorConfiguration="PublicBehavior" name="WebApplication1.Payment">
      <endpoint binding="webHttpBinding" behaviorConfiguration="webBehavior" bindingConfiguration="publicWS" contract="WebApplication1.IPayment"/>
    </service>      
  </services>
  <bindings>
    <mexHttpBinding>
      <binding name="userMex"/>
    </mexHttpBinding>
    <wsHttpBinding>
      <binding name="secureWS">
        <security mode="Message">
          <message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
        </security>
      </binding>
    </wsHttpBinding>
    <webHttpBinding>
      <binding name="publicWS">
        <security mode="None"/>
      </binding>
    </webHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="SecureBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
        <serviceCredentials>
          <windowsAuthentication allowAnonymousLogons="false"/>
        </serviceCredentials>
      </behavior>
      <behavior name="PublicBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
        <serviceCredentials>
          <windowsAuthentication allowAnonymousLogons="true"/>
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="webBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

你去 - 如果你连接到 /MakePayment.svc,你将通过 WSHTTP 连接并能够调用 FinalizePayment,如果你转到 /Payments.svc/rest,它将调用 GetPayment 方法,你将在其中返回一个流。

于 2012-04-23T19:41:56.110 回答