如何从 ASP.NET Web 服务生成 JSONP 以进行跨域调用?
Posted
技术标签:
【中文标题】如何从 ASP.NET Web 服务生成 JSONP 以进行跨域调用?【英文标题】:How can I produce JSONP from an ASP.NET web service for cross-domain calls? 【发布时间】:2012-12-22 16:28:16 【问题描述】:我编写了一个返回 JSON 的网络服务,我尝试使用 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;
谢谢。
【问题讨论】:
我只使用基于此的 ASP.Net Web API 完成它:***.com/a/9422178/585552 它可能会给你一些想法... 尝试在 Web Method 的正文中添加Response.AddHeader("Access-Control-Allow-Origin","*")
【参考方案1】:
好的,我最终自己想通了。由于我发现很难在网络上找到完整的工作解决方案,因此我决定在此处记录我的工作解决方案。
JSONP 响应只是包装在函数调用中的标准 JSON 字符串。 ASP.NET 似乎没有提供任何直接以这种格式返回响应的方法,但是自己执行此操作非常简单。但是,您必须覆盖 JSON 编码的默认方法。
以下是 JSONP 的示例。
functionName( name: 'value';);
..现在这一点:
name: 'value';
只是任何 JSON 序列化程序都会为您提供的标准 JSON,所以我们需要做的就是添加函数调用包装器。不幸的是,这样做意味着我们必须“取消连接”(或绕过)现有的 JSON 编码,当您从 Web 服务函数返回对象时,框架会透明地处理该 JSON 编码。
这是通过使用我们自己的代码将 JSONP 写入输出流 (Response) 来完全覆盖来自 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
【讨论】:
您没有在 ajax 请求中发送callback
。你怎么能用c#方法接收它?
@Sami - 由 JQuery 自动添加
嗨@NickG 如何发送多个数据参数,我尝试了`data: mNo: txtLoginMobile, pWord: txtLoginPassword,` 并使用了public void checkLogin(string callback, string mNo, string pWord)
但是,它给出了'500 Internal Server Error'。可以直接运行webservice。请指教。我正在使用实体序列化。
@Ravimalya 使用 Fiddler 准确检查正在发送的内容,并确保将其编码为有效的 JSON。检查浏览器中的 JS 控制台错误。
@Ravimally 参数的名称需要与服务器端 C# 函数上的名称完全匹配(区分大小写)。【参考方案2】:
谢谢尼克,这是一个很好的答案,解决了我最初在网上也很难找到的问题。对我也很好。
希望确保这行帖子得到应有的关注。
只是想补充一点,我使用了内置的序列化程序 (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();
【讨论】:
响应的内容类型需要是“application/javascript”而不是“application/json”。如果您使用 X-Content-Type-Options=nosniff,它将不适用于“application/json”【参考方案3】:如果有人正在寻找样品,如何从ASP.NET
Web API
返回JSONP
操作:
// 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)));
【讨论】:
以上是关于如何从 ASP.NET Web 服务生成 JSONP 以进行跨域调用?的主要内容,如果未能解决你的问题,请参考以下文章
从 ASP.Net Web 服务 json 输出中删除“d”对象
如何使用 json 从 sql server ASP.net 中检索数据
如何使用适合导入的 Web Api 帮助页面从 Web Api 2 项目生成 JSON Postman 集合
ASP.NET - 使用 jQuery 实现基于 JSON 的 Web 服务的正确方法是啥?