如何使一个ASMX文件输出JSON

65

我创建了一个带有代码后台文件的ASMX文件。它能够正常工作,但输出的是XML格式。

不过,我需要输出JSON格式。ResponseFormat配置似乎不起作用。我的代码后台如下:

[System.Web.Script.Services.ScriptService]
public class _default : System.Web.Services.WebService {
    [WebMethod]
    [ScriptMethod(UseHttpGet = true,ResponseFormat = ResponseFormat.Json)]
    public string[] UserDetails()
    {
        return new string[] { "abc", "def" };
    }
}

可能是Asmx web service如何返回没有XML包装的JSON?的重复问题。 - Stephen Kennedy
6个回答

61

要收到一个不被包装成XML的纯JSON字符串,您必须直接将JSON字符串写入HttpResponse中,并将WebMethod返回类型更改为void

    [System.Web.Script.Services.ScriptService]
    public class WebServiceClass : System.Web.Services.WebService {
        [WebMethod]
        public void WebMethodName()
        {
            HttpContext.Current.Response.Write("{property: value}");
        }
    }

还适用于在不使用额外的XML包装器返回XML时。 - kad81
1
不,你真的不必这样做,正如其他答案所证明的那样。我有很多遗留服务返回JSON或XML,具体取决于Web客户端的要求,并且从未不得不直接编写响应流。 - Stephen Kennedy

39

8
您也可以添加以下注释来启用 Web 服务中的 GET 方法:[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)] public string TestData() - Mario Fraiß
1
哇,谁会想到你不能用 GET 请求获得一个 JSON 响应。难以置信。谢谢你 - 我差点把头发都拔光了! - crush
4
我不同意在此处使用POST请求。这个端点不期望数据,而且 OP 没有向服务器发送任何数据(与 Scott G 的帖子不同),并且当然也不打算更改服务器上的数据。事实上,OP 有正确的 ScriptMethod 属性来允许GET请求- UseHttpGet=true。他们只是调用一个端点来“获取”一些数据。使用GET请求很好 - 唯一缺少的是在请求中设置Content-Type,见下面我的答案。 - bitsprint
略微偏题但相关。Encosia上面的URL在Chrome上会触发一个可怕的安全警告,说该站点包含恶意软件。 - Totoro53
这只是故事的一部分,最多也只是其中的一部分。 - Stephen Kennedy

18

这可能是旧新闻了,但是魔法似乎是:

  • 在 Web 服务类上使用 [ScriptService] 属性
  • 在方法中使用 [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
  • 请求中设置 Content-type: application/json

有了这些设置,GET 请求将会成功。

对于 HTTP POST,

  • 在方法中使用 [ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json)]

并且在客户端(假设你的 Web 方法名为 MethodName,并且它接受一个名为 searchString 的参数):

        $.ajax({
            url: "MyWebService.asmx/MethodName",
            type: "POST",
            contentType: "application/json",
            data: JSON.stringify({ searchString: q }),
            success: function (response) {                  
            },
            error: function (jqXHR, textStatus, errorThrown) {
                alert(textStatus + ": " + jqXHR.responseText);
            }
        });

有趣的是,application/json 是必需的,如果没有它,根据我的 Fiddler 经验,它将返回 XML。这种方式有点 hacky,可以同时返回两种数据类型? - SimpsOff
3
为什么需要将“Content-type”设置为“application/json”? [ScriptMethod(ResponseFormat = ResponseFormat.Json)] 不应该自动完成吗?难以置信。感谢您的研究。 - crush
在我的情况下,[ScriptMethod...] 似乎编译有问题。它无法找到 UseHttpGet 的定义,如果我尝试导入 ScriptMethodAttribute 或者说 ScriptMethodAttribute.UseHttpGet,那么它会提示需要一个常量表达式。 - Panzercrisis
我现在明白了。我在VB.NET中使用的是<ScriptMethod(UseHttpGet = True...,而不是<ScriptMethod(UseHttpGet:=True... - Panzercrisis
1
在类级别上使用[ScriptService]注释,在函数级别上使用 [WebMethod(EnableSession = true)],[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]以及将 HttpContext.Current.Response.ContentType = "application/json"; 设为函数体中的第一行,仍会导致输出为 XML。 - Anders Lindén

9
一个我吃了亏才学到的小技巧(基本上花了4个小时在谷歌上),你可以在ASPX文件中使用PageMethods返回JSON(带有[ScriptMethod()]标记)来调用静态方法,但是如果你决定将静态方法移到asmx文件中,则不能是静态方法。
此外,你需要告诉Web服务Content-Type: application/json,以便从调用中获取JSON(我正在使用jQuery,3 Mistakes To Avoid When Using jQuery文章非常启发人 - 它来自另一个答案中提到的同一网站)。

4
你是在客户端脚本还是服务器端调用Web服务?
你可以尝试发送一个内容类型头到服务器,例如'application/json; charset=utf-8'。
在客户端,我使用原型客户端库,在进行Ajax调用时有一个contentType参数,您可以在其中指定此内容类型。我认为jQuery有一个getJSON方法。

这在我看来是正确的答案。虽然使用POST请求是一个好建议,但OP中编写的代码没有问题。可能的罪魁祸首是内容类型标头错误。例如,JQuery会自动发送“application/json”,但包括一些额外的“text/xml”值,导致asp.net仍然返回xml。 - b_levitt

4

替代方案:使用通用的HTTP处理程序(.ashx),并使用您喜欢的JSON库手动序列化和反序列化您的JSON。

我发现,完全控制请求处理和生成响应比.NET提供的任何其他东西都更适合简单的RESTful网络服务。


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