9

我正在构建一些具有共同标头的服务。这个头在请求中有一定的布局,在响应中有不同的布局(即有两个类)。

但是,当我添加引用或使用 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 消失了。

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

4

1 回答 1

6

There is something strange going on here.

I tried to reproduce your problem, and got the following results (i had to mark some types public, and added [DataContract] to your header classes).

Here is a view of the WSDL:

WSDL

The generated code (svcutil 4.0.30319.18046) uses MyRequestHeader in the Response message as well:

Client code

This is caused by the following XSD:

XSD

As you can see there is only one instance generated for the "Header" class.

I tried creating types for the generic classes, as follows:

[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);
}

But that did not fix the problem, the generated client ResponseContract still is generated using a Header of type RequestHeader.

Even changing the service code to use two diffrent message contracts:

[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);
}

does not solve the problem:

Client code

Even removing all shared inheritance and generics as follows:

[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);
}

still results in the RequestHeader being used in the ResponseMessage.

I think the answer lies somewhere in this documentation:

WSDL Considerations

When generating a Web Services Description Language (WSDL) contract from a service that uses message contracts, it is important to remember that not all message contract features are reflected in the resulting WSDL [sic]. Consider the following points: WSDL cannot express the concept of an array of headers. When creating messages with an array of headers using the MessageHeaderArrayAttribute, the resulting WSDL reflects only one header instead of the array.

The resulting WSDL document may not reflect some protection-level information.

The message type generated in the WSDL has the same name as the class name of the message contract type.

When using the same message contract in multiple operations, multiple message types are generated in the WSDL document. The names are made unique by adding the numbers "2", "3", and so on, for subsequent uses. When importing back the WSDL, multiple message contract types are created and are identical except for their names.

于 2013-05-19T10:01:15.140 回答