我正在竭尽全力试图弄清楚如何使用jQuery对ASMX Web服务进行JSONP调用。这些只是我已经阅读并且没有找到任何解决方案的一些页面:

How to call external webservice using jquery "jsonp"?

Posting cross-domain JSON to ASP.NET with jQuery

Error while accessing ASP.net webservice using JQuery - JSONP

Set Headers with jQuery.ajax and JSONP?

http://www.codeproject.com/Articles/43038/Accessing-Remote-ASP-NET-Web-Services-Using-JSONP

http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/

等等...

这是我的示例.NET Web方法:

[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetEmployee(string employeeId, string callback)
{
    // Get the employee object from the Factory.
    Employee requestedEmployee = EmployeeFactory.GetEmployee(employeeId);

    if(requestedEmployee != null)
    {
        // Return the padded JSON to the caller.
        CrossDomainUtility.SendJsonP(callback, requestedEmployee.ToJson());
    }
}

这是SendJsonP():
public static void SendJsonP(string callback, string json)
{
    // Clear any response that has already been prepared.
    HttpContext.Current.Response.Clear();

    // Set the content type to javascript, since we are technically returning Javascript code.
    HttpContext.Current.Response.ContentType = "application/javascript";

    // Create a function call by wrapping the JSON with the callback function name.
    HttpContext.Current.Response.Write(String.Format("{0}({1})", callback, json));

    // Complete this request, to prevent the ASMX web service from doing anything else.
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

这是一些示例jquery代码:
$.ajax({
    url: 'http://devserver/service/service.asmx/GetEmployee',
    dataType: 'jsonp',
    contentType: 'application/json',
    data: { employeeId: '123456789' }
});

我的Web服务装饰有[ScriptService],并且将我的web.config配置为使用ScriptHandlerFactory处理* .asmx。

我尝试使用Content-Type为'application/json'时ASMX使用的内置JSON序列化,但是有两个问题:由于需要用空格填充,因此它不适用于JSONP。 .NET不支持的JSON。它也不起作用,因为为了序列化JSON,ASMX需要一个'ContentType:application/json' header ,但是jQuery在发送GET请求时会忽略ContentType header (大概是因为它没有发送任何内容)。我试过在Global.asax Application_BeginRequest()中设置Request.ContentType =“application/json”,但这没有任何作用。我也尝试过使用beforeSend()在jQuery中设置请求 header ,但没有运气。

因此,由于无法使用内置的.NET管道轻松使它正常工作,因此我滚动了自己的技术,该技术对Response主体执行原始写入(因此,使用SendJsonP()方法)。但是我仍然遇到问题,因为即使GetEmployee()Web方法未返回值,.NET也会引发序列化错误,因为它试图将对象序列化为XML,因为我无法传递ContentType的“application”/json'和GET请求。

因此,由于无论如何我都无法让jQuery添加ContentType,因此我想通过仅使用Fiddler2创建手动请求来测试我的Web服务:
GET http://devserver/service/service.asmx/GetEmployee?callback=createMember&memberId=123456789
User-Agent: Fiddler
Content-Type: application/json
Host: devserver

...并且由于我的参数不是JSON,因此出现以下错误:
{"Message":"Invalid JSON primitive: createMember [....] }

所以毕竟,我还有几个问题:
  • 是否可以使用内置.NET序列化将填充应用于JSON并将其返回给客户端?
  • 既然我不得不自己动手,那么在向ASMX页面发送带有参数的JSONP查询时,我的查询字符串应如何显示?它必须为JSON格式,但是我尝试了以下操作并收到“无效的JSON原语”错误:

    GetEmployee?{callback:“createMember”,memberId:“99999999”}

    GetEmployee?callback = {callback:“createMember”}&memberId = {memberId:“123456789”}
  • 有什么方法让jQuery通过JSONP GET请求发送ContentType header ?
  • 最佳答案

    我刚刚决定手动处理JSONP请求。在我的解决方案中,用户必须通过GET请求提供两个查询字符串参数,以表明他们想要JSONP结果:callback = callbackFunctionName和jsonp = true。如果两者都收到,我将进行手动处理,否则请求将继续发送到标准ASMX处理器上。

    我创建了一个新的JsonPUtility帮助器类,该类已作为调用添加到HttpApplication.BeginRequest事件中:

    public class Global : System.Web.HttpApplication
    {
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            // Requests for JSONP requests must be handled manually due to the limitations of JSONP ASMX.
            JsonPUtility.ProcessJsonPRequest();
        }
    }
    

    这是JsonPUtility类:
    /*
     *  JSON is Javascript Object Notation, a standard way of serializing objects in Javascript and
     *  other languages.  For more information see http://www.json.org/.
     *
     *  JSONP is a technique to enable the execution of Javascript that resides in a different domain.  It
     *  works by exploiting the exception granted to the <script> tag which allows content to be loaded
     *  from a different domain.  By contrast, making "regular" AJAX calls to a different domain will
     *  not work, usually throwing an "Access Denied" or "No Transport" error.
     *
     *  JSONP (the "P" stands for "Padding") is regular JSON wrapped in a Javascript function call (the
     *  "Padding").  Take for example this standard JSON object:
     *      { "Name" : "John", "Age" : 14, "Gender" : "Male" }
     *
     *  JSONP will turn that JSON into a valid Javascript function call by using the JSON as an argument
     *  to the callback function provided by the caller.  For example, if the caller provides a callback
     *  value of 'processResults', the resulting JSONP looks like this:
     *      processResults({ "Name" : "John", "Age" : 14, "Gender" : "Male" });
     *
     *  The processResults() function will then be able to use the JSON object just like a regular object.
     *  Note that the callback function must be implemented on the page that receives the JSONP, otherwise
     *  a standard Javascript error will occur.
     *
     *  The real "trick" to cross-domain script execution is dynamically creating a "script" tag on the
     *  client for every JSONP request, using the web service URL as the "src" attribute.  This will cause
     *  the browser to automatically download and execute the script that is loaded from the URL,
     *  effectively bypassing the same-domain origin policy.
     */
    public static class JsonPUtility
    {
        /*
         * SendJsonP(string callback, string json)
         *
         *  This method takes the provided 'json' string, wraps it so that it is a parameter to the 'callback'
         *  function, clears any existing response text, writes the resulting Javascript code to the
         *  response, and ends the response.
         *
         *  For example, given these two parameters...
         *      callback    = "callbackFunction"
         *      json        = "{ 'FOO': 'BAR', 'JOO': 'MAR' }"
         *
         *  ... the following code is returned to the client in an HTTP response with a content-type of
         *  'application/javascript':
         *      callbackFunction({ 'FOO': 'BAR', 'JOO': 'MAR' });
         *
         */
        public static void SendJsonP(string callback, string json)
        {
            // Clear any response that has already been prepared.
            HttpContext.Current.Response.Clear();
    
            // Set the content type to javascript, since we are technically returning Javascript code.
            HttpContext.Current.Response.ContentType = "application/javascript";
    
            // Create a function call by wrapping the JSON with the callback function name.
            HttpContext.Current.Response.Write(String.Format("{0}({1});", callback, json));
    
            // Complete this request, to prevent the ASMX web service from doing anything else.
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
    
        /*
         * bool IsJsonPRequest()
         *
         *  Determines whether or not the current request is for JSONP javascript code.
         *
         *  This is the criteria for making a JSONP request to this web service:
         *      1. Include the jsonp parameter.  Its value is not important - we recommend using jsonp=true
         *         to increase clarity.
         *      2. Include the callback=string parameter so we know what function call to wrap around
         *         the requested JSON.
         */
        public static bool IsJsonPRequest()
        {
            // Store the context to the current request.
            var request = HttpContext.Current.Request;
    
            // If a 'jsonp' or a 'callback' parameter was not provided, this isn't a JSONP request.
            if (request.QueryString["jsonp"] == null || String.IsNullOrEmpty(request.QueryString["callback"]))
                return false;
    
            // Since both parameters were provided, this is a jsonp request.
            return true;
        }
    
        /*
         * ProcessJsonPRequest()
         *
         *  Manual processing is required for JSONP requests due to limitations in ASMX web services.
         */
        public static void ProcessJsonPRequest()
        {
            // If this isn't a JSONP request, simply return and continue regular request processing.
            if (!IsJsonPRequest())
                return;
    
            // Store the context to the HTTP request.
            var request = HttpContext.Current.Request;
    
            // Store the callback function that will be wrapped around the JSON string.
            string callback = request.QueryString["callback"];
    
            // Create a place to store the object that will be serialized into JSON.
            object objectForJson = null;
    
            // Store the web service method name that is being requested.  It is always going to follow the
            // final slash after the .asmx extension, and will continue until the question mark that marks
            // the query string.
            int     methodNameStartIndex = request.RawUrl.ToUpper().IndexOf(".ASMX/") + 6;
            int     methodNameLength = (request.RawUrl.IndexOf("?")) - methodNameStartIndex;
            string  requestMethod = request.RawUrl.Substring(methodNameStartIndex, methodNameLength);
    
            // Create a place to store the string ID of the object that is going to be looked-up.
            string lookupId = null;
    
            // Based on the request URL, figure out the method that will create a reference for the objectForJson variable.
            switch (requestMethod)
            {
                case "GetEmployee":
                    // Get the employee's ID from the query string.
                    lookupId = request.QueryString["employeeId"];
    
                    // If the employee ID was provided, get a Employee object.
                    if (!String.IsNullOrEmpty(lookupId))
                        objectForJson = Factory.GetEmployee(lookupId);
    
                    break;
    
                case "GetManager":
                    // Get the manager's ID from the query string.
                    lookupId = request.QueryString["managerId"];
    
                    // If the manager ID was provided, get a Manager object.
                    if (!String.IsNullOrEmpty(lookupId))
                        objectForJson = Factory.GetManager(lookupId);
    
                    break;
    
                case "GetOrder":
                    // Get the order ID from the query string.
                    lookupId = request.QueryString["orderId"];
    
                    // If the order ID was provided, get the  object.
                    if (!String.IsNullOrEmpty(lookupId))
                        objectForJson = Factory.GetOrder(lookupId);
    
                    break;
    
                default:
                    // If the request method wasn't handled, throw an exception.
                    throw new ArgumentException("Unknown request method '" + requestMethod + "'.");
            }
    
            // Create a .NET framework object to serialize the object into JSON.
            JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
    
            // Serialize the object into JSON.  If objectForJson is null, the callback function will be passed a parameter of null (e.g. callback(null)).
            string json = jsonSerializer.Serialize(objectForJson);
    
            // Send the JSONP string back to the caller.
            SendJsonP(callback, json);
        }
    }
    

    我希望这可以在将来对某人有所帮助。

    谢谢,
    文斯

    关于jquery - JSONP和ASMX Web服务,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13884253/

    10-13 07:05