【发布时间】:2016-04-28 14:52:48
【问题描述】:
我已经研究这个问题很长时间了,以下是我的发现和要求:
我们有两个端点:
- TCP 端点
- WebHttp 端点
通过 WebHttp 端点,我们需要支持 JSON 和 XML,但需要自定义响应格式。这是所需的格式(为清楚起见仅显示 JSON):
{
"status": "success",
"data" : {}
}
我们需要的是让每个返回的对象正常序列化并放在层次结构中的数据下。假设我们有这个OperationContract:
ObjectToBeReturned test();
而ObjectToBeReturned 是:
[DataContract]
class ObjectToBeReturned {
[DataMember]
public string A {get; set;}
[DataMember]
public string B {get; set;}
}
现在,我们希望通过TCP 直接交换ObjectToBeReturned 对象,但通过WebHttp 具有以下格式作为响应:
{
"status": "success",
"data": {
"A": "atest",
"B": "btest"
}
}
可能性1
我们考虑了两种可能性。第一个是有一个名为 Response 的对象,它将是我们所有 OperationContract 的返回对象,它将包含以下内容:
[DataContract]
class Response<T> {
[DataMember]
public string Status {get; set;}
[DataMember]
public T Data {get; set;}
}
问题是我们还需要通过 TCP 协议交换这个对象,但这不是我们的理想方案。
可能性2
我们已尝试添加自定义 EndpointBehavior 和自定义 IDispatchMessageFormatter,该自定义 IDispatchMessageFormatter 仅适用于 WebHttp 端点。
在这个类中,我们实现了以下方法:
public Message SerializeReply(
MessageVersion messageVersion,
object[] parameters,
object result)
{
var clientAcceptType = WebOperationContext.Current.IncomingRequest.Accept;
Type type = result.GetType();
var genericResponseType = typeof(Response<>);
var specificResponseType = genericResponseType.MakeGenericType(result.GetType());
var response = Activator.CreateInstance(specificResponseType, result);
Message message;
WebBodyFormatMessageProperty webBodyFormatMessageProperty;
if (clientAcceptType == "application/json")
{
message = Message.CreateMessage(messageVersion, "", response, new DataContractJsonSerializer(specificResponseType));
webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
}
else
{
message = Message.CreateMessage(messageVersion, "", response, new DataContractSerializer(specificResponseType));
webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Xml);
}
var responseMessageProperty = new HttpResponseMessageProperty
{
StatusCode = System.Net.HttpStatusCode.OK
};
message.Properties.Add(HttpResponseMessageProperty.Name, responseMessageProperty);
message.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty);
return message;
}
这似乎很有希望。该方法的问题在于,当使用DataContractSerializer 进行序列化时,我们会收到以下错误:
如果您正在使用,请考虑使用 DataContractResolver DataContractSerializer 或添加任何静态未知的类型到 已知类型的列表 - 例如,通过使用 KnownTypeAttribute 属性或通过将它们添加到传递给 序列化器。
我们真的不想在 Response 类之上列出所有已知类型,因为数量太多而且维护将是一场噩梦(当我们列出已知类型时,我们能够获取数据)。请注意,传递给响应的所有对象都将使用DataContract 属性进行修饰。
我必须提到,我们不在乎更改消息格式是否会导致在另一个 C# 项目中无法通过 ServiceReference 访问 WebHttp 端点,他们应该为此使用 TCP。
问题
基本上,我们只想自定义WebHttp的返回格式,所以问题是:
- 有没有比我们现在做的更简单的方法来实现这一点?
- 有没有办法通过
SerializeReply方法中的result参数类型告诉序列化程序 knowntype? - 我们是否应该实现一个自定义的
Serializer,它将在MessageDispatcherFormatter中调用,从而调整格式以适合我们的格式?
我们觉得我们走在正确的道路上,但缺少一些部分。
【问题讨论】:
-
KnownTypeAttribute 也可以与返回所有已知类型而不是静态列表的方法一起使用。如果您可以在运行时收集所有必要的类型(例如通过反射),也许这对您来说是一个选择。见:msdn.microsoft.com/en-us/library/ms584302%28v=vs.110%29.aspx
标签: c# wcf datacontractserializer