web-dev-qa-db-fra.com

Comment puis-je produire JSONP à partir d'un service Web ASP.NET pour les appels interdomaines?

J'ai écrit un webservice qui retourne JSON et j'ai essayé de l'appeler en utilisant jQuery comme ceci:

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

Cependant, le code n'appelle jamais la fonction de réussite, bien que l'appel du service Web ait réussi lors de l'examen du trafic HTTP à l'aide de Fiddler. Je pense que c'est parce que mon service Web renvoie du JSON brut au lieu de JSONP.

Comment puis-je produire JSONP en tant que réponse à partir d'une méthode de service Web .NET standard comme celle-ci:

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

Merci.

20
NickG

OK, je l'ai finalement compris moi-même. Comme je trouvais si difficile de trouver une solution de travail complète sur le Web, j'ai décidé de documenter ma solution de travail ici.

Une réponse JSONP n'est qu'une chaîne JSON standard enveloppée dans un appel de fonction. ASP.NET ne semble pas fournir de moyen de renvoyer directement la réponse dans ce format, mais il est très simple de le faire vous-même. Cependant, vous devez remplacer la méthode par défaut d'encodage JSON.

Voici un exemple de JSONP.

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

..maintenant ce bit: { name: 'value';} est juste du JSON standard que tout sérialiseur JSON vous donnera, donc tout ce que nous devons faire est de virer de bord sur le wrapper d'appel de fonction. Malheureusement, cela signifie que nous devons "déconnecter" (ou contourner) l'encodage JSON existant qui est géré de manière transparente par le framework lorsque vous retournez un objet à partir de la fonction de service Web.

Cela se fait en remplaçant complètement la réponse de la fonction de service Web en écrivant le JSONP dans le flux de sortie (Response) en utilisant notre propre code. C'est en fait assez simple et j'ai inclus un exemple ci-dessous.

Vous pouvez utiliser soit le serializer intégré DataContractJsonSerializer (à partir de l'espace de noms System.Runtime.Serialization.Json dans ASP.NET 3.5+) ou NewtonSoft JSON , et les deux exemples sont indiqué ci-dessous. Je préfère utiliser le NewtonSoft JSON (installé à partir de nuget) plutôt que le sérialiseur JSON intégré car je trouve qu'il vous donne plus de contrôle et peut également produire un JSON lisible par l'homme bien formaté pour le débogage. C'est aussi beaucoup plus rapide sur papier!

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

Cette méthode peut ensuite être appelée à l'aide du code JQuery suivant:

$.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
}
43
NickG

Merci Nick, c'était une excellente réponse à un problème que j'ai eu du mal à trouver au début en ligne. Ça a très bien fonctionné pour moi aussi.

Je voulais m'assurer que cette ligne de poste a attiré l'attention qu'elle mérite.

Je voulais juste ajouter que j'ai utilisé le sérialiseur intégré (System.Runtime.Serialization.Json) et cela a fonctionné comme un charme aussi.

        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();
3
Joe Ramos

Si quelqu'un cherche un exemple, comment renvoyer JSONP de ASP.NETWeb API action:

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

JsonpResult classe d'assistance encapsulant l'habillage 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)));
            }
        }
    }
}
2
Dmitry Pavlov