我正在构建一些具有通用标头的服务.此标头在请求中具有某种布局,在响应中具有不同的布局(即,有两个类).
但是,当我添加引用或使用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消失了.
任何人都可以对这个问题有所了解吗?
这里有一些奇怪的事情发生.
我试图重现你的问题,并得到以下结果(我必须标记一些类型public,并添加[DataContract]到您的标题类).
这是WSDL的视图:

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

这是由以下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时,会创建多个消息协定类型,除了名称之外,它们是相同的.