C#WCF全球名称空间-皇家邮政

C#WCF全球名称空间-皇家邮政,c#,soap,C#,Soap,我有一个WCFSOAP客户端,它正在生成一个请求。服务器拒绝此请求,因为请求无效。我已经使用SOAPUI将其追溯到名称空间,但无法弄清楚如何让客户端生成所需的结果 客户机是作为来自wsdl的web服务引用生成的,并且正在生成以下SOAP消息 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header></s:Header> <s:Body xmlns:xsi

我有一个WCFSOAP客户端,它正在生成一个请求。服务器拒绝此请求,因为请求无效。我已经使用SOAPUI将其追溯到名称空间,但无法弄清楚如何让客户端生成所需的结果

客户机是作为来自wsdl的web服务引用生成的,并且正在生成以下SOAP消息

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header></s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <createShipmentRequest xmlns="http://www.royalmailgroup.com/api/ship/V2">
      <integrationHeader>
        <dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2015-07-23</dateTime>
        <version xmlns="http://www.royalmailgroup.com/integration/core/V1">2</version>
        <identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
          <applicationId>some random number</applicationId>
          <transactionId>some reference number</transactionId>
        </identification>
      </integrationHeader>
    </createShipmentRequest>
  </s:Body>
</s:Envelope>

因此,我需要创建一个自定义MessageFormatter,并将其作为一种行为附加到客户端操作

对于其他需要这样做的人,您需要3个文件

首先,创建一个实现消息的自定义消息类。在OnWriteStartInvelope方法中,您可以在信封中添加/定义所需的名称空间

class RoyalMailMessage: Message {
  private readonly Message message;

  public RoyalMailMessage(Message message) {
    this.message = message;
  }
  public override MessageHeaders Headers {
    get {
      return this.message.Headers;
    }
  }
  public override MessageProperties Properties {
    get {
      return this.message.Properties;
    }
  }
  public override MessageVersion Version {
    get {
      return this.message.Version;
    }
  }
  protected override void OnWriteStartBody(XmlDictionaryWriter writer) {
    writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");
  }
  protected override void OnWriteBodyContents(XmlDictionaryWriter writer) {
    this.message.WriteBodyContents(writer);
  }
  protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) {
    writer.WriteStartElement("s", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
    writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
    writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
    writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
    writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");

  }
}
然后创建一个实现IClientMessageFormatter的自定义类。这利用了我们在上面定义的Message类来处理客户机发出的传出请求

public class RoyalMailMessageFormatter: IClientMessageFormatter {
  private readonly IClientMessageFormatter formatter;

  public RoyalMailMessageFormatter(IClientMessageFormatter formatter) {
    this.formatter = formatter;
  }

  public object DeserializeReply(Message message, object[] parameters) {
    return this.formatter.DeserializeReply(message, parameters);
  }

  public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) {
    var message = this.formatter.SerializeRequest(messageVersion, parameters);
    return new RoyalMailMessage(message);
  }
}
然后,我们需要创建一个实现IOperationBehavior的自定义类。这是必需的,因此我们可以将自定义消息格式化程序作为一种行为附加到服务操作中

class RoyalMailIEndpointBehavior: IOperationBehavior {

  public RoyalMailIEndpointBehavior() {}

  public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy) {
    IClientMessageFormatter currentFormatter = proxy.Formatter;
    proxy.Formatter = new RoyalMailMessageFormatter(currentFormatter);
  }

  public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {

  }

  public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) {

  }

  public void Validate(OperationDescription operationDescription) {

  }

}
最后,我们需要将自定义IOOperation行为添加到WCF生成的所有服务操作中

private shippingAPIPortTypeClient GetProxy() {

  BasicHttpBinding myBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
  myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

  shippingClient = new shippingAPIPortTypeClient(myBinding, new EndpointAddress(new Uri(shippingClientSandboxEndpoint), EndpointIdentity.CreateDnsIdentity("api.royalmail.com"), new AddressHeaderCollection()));
  shippingClient.ClientCredentials.ClientCertificate.Certificate = certificate;

  foreach(OperationDescription od in shippingClient.Endpoint.Contract.Operations) {
    od.Behaviors.Add(new RoyalMailIEndpointBehavior());
  }
  return shippingClient;
}
名称空间现在应该在SOAP信封中,元素都使用正确的前缀,这给了我们类似的东西

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://www.royalmailgroup.com/api/ship/V2" xmlns:v1="http://www.royalmailgroup.com/integration/core/V1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <s:Header></s:Header>
  <s:Body>
    <v2:createShipmentRequest>
      <v2:integrationHeader>
        <v1:dateTime>2015-07-23T20:37:07.937+01:00</v1:dateTime>
        <v1:version>2</v1:version>
        <v1:identification>
          <v1:applicationId>SOME RANDOM ID</v1:applicationId>
          <v1:transactionId>SOME RANDOM ID</v1:transactionId>
        </v1:identification>
      </v2:integrationHeader>
    </v2:createShipmentRequest>
  </s:Body>
</s:Envelope>

2015-07-23T20:37:07.937+01:00
2.
一些随机ID
一些随机ID

我刚刚遇到了与皇家邮政完全相同的恼人问题。浪费时间弄明白他们的服务根本不遵守XML标准。感谢发布您的解决方案-我将试用。您从哪里获得shippingAPIPortTypeClient?@ReiA.Banaag该客户端是使用visual studio作为Web服务引用生成的。基本上,您可以创建一个新的web服务并浏览到包含Royal Mail API WSDL文件的目录。然后VisualStudio将为您创建所有类和一个客户端。看一看guide@Ash我已经添加了服务,但问题是shippingAPIPortType或shippingAPIPortTypeClient部分代码无效。虽然如果我们从参考资料中进行检查,我可以从那里找到它,但我无法参考该代码。@ReiA.Banaag可能值得打开一个新问题,显示您的完整代码。如果您有生成的类,那么听起来您没有将它们包含在您希望使用它们的类中。
private shippingAPIPortTypeClient GetProxy() {

  BasicHttpBinding myBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
  myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

  shippingClient = new shippingAPIPortTypeClient(myBinding, new EndpointAddress(new Uri(shippingClientSandboxEndpoint), EndpointIdentity.CreateDnsIdentity("api.royalmail.com"), new AddressHeaderCollection()));
  shippingClient.ClientCredentials.ClientCertificate.Certificate = certificate;

  foreach(OperationDescription od in shippingClient.Endpoint.Contract.Operations) {
    od.Behaviors.Add(new RoyalMailIEndpointBehavior());
  }
  return shippingClient;
}
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://www.royalmailgroup.com/api/ship/V2" xmlns:v1="http://www.royalmailgroup.com/integration/core/V1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <s:Header></s:Header>
  <s:Body>
    <v2:createShipmentRequest>
      <v2:integrationHeader>
        <v1:dateTime>2015-07-23T20:37:07.937+01:00</v1:dateTime>
        <v1:version>2</v1:version>
        <v1:identification>
          <v1:applicationId>SOME RANDOM ID</v1:applicationId>
          <v1:transactionId>SOME RANDOM ID</v1:transactionId>
        </v1:identification>
      </v2:integrationHeader>
    </v2:createShipmentRequest>
  </s:Body>
</s:Envelope>