如何从C#方法返回Json对象

26

我正在尝试修复一个ASP.NET WebAPI方法,在该方法中需要返回Json响应,但实际返回了字符串。

最初它返回的是XML格式,但我已经在App_Start\WebApiConfig.cs中的mvc代码中添加了这行代码,以便默认情况下返回Json。

config.Formatters.Remove(config.Formatters.XmlFormatter);

我们已将C#方法更新如下,使用NewtonSoft:

public string Get()
{
    string userid = UrlUtil.getParam(this, "userid", "");
    string pwd = UrlUtil.getParam(this, "pwd", "");
    string resp = DynAggrClientAPI.openSession(userid, pwd);

    JsonSerializer ser = new JsonSerializer();
    string jsonresp = JsonConvert.SerializeObject(resp);

    return resp;
}

resp变量以字符串类型返回:

"{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}"

jsonresp变量的样式如下:

"\"{status:\\\"SUCCESS\\\",data:[\\\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\\\"]}\""

在 Chrome 的 F12 开发者工具中,数据对象为:

""{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}""
在控制台工具中,angular.fromJson(data)的结果是:
"{status:"SUCCESS",data:["4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"]}"

我希望能够得到有关如何正确返回Json对象的建议,并且不是任何字符串类型。


更新

通过拦截resp变量并使用下面Mr. Chu的建议,我可以在客户端成功地获得一个漂亮干净的Json对象。 关键在于resp需要在每个键值对周围包含双引号:

public HttpResponseMessage Get()
{
    string userid = UrlUtil.getParam(this, "userid", "");
    string pwd = UrlUtil.getParam(this, "pwd", "");
    string resp = DynAggrClientAPI.openSession(userid, pwd);

    resp = "{\"status\":\"SUCCESS\",\"data\":[\"194f66366a6dee8738428bf1d730691a9babb77920ec9dfa06cf\"]}";  // TEST !!!!!           

    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StringContent(resp, System.Text.Encoding.UTF8, "application/json");
    return response;
}
在Chrome控制台中,响应内容为:
Object {status: "SUCCESS", data: Array[1]}
data: Array[1]
status: "SUCCESS"
__proto__: Object

resp是什么?它是一个JSON字符串吗? - Anthony Chu
2
WebApi将自动将其转换为JSON(假设您已正确设置)。不要将其转换为JSON并尝试仅返回C#对象。 - Mike Cheel
5个回答

44

