我正在使用Framework 3.5,并希望有一个可以接收不同类型的请求/响应对象的ServiceContract,是否可能?
答案 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>
您的服务端代码很简单,需要确定哪些“选择”对象存在,以确定如何处理该参数。