WCF服务端点采用不同的请求/响应

时间:2009-08-25 13:03:44

标签: wcf

我正在使用Framework 3.5,并希望有一个可以接收不同类型的请求/响应对象的ServiceContract,是否可能?

3 个答案:

答案 0 :(得分:0)

是的,如果你真的想,你可以处理通用的Message类型作为参数和/或返回值。

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    Message GetData();

    [OperationContract]
    void PutData(Message m);
}

请参阅MSDN documentation中的详细信息。

然而,这意味着你必须手动执行大量的XML操作巫术并自己处理大量的东西,如果你使用强类型的[DataContract]类型,那么这些东西将免费处理。

你能做到吗?是。你应该这样做吗?那么,取决于你真正想要它多少! : - )

马克

答案 1 :(得分:0)

正如Marc所说,你有一份服务合同,它接受了Message参数。但是您不必手动构建XML,而是可以在共享DLL中共享接口和消息契约,这对于服务器和客户端都是通用的。

例如,我有一个软件接收消息,因为规范说它必须。我有一个通用程序集,其中包含接口,所有潜在的请求和响应消息以及命名空间的公共静态字符串。因此,对于其中一个操作,它看起来像下面的

[ServiceContract(
    Namespace = Constants.Service.Namespace.Location, 
    Name = "ServiceMonitorContract")]
public interface IMonitor
{
    [OperationContract(
        Action = Constants.Service.Actions.GetTasksRequest,
        ReplyAction = Constants.Service.Actions.GetTasksResponse)]
    Message GetTasks(Message request);
}

我的消息合约看起来像

[MessageContract(IsWrapped = true, 
                 WrapperNamespace = Constants.Messages.Namespace.Location)]
public sealed class GetTasksRequest 
{
    ....
}

要获得与服务的连接,请执行以下操作

private static IMonitor GetChannelToWebService()
{
    EndpointAddress endpoint = new EndpointAddress("http://example/service.svc");
    ChannelFactory<IMonitor> channelFactory = 
        new ChannelFactory<IMonitor>(new BasicHttpBinding(), endpoint);

    return channelFactory.CreateChannel();
} 

然后我可以使用共享消息合同

执行以下操作
IMonitor channel = GetChannelToWebService();

// Create the GetTasksRequest message
GetTasksRequest getTasksRequest = new GetTasksRequest();
// Set the various properties on the message

// Convert it to a strongly type message
TypedMessageConverter requestMessageConverter = TypedMessageConverter.Create(
    typeof(GetTasksRequest),
    Constants.Service.Actions.GetTasksRequest,
    Constants.Service.Namespace.Location);
Message request = requestMessageConverter.ToMessage(
                      getTasksRequest, 
                      MessageVersion.Soap11);

// Send it and get the response.
Message response = channel.GetTasks(request);

// Check for SOAP faults
if (response.IsFault)
{
    MessageFault fault = MessageFault.CreateFault(response, int.MaxValue);
    // React accordingly        
}

TypedMessageConverter responseMessageConverter = TypedMessageConverter.Create(
    typeof(GetTasksResponse),
    Constants.Service.Actions.GetTasksResponse,
    Constants.Service.Namespace.Location);
GetTasksResponse getTasksResponse = 
    responseMessageConverter.FromMessage(response) as GetTasksResponse;

((IClientChannel)channel).Close();

需要注意的一点是,客户端不会抛出错误,必须手动检查Message对象作为响应,并从样本中看到相应的行为。

服务器端我使用TypedMessageConvertor

做了很多相同的事情
// Convert the inbound message to a GetTasksRequest.
TypedMessageConverter getTasksMessageConverter = TypedMessageConverter.Create(
    typeof(GetTasksRequest),
    Constants.Service.Actions.GetTasksRequest,
    Constants.Service.Namespace.Location);
GetTasksRequest getTasksMessage = 
    getTasksMessageConverter.FromMessage(request) as GetTasksRequest;

// Validate the message is the correct type.
if (getTasksMessage == null)
{
    throw FaultHelper.UnknownMessageTypeFault();
}

// Do my thing

GetTasksResponse responseMessage = new GetTasksResponse();

// Set appropriate response bits in the responseMessage

TypedMessageConverter responseConverter = TypedMessageConverter.Create(
    typeof(GetTasksResponse),
    Constants.Service.Actions.GetTasksResponse,
    Constants.Service.Namespace.Location);
Message response = responseConverter.ToMessage(responseMessage, request.Version);
response.Headers.RelatesTo = request.Headers.MessageId;

return response;

请不要忘记将RelatesTo标头设置为请求标头中的MessageId

答案 2 :(得分:0)

您也可以传递XElement。这使请求对象可以灵活地包含您选择的任何内容。

您最好指定一个XSD,其中包含许多“choice”元素,每个元素都指定一种不同的请求类型。

<xs:element name="request">
  <xs:complexType>
    <xs:choice>
      <xs:element name="requestType1"/>
          ....
      </xs:element>
      <xs:element name="requestType2"/>
          ....
      </xs:element>
    </xs:choice>
  </xs:complexType>
</xs:element>

您的服务端代码很简单,需要确定哪些“选择”对象存在,以确定如何处理该参数。