5

jQueryを使用してASMXWebサービスにJSONP呼び出しを行う方法を理解しようとしています。これらは私がすでに読んだページのほんの一部であり、解決策は見つかりませんでした。

jquery "jsonp"を使用して外部Webサービスを呼び出す方法は?

jQueryを使用してクロスドメインJSONをASP.NETに投稿する

JQueryを使用してASP.netWebサービスにアクセス中にエラーが発生しました-JSONP

jQuery.ajaxと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/

等...

これが私のサンプルの.NETWebメソッドです。

[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' }
});

[ScriptService]で装飾されたWebサービスがあり、ScriptHandlerFactoryを使用して*.asmxを処理するようにweb.configを構成しています。

Content-Typeが'application/ json'の場合にASMXが使用する組み込みのJSONシリアル化を使用してみましたが、いくつかの問題があります。パディングをラップする必要があるため、JSONPでは機能しません。 .NETがサポートしていないJSON。また、JSONをシリアル化するためにASMXは「ContentType:application / json」ヘッダーを予期しているため、機能しませんが、jQueryはGETリクエストを送信するときにContentTypeヘッダーを無視します(おそらくコンテンツを送信していないため)。Global.asax Application_BeginRequest()でRequest.ContentType = "application / json"を設定しようとしましたが、何もしませんでした。また、beforeSend()を使用してjQueryでリクエストヘッダーを設定しようとしましたが、うまくいきませんでした。

そのため、組み込みの.NETパイプラインを使用して簡単に動作させることができなかったため、応答本文への生の書き込みを実行する独自の手法(したがって、SendJsonP()メソッド)を使用しました。GetEmployee()Webメソッドが値を返さない場合でも、ContentType of'アプリケーションを渡すことができないため、オブジェクトをXMLにシリアル化しようとしているため、.NETはシリアル化エラーをスローしているため、まだ問題があります。 /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 [....] }

それで、結局、私はいくつかの質問を残されています:

  1. 組み込みの.NETシリアル化を使用してJSONにパディングを適用し、それをクライアントに返す方法はありますか?

  2. 自分でロールする必要があるようですが、パラメーターを含むJSONPクエリをASMXページに送信する場合、クエリ文字列はどのように表示されますか?JSON形式である必要がありますが、次のことを試したところ、「無効なJSONプリミティブ」エラーが発生しました。

    GetEmployee?{callback: "createMember"、memberId: "99999999"}

    GetEmployee?callback = {callback: "createMember"}&memberId = {memberId: "123456789"}

  3. jQueryにJSONPGETリクエストでContentTypeヘッダーを送信させる方法はありますか?

4

1 に答える 1

5

JSONP リクエストを手動で処理することにしました。私のソリューションでは、ユーザーは、JSONP の結果が必要であることを示すために、GET 要求を介して 2 つのクエリ文字列パラメーター (callback=callbackFunctionName と jsonp=true) を提供する必要があります。これらの両方が受信された場合は、手動で処理します。それ以外の場合、要求は標準の ASMX プロセッサに続行されます。

HttpApplication.BeginRequest イベントの呼び出しとして追加した新しい JsonPUtility ヘルパー クラスを作成しました。

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);
    }
} 

これが将来誰かに役立つことを願っています。

ありがとう、ヴィンス

于 2012-12-18T17:34:32.567 に答える