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

Bru*_*ant 9 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; }
}
Run Code Online (Sandbox Code Playgroud)

OperationContract类似于:

[OperationContract]
public Contract<MyResponseHeader, ResponseBody> Process(Contract<MyRequestHeader, RequestBody> data);
Run Code Online (Sandbox Code Playgroud)

代理变成如下:

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

**ResponseBody** 

response = client.Process(ref header, body);
Run Code Online (Sandbox Code Playgroud)

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

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

oɔɯ*_*ɯǝɹ 6

这里有一些奇怪的事情发生.

我试图重现你的问题,并得到以下结果(我必须标记一些类型public,并添加[DataContract]到您的标题类).

这是WSDL的视图:

WSDL

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

客户代码

这是由以下XSD引起的:

XSD

如您所见,"Header"类只生成了一个实例.

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

[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);
}
Run Code Online (Sandbox Code Playgroud)

但是这并没有解决问题,生成的客户端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);
}
Run Code Online (Sandbox Code Playgroud)

没有解决问题:

客户代码

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

[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);
}
Run Code Online (Sandbox Code Playgroud)

仍会导致RequestMeader在ResponseMessage中使用.

我认为答案就在本文档的某处:

WSDL注意事项

从使用消息协定的服务生成Web服务描述语言(WSDL)合同时,请 务必记住并非所有消息协定功能都反映在生成的WSDL中 [原文如此].请考虑以下几点:WSDL无法表达标头数组的概念.使用MessageHeaderArrayAttribute创建包含标头数组的消息时,生成的WSDL仅反映一个标头而不是数组.

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

WSDL中生成的消息类型与消息协定类型的类名具有相同的名称.

在多个操作中使用相同的消息协定时,会在WSDL文档中生成多个消息类型.通过添加数字"2","3"等使名称唯一,以供后续使用.导回WSDL时,会创建多个消息协定类型,除了名称之外,它们是相同的.