resp 已经是一个 JSON 字符串,但它不是有效的 JSON(键没有用引号"包装)。如果返回给 Angular,JavaScript 的 JSON.parse() 方法将无法反序列化它。然而,您可以使用 JSON.NET 反序列化为 JObject 并再次序列化为有效的 JSON,并创建自己的 HttpResponseMessage...

public HttpResponseMessage Get()
{
    string userid = UrlUtil.getParam(this, "userid", "");
    string pwd    = UrlUtil.getParam(this, "pwd", "" );

    string resp = DynAggrClientAPI.openSession(userid, pwd);
    var jObject = JObject.Parse(resp);

    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
    return response;
}

或者你可以直接返回JObject,这样Web API会为您进行序列化...

public JObject Get()
{
    string userid = UrlUtil.getParam(this, "userid", "");
    string pwd    = UrlUtil.getParam(this, "pwd", "" );

    string resp = DynAggrClientAPI.openSession(userid, pwd);
    var jObject = JObject.Parse(resp);

    return jObject;
}

无论哪种情况,Web API 调用应该返回此 JSON,现在它是有效的...

{
  "status": "SUCCESS",
  "data": [
    "4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"
  ]
}

在 Angular 代码中,您需要挖掘存储在名为 data 的数组中的会话 ID ...

userService.openUserSession(rzEnvJson).then(function (response) {
    var sessionResponse = response.data; // or simply response, depending if this is a promise returned from $http
    $rootScope.rgSessionVars.sessionID = sessionResponse.data[0];
});

1
我已更新原始帖子以显示更改 - 现在使用NewtonSoft的JsonConvert.SerializeObject。 - bob.mazzo
你试过这个答案吗?看起来它应该能做到你想要的。 - Anthony Chu
我遇到了一个前端错误:"SyntaxError: Unexpected token s at Object.parse (native)"。 - bob.mazzo
1
看起来 resp 包含无效的 JSON。statusdata 应该用 " 包裹起来。错误提示中提到的 sstatus 中的 s - Anthony Chu
1
@bob 我已经更新了我的答案,展示了如何使用JSON.NET将来自DynAggrClientAPI.openSession的无效JSON转换为有效的JSON并返回给Angular。 - Anthony Chu
显示剩余3条评论

8
重点在于Mike Cheel的评论; 序列化发生了两次,一次是在OP的代码中,另一次是由Asp.Net WebAPI执行。这就是为什么会返回一个字符串而不是一个Json对象。
我也遇到了完全相同的问题。以下是一个hello world示例来展示这个问题。我最初做了这样的事情:
[Route("getall")]
public string GetAllItems()
{
    var result = new
    {
        x = "hello",
        y = "world"
    };
    return JsonConvert.SerializeObject(result);
}

我尝试着像这样做,认为我需要返回IHttpActionResult来解决这个问题:

[Route("getall")]
public IHttpActionResult GetAllItems()
{
    var result = new
    {
        x = "hello",
        y = "world"
    };
    return Ok(JsonConvert.SerializeObject(result));
}

这两个控制器动作返回的是字符串,而不是我想要的Json对象;所以我这样做:

"{\"x\":\"hello\",\"y\":\"world\"}"

最终,我看到了Mike的评论,并意识到需要直接返回.Net对象,并让WebAPI处理序列化。所以,不是返回这个:

return Ok(JsonConvert.SerializeObject(result));

返回 this:

return Ok(result);

然后我得到了我期望的结果:
{"x":"hello","y":"world"}

1
我知道你发现了 return Ok(JsonConvert.SerializeObject(result)); 这行代码引起了问题。但是我很高兴你发布了那段代码,因为那段代码解决了我遇到的问题。 - StackOverflowUser

2

我不明白这与AngularJS有什么关系,但你的问题很简单。你的数据对象是JSON编码的。因此,你几乎可以访问data.JsonRequestBehavior,它将是1。但是,其中的Data字段再次进行了JSON编码。在尝试使用之前,需要对其进行解码 - 当你到达此回调时,它只是一个字符串:

var myData = angular.fromJson(data.Data);
console.log(myData.data);

请注意,您的data.Data对象本身是另一个包装器 - 一个数组。您几乎可以肯定希望myData.data [0]进入该sessionID字段...

3
可能发生这种情况是因为你在执行 string resp = DynAggrClientAPI.openSession(userid, pwd); 并将结果作为字符串处理。虽然你没有提供代码,但是如果将其返回一个真正的对象,则你的 JSON 编码器可能可以避免双重编码,让你跳过上述步骤。请注意:翻译仅供参考,具体语境需要根据实际情况进行理解。 - Chad Robinson
'resp'变量确实是这里的争议点。这是一个返回此内容的C++程序。我需要那个编码器返回某种Json格式的对象,我想。 - bob.mazzo
我们已经更新了代码,使用JsonSerializer()。现在我的数据结果返回为"{status:"SUCCESS",data:["9f9502cd3e0a81cab3b2c7b4fc65395b0b40741130c7aead498a"]}"。 - bob.mazzo
与此同时,我正在提取数据:首先应用JSON.parse(data),然后使用.split()函数访问数据:字段。这不是理想的解决方案,但在此期间可以使用。 - bob.mazzo

0

我曾经遇到过类似的问题(字符串中包含原始JSON,例如resp),在 .Net 6 中这个方法对我来说很有效。我没有检查过之前的版本。

[HttpGet]
public IActionResult Get()
{
    string userid = UrlUtil.getParam(this, "userid", "");
    string pwd    = UrlUtil.getParam(this, "pwd", "" );

    string resp = DynAggrClientAPI.openSession(userid, pwd);
    return Content(resp, "application/json"):
}

0

这些其他的解决方案对我来说都不起作用,但我能够让类似这样的东西工作:

 [HttpGet]
 public async Task Get(CancellationToken cancellationToken)
 {
     string userid = UrlUtil.getParam(this, "userid", "");
     string pwd = UrlUtil.getParam(this, "pwd", "");    
     
     await using (Stream contentStream = await DynAggrClientAPI.openSessionStreamAsync(userid, pwd, cancellationToken))
     {
         Response.StatusCode = (int)HttpStatusCode.OK;
         Response.ContentType = "application/json";
         await contentStream.CopyToAsync(Response.Body, cancellationToken);
     }
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接