2011-01-25 20 views
7

Phil Haack ha un eccellente blog post su come utilizzare JSON, associazione dati e convalida dei dati.ASP.NET MVC 3 JSONP: Funziona con JsonValueProviderFactory?

Immettere "lo stesso limite di sicurezza della politica di origine del browser". e JSONP dove usi $ .getJSON() per recuperare il contenuto.

Esiste un sistema MVC 3 integrato per eseguire questa operazione oppure è necessario seguire il consiglio di posts like this? Puoi pubblicare contenuti? Chiedo perché il mio collega ha implementato un JsonPfilterAttribute tra le altre cose per farlo funzionare. E 'ovviamente preferito evitare che se qualcosa esiste già nella MVC 3.

Edit:

Sommario: tutto funziona con l'eccezione di accesso a una variabile POST, vale a dire, come faccio ad accedere alla variabile POST in il contesto? (commento marcatura che nell'ultima sezione di codice)

ho scelto di utilizzare questo formato per chiamare il server:

$.ajax({ 
    type: "GET", 
    url: "GetMyDataJSONP", 
    data: {}, 
    contentType: "application/json; charset=utf-8", 
    dataType: "jsonp", 
    jsonpCallback: "randomFunctionName" 
}); 

che produce questa risposta:

randomFunctionName([{"firstField":"111","secondField":"222"}]); 

E tutto questo funziona molto bene se uso uno GET. Tuttavia, non riesco ancora a far funzionare questo come POST. Ecco il codice originale pubblicato da Nathan Bridgewater here. Questa linea non trova i dati POST:

context.HttpContext.Request["callback"]; 

O dovrei accederanno Form in qualche modo, o i validatori dati MVC stanno escludendo le variabili POST.

Come deve essere scritto context.HttpContext.Request["callback"]; per accedere alla variabile POST oppure MVC estrapola questi valori per qualche motivo?

namespace System.Web.Mvc 
{ public class JsonpResult : ActionResult 
    { public JsonpResult() {} 

     public Encoding ContentEncoding { get; set; } 
     public string ContentType { get; set; } 
     public object Data { get; set; } 
     public string JsonCallback { get; set; } 

     public override void ExecuteResult(ControllerContext context) 
     { if (context == null) 
       throw new ArgumentNullException("context"); 

      this.JsonCallback = context.HttpContext.Request["jsoncallback"]; 

      // This is the line I need to alter to find the form variable: 

      if (string.IsNullOrEmpty(this.JsonCallback)) 
       this.JsonCallback = context.HttpContext.Request["callback"]; 

      if (string.IsNullOrEmpty(this.JsonCallback)) 
       throw new ArgumentNullException(
        "JsonCallback required for JSONP response."); 

      HttpResponseBase response = context.HttpContext.Response; 

      if (!String.IsNullOrEmpty(ContentType)) 
       response.ContentType = ContentType; 
      else 
       response.ContentType = "application/json; charset=utf-8"; 

      if (ContentEncoding != null) 
       response.ContentEncoding = ContentEncoding; 

      if (Data != null) 
      { JavaScriptSerializer serializer = new JavaScriptSerializer(); 
       response.Write(string.Format("{0}({1});", this.JsonCallback, 
        serializer.Serialize(Data))); 
    } } } 

    //extension methods for the controller to allow jsonp. 
    public static class ContollerExtensions 
    { 
     public static JsonpResult Jsonp(this Controller controller, 
       object data) 
     { 
      JsonpResult result = new JsonpResult(); 
      result.Data = data; 
      result.ExecuteResult(controller.ControllerContext); 
      return result; 
     } 
    } 
} 

risposta

39

Per quanto riguarda la ricezione di una stringa JSON e legandolo a un modello è interessato il JsonValueProviderFactory fa questo lavoro, fuori dalla scatola in ASP.NET MVC 3. Ma non c'è nulla built-in per l'emissione JSONP. Si potrebbe scrivere un custom JsonpResult:

public class JsonpResult : JsonResult 
{ 
    public override void ExecuteResult(ControllerContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException("context"); 
     } 
     var request = context.HttpContext.Request; 
     var response = context.HttpContext.Response; 
     string jsoncallback = (context.RouteData.Values["jsoncallback"] as string) ?? request["jsoncallback"]; 
     if (!string.IsNullOrEmpty(jsoncallback)) 
     { 
      if (string.IsNullOrEmpty(base.ContentType)) 
      { 
       base.ContentType = "application/x-javascript"; 
      } 
      response.Write(string.Format("{0}(", jsoncallback)); 
     } 
     base.ExecuteResult(context); 
     if (!string.IsNullOrEmpty(jsoncallback)) 
     { 
      response.Write(")"); 
     } 
    } 
} 

E poi nella vostra azione di controllo:

public ActionResult Foo() 
{ 
    return new JsonpResult 
    { 
     Data = new { Prop1 = "value1", Prop2 = "value2" }, 
     JsonRequestBehavior = JsonRequestBehavior.AllowGet 
    }; 
} 

che potrebbe essere consumato da un altro dominio con $.getJSON():

$.getJSON('http://domain.com/home/foo?jsoncallback=?', function(data) { 
    alert(data.Prop1); 
}); 
+0

Ho curato la questione per riflettere la tua risposta (bella risposta), solo bisogno di un altro pezzo di lavoro. –

+2

@Dr. Zim, 'JSONP' funziona solo con le richieste GET implementate da jQuery. Qui non c'è magia, jQuery inserisce semplicemente un tag '