ASP.NET ASMX Web服务返回XML而不是JSON

52
为什么这个简单的 Web 服务拒绝向客户端返回 JSON?下面是我的客户端代码:
        var params = { };
        $.ajax({
            url: "/Services/SessionServices.asmx/HelloWorld",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            timeout: 10000,
            data: JSON.stringify(params),
            success: function (response) {
                console.log(response);
            }
        });

同时还有服务:

namespace myproject.frontend.Services
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [ScriptService]
    public class SessionServices : System.Web.Services.WebService
    {
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string HelloWorld()
        {
            return "Hello World";
        }
    }
}

web.config:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
</configuration>

并且响应:

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>

无论我怎么做,响应总是以 XML 的形式返回,我该如何让 Web 服务返回 Json?
编辑:以下是 Fiddler HTTP 跟踪记录:
REQUEST
-------
POST http://myproject.local/Services/SessionServices.asmx/HelloWorld HTTP/1.1
Host: myproject.local
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://myproject.local/Pages/Test.aspx
Content-Length: 2
Cookie: ASP.NET_SessionId=5tvpx1ph1uiie2o1c5wzx0bz
Pragma: no-cache
Cache-Control: no-cache

{}

RESPONSE
-------
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 19 Jun 2012 16:33:40 GMT
Content-Length: 96

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>

我已经失去了数数我读过多少篇文章来修复这个问题。指令要么不完整,要么由于某些原因无法解决我的问题。 其中一些更相关的包括(都没有成功): 此外还有几篇其他的通用文章。

我看到目标框架标签设置为4.0,你的应用程序实际上是在哪个版本的框架中构建的? - Terry
在“项目属性”中的“应用程序”选项卡下,目标框架是“.Net Framework 4”。这样就足够了吗?还是我需要在其他地方进行设置?抱歉,我对VS相对较新(更有js经验)。 - njr101
你的代码看起来是正确的。能否使用WireShark记录下你的AJAX请求和服务器的响应呢?查看这些HTTP数据包将有助于理解发生了什么。 - kol
@kol:感谢您抽出时间查看这个问题。我已经按要求发布了HTTP跟踪信息。也许您能够发现我所忽略的问题。 - njr101
可能是重复问题:https://dev59.com/gWLVa4cB1Zd3GeqPsxKd - mas_oz2k1
10个回答

49

终于搞清楚了。

应用程序代码如发布的那样是正确的。问题出在配置上。正确的 web.config 如下:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.webServer>
        <handlers>
            <add name="ScriptHandlerFactory"
                 verb="*" path="*.asmx"
                 type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                 resourceType="Unspecified" />
        </handlers>
    </system.webServer>
</configuration>
根据文档,从.NET 4开始将处理程序的注册移到了machine.config文件中,因此不需要再注册处理程序。但由于某些原因,这对我并没有起作用,但是将该注册添加到我的应用程序的web.config文件中解决了问题。
许多涉及此问题的文章指示将处理程序添加到<system.web>部分。这样做不起作用,并可能导致其他一系列问题。我尝试将处理程序添加到两个部分,但会生成一组其他迁移错误,完全误导我的故障排除过程。
如果对其他人有所帮助,则以下是我会查看的检查清单:
1. 是否在ajax请求中指定了type: "POST"? 2. 是否在ajax请求中指定了contentType: "application/json; charset=utf-8"? 3. 是否在ajax请求中指定了dataType: "json"? 4. 您的.asmx web服务是否包含[ScriptService]属性? 5. 您的Web方法是否包括[ScriptMethod(ResponseFormat = ResponseFormat.Json)]属性?(我的代码即使没有这个属性也可以工作,但很多文章都说它是必需的) 6. 是否已将ScriptHandlerFactory添加到<system.webServer><handlers>中的web.config文件中? 7. 是否已从<system.web><httpHandlers>中的web.config文件中删除了所有处理程序?
希望这能帮助到遇到相同问题的人,并感谢发帖者提供的建议。

1
我已经在这个问题上苦苦思索了好几个小时,你的帖子非常有用。我已经按照七个步骤进行了操作,但我的服务仍然在响应中返回xml。我正在使用ASP.NET 3.5 - 还有其他想法吗?我还在使用jQuery表单插件(不需要显式声明POST、json等)。 - Daryl
如果您打开一个新的问题并在此处添加一个链接评论,我可以查看。请包括请求和响应的Fiddler跟踪。包括您完整的web.config。还要包括特定于asp.net的代码,包括属性。我建议您使用类似于我的示例的“Hello World”服务进行测试。 - njr101
这个回答对我帮助很大,尤其是他提到的七个步骤。 - Ju-chan
我在我的应用程序中使用相同的内容,但是出现错误,你能否建议我遗漏了什么?XMLHttpRequest 无法加载 http://192.168.200.56/ChatApp.asmx/HelloWorld。无效的 HTTP 状态码 500。 - Amit Sharma
为了更好地解决问题,对于#2,我添加了一些魔法,并将contentType更改为“application/json”。 - archangel76

32

以上解决方案没有成功,这里是我是如何解决的。

将以下代码放入您的Web服务中,而不是返回类型,只需在响应上下文中编写字符串即可:

this.Context.Response.ContentType = "application/json; charset=utf-8";
this.Context.Response.Write(serial.Serialize(city));

