如何使用 Json.Net 从我的 WCF 休息服务(.NET 4)返回 json,而不是用引号括起来的字符串? [英] How can I return json from my WCF rest service (.NET 4), using Json.Net, without it being a string, wrapped in quotes?

查看:16
本文介绍了如何使用 Json.Net 从我的 WCF 休息服务(.NET 4)返回 json,而不是用引号括起来的字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

2010 年 10 月 19 日更新我知道我不久前问过这个问题,但这些答案中显示的解决方法很难令人满意,这仍然是许多人的常见问题.WCF 只是不灵活.我创建了自己的开源 C# 库,用于在没有 WCF 的情况下创建 REST 服务.检查 restcake.netrest.codeplex.com 获取有关该库的信息.结束更新

UPDATE 10/19/2010 I know I asked this question a while ago, but the workarounds shown in these answers are hardly satisfactory, and this is still a common problem for many. WCF just isn't flexible. I started my own open source C# library for creating REST services without WCF. Check restcake.net or rest.codeplex.com for info on said library. END UPDATE

2012 年 8 月 2 日更新ASP.NET Web API(以前的 WCF Web API,REST WCF 的替代品)使用 Json.NET 默认结束更新

UPDATE 8/2/2012 ASP.NET Web API (previously WCF Web API, the replacement for REST WCF) uses Json.NET by default END UPDATE

DataContractJsonSerializer 无法处理 Json.Net 仅处理的许多场景正确配置(特别是循环)时很好.

The DataContractJsonSerializer is unable to handle many scenarios that Json.Net handles just fine when properly configured (specifically, cycles).

服务方法可以返回特定的对象类型(在本例中为 DTO),在这种情况下,将使用 DataContractJsonSerializer,或者我可以让该方法返回一个字符串,然后自己使用 Json.Net 进行序列化.问题是,当我返回一个 json 字符串而不是一个对象时,发送给客户端的 json 用引号括起来.

A service method can either return a specific object type (in this case a DTO), in which case the DataContractJsonSerializer will be used, or I can have the method return a string, and do the serialization myself with Json.Net. The problem is that when I return a json string as opposed to an object, the json that is sent to the client is wrapped in quotes.

使用DataContractJsonSerializer,返回具体的对象类型,响应为:
{"Message":"Hello World"}

Using DataContractJsonSerializer, returning a specific object type, the response is:
{"Message":"Hello World"}

使用Json.Net返回一个json字符串,响应为:
"{"Message":"Hello World"}"

Using Json.Net to return a json string, the response is:
"{"Message":"Hello World"}"

我不想在客户端上对结果进行 eval() 或 JSON.parse(),如果 json 作为字符串返回并用引号括起来,我必须这样做.我意识到行为是正确的;这不是我想要/需要的.我需要原始的json;服务方法的返回类型是对象而不是字符串时的行为.

I do not want to have to eval() or JSON.parse() the result on the client, which is what I would have to do if the json comes back as a string, wrapped in quotes. I realize that the behavior is correct; it's just not what I want/need. I need the raw json; the behavior when the service method's return type is an object, not a string.

那么,我怎样才能让我的方法返回一个对象类型,但使用 DataContractJsonSerializer?如何告诉它改用 Json.Net 序列化程序?

So, how can I have my method return an object type, but not use the DataContractJsonSerializer? How can I tell it to use the Json.Net serializer instead?

或者,有没有办法直接写入响应流?所以我可以自己返回原始 json 吗?没有包装引号?

Or, is there someway to directly write to the response stream? So I can just return the raw json myself? Without the wrapping quotes?

这是我做的例子,供参考:

Here is my contrived example, for reference:

[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.
}

推荐答案

我终于想出了一个解决方案.这不是我想要的(返回特定的对象类型,并以某种方式指示 WCF 使用 Json.Net 序列化程序,而不是 DataContractJsonSerializer),但它工作得很好,而且简单明了.

I finally figured out a solution to this. It's not what I would have preferred (which would be to return the specific object type, and somehow instruct WCF to use a Json.Net serializer, instead of the DataContractJsonSerializer), but it is working great, and it's simple and clear.

使用这个新解决方案扩展我的人为示例:

Extending my contrived example using this new solution:

[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);
}

注意void的返回类型.我们不返回任何内容,因为它将使用 DataContractJsonSerializer 进行序列化.相反,我直接写入响应输出流.由于返回类型为void,处理管道并没有将content-type设置为默认类型application/json",所以我明确设置.

Note the return type of void. We do not return anything, since it would be serialized with DataContractJsonSerializer. Instead, I write directly to the response output stream. Since the return type is void, the processing pipeline doesn't set the content-type to the default type of "application/json", so I set it explicitly.

因为它使用 HttpContext,我猜它只有在你的服务类上有 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 时才会起作用,因为那将强制对服务的请求通过 ASP.NET 管道.如果没有 asp.net 兼容性,HttpContext 将不可用,因为 wcf 托管应该与主机无关.

Because this uses HttpContext, I'm guessing it will only work if you have [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] on your service class, since that will force requests to the service to go through the ASP.NET pipeline. Without the asp.net compatibility, the HttpContext will not be available, since wcf hosting is supposed to be host agnostic.

使用这种方法,在 firebug 中 GET 请求的结果看起来很完美.正确的内容类型、正确的内容长度和原始 json,不包含在引号中.而且,我正在使用 Json.Net 获得我想要的序列化.两全其美.

Using this method, the results look perfect in firebug for GET requests. Correct content-type, correct content length, and raw json, not wrapped in quotes. And, I'm getting the serialization I want using Json.Net. Best of both worlds.

当我的服务方法将 [DataContract] 对象类型作为输入参数时,我并不是 100% 肯定我可能会在de序列化方面遇到什么障碍.我假设 DataContractJsonSerializer 也将用于此目的.当我来到它时会越过那座桥......如果它产生问题.到目前为止,我的简单 DTO 还没有.

I'm not 100% positive of what obstacles I might run into regarding deserialization, when my service methods have [DataContract] object types as input parameters. I'm assuming the DataContractJsonSerializer will be used for that too. Will cross that bridge when I come to it...if it creates a problem. It hasn't so far, with my simple DTOs.

更新请参阅 Oleg 的答案(UPDATE2 部分).他将服务方法的返回类型从 void 更改为 System.ServiceModel.Channels.Message,而不是使用 HttpContext.Current.Response.Write(),而是使用:

UPDATE See Oleg's answer (the UPDATE2 part). He changes the return type of the service method from void to System.ServiceModel.Channels.Message, and rather than using HttpContext.Current.Response.Write(), he uses:

return WebOperationContext.Current.CreateTextResponse (json,
    "application/json; charset=utf-8", Encoding.UTF8);

这确实是一个更好的解决方案.谢谢奥列格.

Which is indeed a better solution. Thank you Oleg.

更新 2还有另一种方法可以做到这一点.将服务的返回类型从 Message 更改为 Stream,并返回:

UPDATE 2 There is yet another way of accomplishing this. Change your service's return type from Message to Stream, and return this:

WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));

我没有做过任何具体的测试,但对于可能返回大量数据的方法来说,这可能是一个更好的选择.我不知道这对非二进制数据是否重要.无论如何,一个想法.

I haven't done any specific tests, but it's possible that this would be a better choice for methods that could potentially return large amounts of data. I don't know if that matters for non-binary data though. Anyway, a thought.

这篇关于如何使用 Json.Net 从我的 WCF 休息服务(.NET 4)返回 json,而不是用引号括起来的字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