20

我编写了一个返回 JSON 的 web 服务,并尝试使用 jQuery 调用它,如下所示:

$.ajax({
    contentType: "application/json; charset=utf-8",
    url: "http://examplewebsite.com/service.asmx/GetData",
    data: { projectID: 1 },
    dataType: "jsonp",
    success: function () {alert("success");}
});

然而,代码从不调用成功函数,尽管在使用 Fiddler 查看 HTTP 流量时 Web 服务调用成功。我认为这是因为我的 Web 服务返回的是原始 JSON 而不是 JSONP。

如何生成 JSONP 作为来自标准 .NET Web 服务方法的响应,如下所示:

[WebMethod(), ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public Project GetData(int projectID)
{
    Project p = new Project();
    p.Name = "foobar";
    return p;
}

谢谢。

4

3 回答 3

44

好的,我最终自己弄清楚了。由于我发现很难在网络上找到完整的工作解决方案,因此我决定在此处记录我的工作解决方案。

JSONP 响应只是包装在函数调用中的标准 JSON 字符串。ASP.NET 似乎没有提供任何直接以这种格式返回响应的方法,但是自己执行此操作非常简单。但是,您必须覆盖 JSON 编码的默认方法。

下面是 JSONP 的示例。

functionName({ name: 'value';});

..现在这一点: { name: 'value';} 只是任何 JSON 序列化程序都会给你的标准 JSON,所以我们需要做的就是添加函数调用包装器。不幸的是,这样做意味着我们必须“取消连接”(或绕过)现有的 JSON 编码,当您从 Web 服务函数返回对象时,该编码由框架透明地处理。

这是通过使用我们自己的代码将 JSONP 写入输出流(响应)来完全覆盖来自 Web 服务功能的响应来完成的。这实际上非常简单,我在下面提供了一个示例。

您可以使用内置的DataContractJsonSerializer(来自 ASP.NET 3.5+ 中的 System.Runtime.Serialization.Json 命名空间)或NewtonSoft JSON序列化程序,两个示例如下所示。我更喜欢使用NewtonSoft JSON(从 nuget 安装)而不是内置的 JSON 序列化程序,因为我发现它可以为您提供更多控制,并且还可以输出格式良好的人类可读 JSON 以进行调试。它在纸上也快得多!

[WebMethod()]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetData(int projectID, string callback)
{
    List<Video> videos = null;
    // <code here to populate list on line above>

    // Method 1: use built-in serializer:
    StringBuilder sb = new StringBuilder();
    JavaScriptSerializer js = new JavaScriptSerializer();
    sb.Append(callback + "(");
    sb.Append(js.Serialize(videos));
    sb.Append(");");    

    // Method 2: NewtonSoft JSON serializer (delete as applicable)
    // StringBuilder sb = new StringBuilder();
    // sb.Append(callback + "(");
    // sb.Append(JsonConvert.SerializeObject(videos, Formatting.Indented)); // indentation is just for ease of reading while testing
    // sb.Append(");");     

    Context.Response.Clear();
    Context.Response.ContentType = "application/json";
    Context.Response.Write(sb.ToString());
    Context.Response.End();
}

然后可以使用以下 JQuery 代码调用此方法:

$.ajax({
    crossDomain: true,
    contentType: "application/json; charset=utf-8",
    url: "http://examplewebsite.com/service.asmx/GetData",
    data: { projectID: 1 }, // example of parameter being passed
    dataType: "jsonp",
    success: onDataReceived
});

function onDataReceived(data)
{
    alert("Data received");
    // Do your client side work here.
    // 'data' is an object containing the data sent from the web service 
    // Put a JS breakpoint on this line to explore the data object
}
于 2013-01-09T13:39:38.637 回答
3

谢谢尼克,这是一个很好的答案,我最初在网上也很难找到这个问题。对我也很好。

想确保这行帖子得到应有的关注。

只是想补充一点,我使用了内置的序列化程序(System.Runtime.Serialization.Json),它也很有吸引力。

        List<orderHistory> orderHistory = null;

        StringBuilder sb = new StringBuilder();
        JavaScriptSerializer js = new JavaScriptSerializer();
        sb.Append(callback + "(");
        sb.Append(js.Serialize(orderHistory));
        sb.Append(");");

        Context.Response.Clear();
        Context.Response.ContentType = "application/json";
        Context.Response.Write(sb.ToString());
        Context.Response.End();
于 2013-06-06T01:06:50.130 回答
2

如果有人正在寻找如何JSONPASP.NET Web API行动中返回的样本:

// GET api/values
public JsonpResult Get()
{
    var values = new string[] { "value1", "value2" };
    return new JsonpResult(values);
}

JsonpResult封装包装的助手类JSONP

public class JsonpResult : JsonResult
{
    object _data = null;

    public JsonpResult(object data)
    {
        _data = data;
    }

    public override void ExecuteResult(ControllerContext controllerContext)
    {
        if (controllerContext != null)
        {
            var response = controllerContext.HttpContext.Response;
            var request = controllerContext.HttpContext.Request;

            var callBackFunction = request["callback"];
            if (string.IsNullOrEmpty(callBackFunction))
            {
                throw new Exception("Callback function name must be provided in the request!");
            }
            response.ContentType = "application/x-javascript";
            if (_data != null)
            {
                var serializer = new JavaScriptSerializer();
                response.Write(string.Format("{0}({1});", callBackFunction, serializer.Serialize(_data)));
            }
        }
    }
}
于 2017-04-25T14:21:41.027 回答