Sam*_*ham 40 rest wcf serialization json.net
更新2010年10月19日 我知道我刚才问过这个问题,但这些答案中显示的解决方法难以令人满意,对许多人来说,这仍然是一个常见的问题.WCF只是不灵活.我创建了自己的开源C#库,用于在没有WCF的情况下创建REST服务.检查restcake.net或rest.codeplex.com以获取有关所述库的信息. 结束更新
更新8/2/2012 ASP.NET Web API(以前是WCF Web API,REST WCF的替代品)默认情况下 使用Json.NET END UPDATE
在DataContractJsonSerializer无法处理许多情况下是Json.Net在正确配置(具体周期)处理就好了.
一个服务方法可以返回一个特定的对象类型(在这种情况下是一个DTO),在这种情况下DataContractJsonSerializer将使用它,或者我可以让该方法返回一个字符串,并自己使用Json.Net进行序列化.问题是当我返回一个json字符串而不是一个对象时,发送到客户端的json用引号括起来.
使用DataContractJsonSerializer,返回特定的对象类型,响应是:
{"Message":"Hello World"}
使用Json.Net返回json字符串,响应是:
"{\"Message\":\"Hello World\"}"
我不想在客户端上使用eval()或JSON.parse()结果,如果json以字符串形式返回,用引号括起来就是我必须要做的.我意识到这种行为是正确的; 这不是我想要/需要的.我需要原始的json; 当服务方法的返回类型是对象而不是字符串时的行为.
那么,我如何让我的方法返回一个对象类型,但不能使用DataContractJsonSerializer?我怎么能告诉它使用Json.Net序列化器呢?
或者,有没有直接写入响应流?所以我可以自己退回原始的json?没有包装报价?
这是我的人为例子,供参考:
[DataContract]
public class SimpleMessage
{
[DataMember]
public string Message { get; set; }
}
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PersonService
{
// uses DataContractJsonSerializer
// returns {"Message":"Hello World"}
[WebGet(UriTemplate = "helloObject")]
public SimpleMessage SayHelloObject()
{
return new SimpleMessage("Hello World");
}
// uses Json.Net serialization, to return a json string
// returns "{\"Message\":\"Hello World\"}"
[WebGet(UriTemplate = "helloString")]
public string SayHelloString()
{
SimpleMessage message = new SimpleMessage() { Message = "Hello World" };
string json = JsonConvert.Serialize(message);
return json;
}
// I need a mix of the two. Return an object type, but use the Json.Net serializer.
}
Run Code Online (Sandbox Code Playgroud)
Sam*_*ham 40
我终于找到了解决方案.这不是我想要的(这将是返回特定的对象类型,并以某种方式指示WCF使用Json.Net序列化器,而不是DataContractJsonSerializer),但它工作得很好,而且简单明了.
使用这个新解决方案扩展我的设计示例:
[WebGet(UriTemplate = "hello")]
public void SayHello()
{
SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
string json = JsonConvert.Serialize(message);
HttpContext.Current.Response.ContentType = "application/json; charset=utf-8";
HttpContext.Current.Response.Write(json);
}
Run Code Online (Sandbox Code Playgroud)
注意返回类型void.我们不返回任何内容,因为它将使用DataContractJsonSerializer进行序列化.相反,我直接写入响应输出流.由于返回类型为void,处理管道不会将content-type设置为默认类型"application/json",因此我将其显式设置.
因为这使用HttpContext,我猜它只有[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]你的服务类才有效,因为这会强制请求服务通过ASP.NET管道.没有asp.net兼容性,HttpContext将不可用,因为wcf托管应该是主机不可知的.
使用此方法,结果在firebug中对于GET请求看起来很完美.正确的内容类型,正确的内容长度和原始json,不包括在引号中.而且,我正在使用Json.Net获得我想要的序列化.两全其美.
我不是100%肯定的我可能会遇到什么障碍就成德序列化,在我服务的方法有[DataContract]对象类型作为输入参数.我假设DataContractJsonSerializer也将用于此.当我来到它时会穿过那座桥......如果它造成了问题.到目前为止,还有我简单的DTO.
更新
请参阅Oleg的答案(UPDATE2部分).他将服务方法的返回类型从void更改为System.ServiceModel.Channels.Message,而不是使用HttpContext.Current.Response.Write(),他使用:
return WebOperationContext.Current.CreateTextResponse (json,
"application/json; charset=utf-8", Encoding.UTF8);
Run Code Online (Sandbox Code Playgroud)
这确实是一个更好的解决方案.谢谢奥列格.
更新2 还有另一种方法可以实现这一目标.将服务的返回类型从Message更改为Stream,并返回:
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));
Run Code Online (Sandbox Code Playgroud)
我没有做过任何特定的测试,但对于可能返回大量数据的方法,这可能是更好的选择.我不知道这对非二进制数据是否重要.无论如何,一个想法.
Ole*_*leg 11
在我看来,你使用不正确DataContractJsonSerializer.奇怪的是:你没有ResponseFormat = ResponseFormat.Json为public SimpleMessage SayHelloObject()方法定义属性.
此外,如果你有{"Message":"Hello World"}一个字符串并在调试器中显示它将显示为"{\"Message\":\"Hello World\"}",所以就像你看到的那样string json = JsonConvert.Serialize(message);(Json.Net).所以在我看来,你在两种情况下都有相同的结果.
要验证这一点,请使用读取结果的客户端软件.看一些例子
JQuery ajax调用httpget webmethod(c#)无法正常工作
如果ContentType不是JSON,我可以从.asmx Web服务返回JSON吗?
如何构建要发送到AJAX WebService的JSON对象?
更新:在您的代码中定义方法SayHelloString().它的结果是一个字符串.如果调用该方法这个字符串将是一次 JSON序列化.字符串的JSON序列化{"Message":"Hello World"}是带引号的字符串(请参阅http://www.json.org/定义,不是对象,而是字符串)或字符串"{\"Message\":\"Hello World\"}".因此,Web Service的两种方法都是正确的.
更新2:我很高兴我的回答"更新"部分的提示帮助你完成了双JSON序列化.
不过我建议你改变一点解决方案,以便更多地关注WCF概念.
如果您想在WCF中实现Web响应的自定义编码(请参阅http://msdn.microsoft.com/en-us/library/ms734675.aspx),您的WCF方法最好返回Message而不是void:
[WebGet(UriTemplate = "hello")]
public Message SayHello()
{
SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
string myResponseBody = JsonConvert.Serialize(message);
return WebOperationContext.Current.CreateTextResponse (myResponseBody,
"application/json; charset=utf-8",
Encoding.UTF8);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用另一个Message formater:例如CreateStreamResponse(或其他一些参见http://msdn.microsoft.com/en-us/library/system.servicemodel.web.weboperationcontext_methods(v=VS.100).aspx)的CreateTextResponse.如果您想设置一些额外的HTTP标头或Http状态代码(例如,如果出现一些错误),您可以这样做:
OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
ctx.StatusCode = HttpStatusCode.BadRequest;
Run Code Online (Sandbox Code Playgroud)
最后,我想从评论中重复我的问题:你能解释为什么要使用Json.Net而不是DataContractJsonSerializer?是性能提升?您是否需要像DateTime其他方式一样实现某些数据类型的序列化DataContractJsonSerializer?或者你选择的主要原因Json.Net是其他的?
| 归档时间: |
|
| 查看次数: |
59713 次 |
| 最近记录: |