- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经研究这个问题很长时间了,以下是我的发现和要求:
我们有两个端点:
通过 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 协议(protocol)交换这个对象,但这不是我们理想的场景。
可能性2
我们尝试添加一个自定义 EndpointBehavior
和一个自定义 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
进行序列化时,我们会收到以下错误:
Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
我们真的不想在 Response 类之上列出所有已知类型,因为数量太多而且维护将是一场噩梦(当我们列出已知类型时,我们能够获取数据)。请注意,传递给响应的所有对象都将使用 DataContract
属性进行修饰。
我必须指出,我们不关心更改消息格式是否会导致无法通过另一个 C# 项目中的 ServiceReference
访问 WebHttp
端点,他们应该为此使用 TCP
。
问题
基本上,我们只想自定义WebHttp的返回格式,所以问题是:
SerializeReply
方法中的 result
参数类型告诉序列化程序已知类型?Serializer
,它将在 MessageDispatcherFormatter
中调用,从而调整格式以适应我们的格式?我们觉得我们走在正确的道路上,但有些地方缺失了。
最佳答案
您几乎走在正确的轨道上 - 拥有仅适用于 JSON 端点的端点行为无疑是正确的选择。但是,您可以使用消息检查器,它比格式化程序简单一些。在检查器上,您可以获取现有响应(如果它是 JSON 响应)并使用您的包装对象包装内容。
请注意,WCF 内部结构都是基于 XML 的,因此您需要使用 Mapping Between JSON and XML ,但这并不太复杂。
下面的代码显示了这个场景的实现。
public class StackOverflow_36918281
{
[DataContract] public class ObjectToBeReturned
{
[DataMember]
public string A { get; set; }
[DataMember]
public string B { get; set; }
}
[ServiceContract]
public interface ITest
{
[OperationContract, WebGet(ResponseFormat = WebMessageFormat.Json)]
ObjectToBeReturned Test();
}
public class Service : ITest
{
public ObjectToBeReturned Test()
{
return new ObjectToBeReturned { A = "atest", B = "btest" };
}
}
public class MyJsonWrapperInspector : IEndpointBehavior, IDispatchMessageInspector
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
object propValue;
if (reply.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out propValue) &&
((WebBodyFormatMessageProperty)propValue).Format == WebContentFormat.Json)
{
XmlDocument doc = new XmlDocument();
doc.Load(reply.GetReaderAtBodyContents());
var newRoot = doc.CreateElement("root");
SetTypeAttribute(doc, newRoot, "object");
var status = doc.CreateElement("status");
SetTypeAttribute(doc, status, "string");
status.AppendChild(doc.CreateTextNode("success"));
newRoot.AppendChild(status);
var newData = doc.CreateElement("data");
SetTypeAttribute(doc, newData, "object");
newRoot.AppendChild(newData);
var data = doc.DocumentElement;
var toCopy = new List<XmlNode>();
foreach (XmlNode child in data.ChildNodes)
{
toCopy.Add(child);
}
foreach (var child in toCopy)
{
newData.AppendChild(child);
}
Console.WriteLine(newRoot.OuterXml);
var newReply = Message.CreateMessage(reply.Version, reply.Headers.Action, new XmlNodeReader(newRoot));
foreach (var propName in reply.Properties.Keys)
{
newReply.Properties.Add(propName, reply.Properties[propName]);
}
reply = newReply;
}
}
private void SetTypeAttribute(XmlDocument doc, XmlElement element, string value)
{
var attr = element.Attributes["type"];
if (attr == null)
{
attr = doc.CreateAttribute("type");
attr.Value = value;
element.Attributes.Append(attr);
}
else
{
attr.Value = value;
}
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
string baseAddressTcp = "net.tcp://" + Environment.MachineName + ":8888/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress), new Uri(baseAddressTcp));
var ep1 = host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(), "");
var ep2 = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
ep2.EndpointBehaviors.Add(new WebHttpBehavior());
ep2.EndpointBehaviors.Add(new MyJsonWrapperInspector());
host.Open();
Console.WriteLine("Host opened");
Console.WriteLine("TCP:");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new NetTcpBinding(), new EndpointAddress(baseAddressTcp));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.Test());
((IClientChannel)proxy).Close();
factory.Close();
Console.WriteLine();
Console.WriteLine("Web:");
WebClient c = new WebClient();
Console.WriteLine(c.DownloadString(baseAddress + "/Test"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
关于c# - 仅针对 webHttpBinding 更改 XML 和 JSON 中的响应输出格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36918281/
SO亲爱的 friend 们: 2014 年 3 月 18 日。我正在处理一种情况,在使用 ng-repeat 时,数组内的元素(我从 Json 字符串中获取)更改了原始顺序。 需要明确的是,数组中的
有很多问题询问如何在 JavaScript 单击处理程序中更改 div 的类,例如,此处:Change Div style onclick .我理解得很好(只需更改 .className),并且它有效
我从access导入了一个数据库到mysql,但其中一个表的列名“股数”带有空格,但我尝试更改、替换甚至删除列名,但失败了。任何人都可以帮助解决这一问题 String UpdateQuary = "U
我正在做一个随机的学校元素。 目前,我有一个包含两个 CSS 的页面。一种用于正常 View ,一种用于残障人士 View 。 此页面还包括两个按钮,它们将更改使用的样式表。 function c
我需要使用 javascript 更改 HTML 元素中的文本,但我不知道该怎么做。 ¿有什么帮助吗? 我把它定义成这样: Text I want to change. 我正在尝试这样做: docum
我在它自己的文件 nav_bar.shtml 中有一个主导航栏,每个其他页面都包含该导航栏。这个菜单栏是一个 jQuery 菜单栏(ApyCom 是销售这些导航栏的公司的名称)。导航栏上的元素如何确定
我正在摆弄我的代码,并开始想知道这个变化是否来自: if(array[index] == 0) 对此: if(!array[index] != 0) 可能会影响任何代码,或者它只是做同样的事情而我不需
我一直在想办法调整控制台窗口的大小。这是我正在使用的函数的代码: #include #include #define WIDTH 70 #define HEIGHT 35 HANDLE wHnd;
我有很多情况会导致相同的消息框警报。 有没有比做几个 if 语句更简单/更好的解决方案? PRODUCTS BOX1 BOX2 BOX3
我有一个包含这些元素的 XELEMENT B Bob Petier 19310227 1 我想像这样转换前缀。 B Bob Pet
我使用 MySQL 5.6 遇到了这种情况: 此查询有效并返回预期结果: select * from some_table where a = 'b' and metadata->>"$.countr
我想知道是否有人知道可以检测 R 中日期列格式的任何中断的包或函数,即检测日期向量格式更改的位置,例如: 11/2/90 12/2/90 . . . 15/Feb/1990 16/Feb/1990 .
我希望能够在小部件显示后更改 GtkButton 的标签 char *ButtonStance == "Connect"; GtkWidget *EntryButton = gtk_button_ne
我正在使用 Altera DE2 FPGA 开发板并尝试使用 SD 卡端口和音频线路输出。我正在使用 VHDL 和 C 进行编程,但由于缺乏经验/知识,我在 C 部分遇到了困难。 目前,我可以从 SD
注意到这个链接后: http://www.newscientist.com/blogs/nstv/2010/12/best-videos-of-2010-progress-bar-illusion.h
我想知道在某些情况下,即使剧本任务已成功执行并且 ok=2,ansible 也会显示“changed=0”。使用 Rest API 和 uri 模块时会发生这种情况。我试图找到解释但没有成功。谁能告诉
这个问题已经有答案了: 已关闭12 年前。 Possible Duplicate: add buttons to push notification alert 是否可以在远程通知显示的警报框中指定有
当您的 TabBarController 中有超过 5 个 View Controller 时,系统会自动为您设置一个“更多” View 。是否可以更改此 View 中导航栏的颜色以匹配我正在使用的颜
如何更改.AndroidStudioBeta文件夹的位置,默认情况下,该文件夹位于Windows中的\ .. \ User \ .AndroidStudioBeta,而不会破坏任何内容? /编辑: 找
我目前正在尝试将更具功能性的编程风格应用于涉及低级(基于 LWJGL)GUI 开发的项目。显然,在这种情况下,需要携带很多状态,这在当前版本中是可变的。我的目标是最终拥有一个完全不可变的状态,以避免状
我是一名优秀的程序员,十分优秀!