8
你做到了!这是最佳答案。我将我的函数返回类型修改为“void”,并使用你的代码,现在JQuery UI自动完成终于能够正常工作了。 - Dexter
这很粗糙和令人担忧,但当更复杂的操作似乎无法解决我的问题时,它是非常有效的。这个方法可行。 - philw
开心的小兔子!:D - DreamTeK
兄弟,你是我最敬佩的救星!我已经苦思冥想了好几个小时,直到看到你的答案,没有其他东西能帮助我。我太爱你了 :) - aradalvand

13

如果您想继续使用Framework 3.5,您需要按照以下方式更改代码。

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
[ScriptService]
public class WebService : System.Web.Services.WebService
{
    public WebService()
    {
    }

    [WebMethod]
    public void HelloWorld() // It's IMP to keep return type void.
    {
        string strResult = "Hello World";
        object objResultD = new { d = strResult }; // To make result similarly like ASP.Net Web Service in JSON form. You can skip if it's not needed in this form.

        System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer();
        string strResponse = ser.Serialize(objResultD);

        string strCallback = Context.Request.QueryString["callback"]; // Get callback method name. e.g. jQuery17019982320107502116_1378635607531
        strResponse = strCallback + "(" + strResponse + ")"; // e.g. jQuery17019982320107502116_1378635607531(....)

        Context.Response.Clear();
        Context.Response.ContentType = "application/json";
        Context.Response.AddHeader("content-length", strResponse.Length.ToString());
        Context.Response.Flush();

        Context.Response.Write(strResponse);
    }
}

如果您在回答中添加您所使用的内容,并可能链接到文档,那将非常有帮助。这样其他人就可以更容易地弄清楚它的工作原理以及如何在其他情况下使用它。 - Sumurai8
这个答案适用于在Sharepoint 2010和.NET Framework 3.5中使用ASMX + jQuery。我决定使用标准的JavaScriptSerializer而不是引用NewtonJson程序集。谢谢! - opewix

8

有更简单的方法从 Web 服务返回纯字符串。我称之为 CROW 函数(容易记忆)。

  [WebMethod]
  public void Test()
    {
        Context.Response.Output.Write("and that's how it's done");    
    }

正如您所见,返回类型为“void”,但CROW函数仍然会返回您想要的值。

这对我非常有效。我将返回字符串更改为void,并使用context.response.output.write来输出已序列化的JSON! - Josh

1
希望这可以帮助你,看起来你仍然需要在请求中发送一些JSON对象,即使你调用的方法没有参数。
var params = {};
return $http({
        method: 'POST',
        async: false,
        url: 'service.asmx/ParameterlessMethod',
        data: JSON.stringify(params),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json'

    }).then(function (response) {
        var robj = JSON.parse(response.data.d);
        return robj;
    });

1
我有一个 .asmx 网络服务(.NET 4.0),其中包含一个返回字符串的方法。该字符串是一个序列化的 List,就像你在许多示例中看到的那样。这将返回未包装在 XML 中的 JSON。无需更改 web.config 或需要第三方 DLL。
var tmsd = new List<TmsData>();
foreach (DataRow dr in dt.Rows)
{

m_firstname = dr["FirstName"].ToString();
m_lastname = dr["LastName"].ToString();

tmsd.Add(new TmsData() { FirstName = m_firstname, LastName = m_lastname} );

}

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string m_json = serializer.Serialize(tmsd);

return m_json;

客户端使用该服务的部分如下所示:
   $.ajax({
       type: 'POST',
       contentType: "application/json; charset=utf-8",
       dataType: 'json',
       url: 'http://localhost:54253/TmsWebService.asmx/GetTombstoneDataJson',
       data: "{'ObjectNumber':'105.1996'}",
       success: function (data) {
           alert(data.d);
       },
       error: function (a) {
           alert(a.responseText);
       }
   });

0

ScriptService属性应该自动处理这个问题。我真的不想自己处理所有的序列化工作。我有其他项目,这段代码在那里运行得很好。但它们在其他服务器上,这让我觉得可能存在某种配置问题。 - njr101

0

我知道这是一个非常老的问题,但今天我遇到了同样的问题,我已经到处搜索找到答案,但没有结果。经过长时间的研究,我找到了使其工作的方法。为了从服务中返回JSON,您必须以正确的格式在请求中提供数据,在请求之前使用JSON.stringify()来解析数据,别忘了使用contentType: "application/json; charset=utf-8",这样将提供预期的结果。


0
我已经尝试了上述所有步骤(包括答案),但都没有成功,我的系统配置是Windows Server 2012 R2,IIS 8。以下步骤解决了我的问题。
更改应用程序池,使其托管管道=经典。

-1
response = await client.GetAsync(RequestUrl, HttpCompletionOption.ResponseContentRead);
if (response.IsSuccessStatusCode)
{
    _data = await response.Content.ReadAsStringAsync();
    try
    {
        XmlDocument _doc = new XmlDocument();
        _doc.LoadXml(_data);
        return Request.CreateResponse(HttpStatusCode.OK, JObject.Parse(_doc.InnerText));
    }
    catch (Exception jex)
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest, jex.Message);
    }
}
else
    return Task.FromResult<HttpResponseMessage>(Request.CreateResponse(HttpStatusCode.NotFound)).Result;

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