通过Web API发送的字符串包含在引号中

kiw*_*hen 31 c# api json asp.net-web-api

我使用C#在ASP.NET 4中使用我的Web API遇到了一个小问题.我正在尝试创建一个前端GUI,它通过多个Web API发送和接收数据.拥有多个API的原因与我们的网络有关,该网络由多个安全区域组成.服务器位于不同的区域,一个简单的请求可能需要通过3个不同的API.

具体来说,我正在从GUI向第一个API发送一个JSON对象.应该将JSON对象转发到下一个API,然后从那里创建一个新的JSON对象,并在同一路径下返回.

路径本身工作正常.问题是JSON对象一旦返回GUI就无法解析.我收到一个用引号括起来的JSON字符串,每个API一次.

字符串可能会像这样开始:

Hey! I am a string, or a JSON object of sorts!

API之间的第一跳给了我:

"Hey! I am a string, or a JSON object of sorts!"

在下一跳之后它看起来像这样:

"\"Hey! I am a string, or a JSON object of sorts!\""

当我的GUI掌握它时,我们有这样的事情:

"\"\\\"Hey! I am a string, or a JSON object of sorts!\\\"\""

这是解析失败的原因,原因很明显.JSON对象本身已正确格式化,但所有引号都会导致JSON.net解析器出现问题(对象内的所有引号也会被多次包装).

到目前为止我尝试过的是将请求作为application/json类型和text/plain类型发送.两者都做了同样的事情.API返回一个HttpResponseMessage,使用ReadAsStringAsync()读取.我也试图避免字符串读取,只是直接从HttpRequestMessage读取到HttpResponseMessage并仅在GUI中执行ReadAsStringAsync(),但问题仍然存在.JSON字符串是使用JSON.nets Serialize() - 方法创建的,并使用StringContent()放入HttpContent.这似乎正确地完成了工作.我相信当API和GUI收到HttpResponseMessage时会生成引号.

知道我如何发送和接收JSON字符串作为原始字符串,这是不是以任何方式处理?

我可以通过在每个API上将对象解析为JToken或JObject并再次序列化来绕过此行为.然而,这不是一个好的解决方案 - 我宁愿API只是按照他们获得它的方式转发消息,而不是对它做任何事情.我使用路由查看了前进,但是有许多授权内容正在进行,这需要我使用API​​操作,而不是重定向路由.

澄清(TLDR):理想的解决方案是让API简单地传递消息而不解析或读取任何内容.只要消息来源被授权,请求就会被加密并且请求的URL有效,消息本身对每个"代理"API都无关紧要.

Bri*_*ers 49

每个"代理"API都会添加引号和反斜杠,因为每个响应都会重新序列化JSON字符串,而不是在收到响应时.

在你的代理API中,大概是你正在做这样的事情(为简洁省略了错误处理):

[HttpGet]
public async Task<HttpResponseMessage> GetWidget(int id)
{
    HttpClient client = new HttpClient();
    string url = "http://nextapiserver.example.org/widgets/" + id;
    string json = await client.GetStringAsync(url);
    return Request.CreateResponse(HttpStatusCode.OK, json);
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是Web API默认情况下假定它负责序列化您提供的任何内容.对于大多数用例,这正是您想要的.但是如果你的内容已经被序列化为JSON,那么Web API无法知道这一点; 它会愉快地重新序列化字符串,在过程中添加额外的引号和反斜杠.

要不改变地传递JSON字符串,您需要显式创建响应内容对象(而不是让Web API创建它),确保将媒体类型设置为以便下游客户端仍然将其解释为JSON(而不是纯文本) ).这是修改后的代码:

[HttpGet]
public async Task<HttpResponseMessage> GetWidget(int id)
{
    HttpClient client = new HttpClient();
    string url = "http://nextapiserver.example.org/widgets/" + id;
    string json = await client.GetStringAsync(url);
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StringContent(json, Encoding.UTF8, "application/json");
    return response;
}
Run Code Online (Sandbox Code Playgroud)

我确信上面的内容可以改进,但这就是它的要点.试一试,看看它是否能为您解决问题.请注意,您需要在所有代理API 上应用此修复程序.

  • 这很完美.不知道为什么这不是正确的答案.只是返回一个字符串的问题. (4认同)
  • 谢谢,这应该是答案 (2认同)

kiw*_*hen 9

经过多方面的研究,我终于想出了这个.

首先; 我直接返回了HttpResponseMessage; 我没有故意在API路径的每一跳内反序列化它.

事实证明,问题实际上是我们使用了"原生"MVC序列化方法和JSON.net方法的混合.任何一个本身都很好,并提供所有API的干净直通.但是,如果我们将来自本机方法和JSON.net方法的序列化数据组合在一起,那么链下游的API将无法识别格式并错误地认为应该再次序列化内容(使用本机方法).

所以解决方案只是从序列化过程中删除所有JSON.net方法,我们最终得到了预期的结果.


ctc*_*ctc 6

这可能并不适合所有人,但我想使用来自 Microsoft.AspNetCore.Mvc 的 Ok() IActionResult 而不是执行完整的 HttpResponseMessage。这也有引号中的字符串结果:

"\"my string result\""
Run Code Online (Sandbox Code Playgroud)

我没有返回一个字符串,而是返回了一个具有该属性的对象。原始问题示例:

return Ok(myStringValue);
Run Code Online (Sandbox Code Playgroud)

什么对我有用:

return Ok(new { id = myStringValue });
Run Code Online (Sandbox Code Playgroud)

这有一个额外的好处,即在请求的接收方更具描述性。


gld*_*ael 6

对于ASP.NET Core,请使用修饰动作[Produces("text/plain")]

例如。

[HttpGet("/"), Produces("text/plain")]
public IActionResult HelloWorld() => Ok("Hello World");
Run Code Online (Sandbox Code Playgroud)


Más*_*ter 5

我遇到了这个问题,所以我Newtonsoft.Json通过 Nuget Packages Manager安装。然后反序列化您的 JSON 字符串:

string deserializedString = JsonConvert.DeserializeObject<string>(yourJsonString);

不要忘记导入命名空间:

using Newtonsoft.Json;