使用消息协定在请求/响应中使用不同的SOAP标头

时间:2013-05-16 03:59:38

标签: wcf

我正在构建一些具有公共标头的服务。该头部在请求中具有某种布局,并且在响应中具有不同的布局(即,存在两个类别)。

但是,当我添加引用或使用svcutil时,会在请求和响应类型中生成具有相同标头的代理。

例如:

[MessageContract]
class Contract<THeader, TBody>
{
    [MessageHeader] public THeader Header { get; set; }

    [MessageBodyMember] public TBody Body { get; set; }
}

class MyRequestHeader
{
    public string RequestorId { get; set; }
}

class MyResponseHeader
{
    public string ErrorMessage  { get; set; }
}

OperationContract类似于:

[OperationContract]
public Contract<MyResponseHeader, ResponseBody> Process(Contract<MyRequestHeader, RequestBody> data);

代理变成类似:

var client = new ...; 
var header = new MyRequestHeader(); 
var body = new RequestBody();

**ResponseBody** 

response = client.Process(ref header, body);

如您所见,标题(Request)作为ref传递;这可能意味着WCF在请求和响应中具有相同的标头。并且MyResponseHeader消失了。

任何人都可以对这个问题有所了解吗?

1 个答案:

答案 0 :(得分:6)

这里有一些奇怪的事情。

我尝试重现您的问题,并得到以下结果(我必须标记某些类型public,并将[DataContract]添加到您的标题类中。

以下是WSDL的视图:

WSDL

生成的代码(svcutil 4.0.30319.18046)也在响应消息中使用MyRequestHeader

Client code

这是由以下XSD引起的:

XSD

正如您所看到的,只有一个实例为&#34; Header&#34;类。

我尝试为泛型类创建类型,如下所示:

[MessageContract]
public abstract class Contract<THeader, TBody>
{
    [MessageHeader]
    public THeader Header { get; set; }

    [MessageBodyMember]
    public TBody Body { get; set; }
}

[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
    public string RequestorId { get; set; }
}

[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
    public string ErrorMessage { get; set; }
}

[MessageContract]
public class RequestContract : Contract<MyRequestHeader, string>
{ }

[MessageContract]
public class ResponseContract : Contract<MyResponseHeader, string>
{ }

[ServiceContract]
public interface IService1
{
    [OperationContract]
    ResponseContract Process(RequestContract data);
}

但是这并没有解决问题,生成的客户端ResponseContract仍然是使用RequestHeader类型的Header生成的。

甚至更改服务代码以使用两种不同的消息合同:

[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
    public string RequestorId { get; set; }
}

[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
    public string ErrorMessage { get; set; }
}

[MessageContract]
public class RequestContract<TBody>
{
    [MessageHeader]
    public MyRequestHeader Header { get; set; }

    [MessageBodyMember]
    public TBody Body { get; set; }
}

[MessageContract]
public class ResponseContract<TBody>
{
    [MessageHeader]
    public MyResponseHeader Header { get; set; }

    [MessageBodyMember]
    public TBody Body { get; set; }
}

[ServiceContract]
public interface IService1
{
    [OperationContract]
    ResponseContract<string> Process(RequestContract<string> data);
}

无法解决问题:

Client code

甚至删除所有共享继承和泛型,如下所示:

[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
    public string RequestorId { get; set; }
}

[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
    public string ErrorMessage { get; set; }
}

[MessageContract(WrapperName="RequestMessage")]
public class RequestContract
{
    [MessageHeader]
    public MyRequestHeader Header { get; set; }

    [MessageBodyMember]
    public string Body { get; set; }
}

[MessageContract(WrapperName = "ResponseMessage")]
public class ResponseContract
{
    [MessageHeader]
    public MyResponseHeader Header { get; set; }

    [MessageBodyMember]
    public string Body { get; set; }
}

[ServiceContract]
public interface IService1
{
    [OperationContract]
    ResponseContract Process(RequestContract data);
}

仍会导致在ResponseMessage中使用RequestHeader。

我认为答案在于this documentation

  

WSDL注意事项

     

生成Web服务描述时   来自使用消息契约的服务的语言(WSDL)契约,   重要的是要记住并非所有的邮件合同功能都是   反映在生成的WSDL中 [原文如此]。请考虑以下几点:WSDL   无法表达标题数组的概念。创建时   带有一个标题数组的消息使用   MessageHeaderArrayAttribute,生成的WSDL只反映一个   标题而不是数组。

     

生成的WSDL文档可能无法反映某些保护级别   信息。

     

WSDL中生成的消息类型与类具有相同的名称   消息合同类型的名称。

     

在多个操作中使用相同的消息合同时,多个   消息类型在WSDL文档中生成。这些名字都是   通过添加数字&#34; 2&#34;,&#34; 3&#34;等来进行后续使用。   导回WSDL时,有多种消息协定类型   创建并且除了名字之外完全相同。