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 上应用此修复程序.
经过多方面的研究,我终于想出了这个.
首先; 我直接返回了HttpResponseMessage; 我没有故意在API路径的每一跳内反序列化它.
事实证明,问题实际上是我们使用了"原生"MVC序列化方法和JSON.net方法的混合.任何一个本身都很好,并提供所有API的干净直通.但是,如果我们将来自本机方法和JSON.net方法的序列化数据组合在一起,那么链下游的API将无法识别格式并错误地认为应该再次序列化内容(使用本机方法).
所以解决方案只是从序列化过程中删除所有JSON.net方法,我们最终得到了预期的结果.
这可能并不适合所有人,但我想使用来自 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)
这有一个额外的好处,即在请求的接收方更具描述性。
对于ASP.NET Core,请使用修饰动作[Produces("text/plain")]。
例如。
[HttpGet("/"), Produces("text/plain")]
public IActionResult HelloWorld() => Ok("Hello World");
Run Code Online (Sandbox Code Playgroud)
我遇到了这个问题,所以我Newtonsoft.Json通过 Nuget Packages Manager安装。然后反序列化您的 JSON 字符串:
string deserializedString = JsonConvert.DeserializeObject<string>(yourJsonString);
不要忘记导入命名空间:
using Newtonsoft.Json;
| 归档时间: |
|
| 查看次数: |
27703 次 |
| 最近记录: |