2011-01-25 12 views
7

Phil Haack tiene un excelente blog post sobre cómo usar JSON, enlace de datos y validación de datos.ASP.NET MVC 3 JSONP: ¿Funciona esto con JsonValueProviderFactory?

Introduzca la "misma restricción de seguridad de la política de origen" del navegador. y JSONP donde usa $ .getJSON() para recuperar el contenido.

¿Hay una forma de MVC 3 integrada para hacer esto, o tengo que seguir los consejos de posts like this? ¿Puedes publicar contenido? Pregunto porque mi colega implementó un JsonPfilterAttribute entre otras cosas para que esto funcione. Es obvio que es preferible para evitar que si algo ya existe en MVC 3.

Editar:

Resumen: todo funciona con la excepción de acceder a una variable POST, es decir, cómo accedo a la variable POST en ¿el contexto? (comentario marcándolo en la última sección de código)

Me elegidos para utilizar este formato para llamar al servidor:

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

que produce esta respuesta:

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

Y funciona todo esto muy bien si uso un GET. Sin embargo, todavía no puedo hacer que funcione como POST. Aquí está el código original publicado por Nathan Bridgewater here. Esta línea no encuentra los datos POST:

context.HttpContext.Request["callback"]; 

O yo debería estar accediendo Form de alguna manera, o los validadores de datos MVC están desnudando a cabo las variables POST.

¿Cómo se debe escribir context.HttpContext.Request["callback"]; para acceder a la variable POST o MVC está eliminando estos valores por alguna razón?

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

Respuesta

39

En cuanto a la recepción de una cadena JSON y enlazarlo a un modelo que respecta a la JsonValueProviderFactory hace este trabajo fuera de la caja en ASP.NET MVC 3. Pero no hay nada incorporado para dar salida a JSONP. Se podría escribir una costumbre 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(")"); 
     } 
    } 
} 

Y luego, en su acción de controlador:

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

que podría ser consumido de otro dominio con $.getJSON():

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

he editado la pregunta para reflexionar su respuesta (buena respuesta), solo necesita una pieza más trabajando. –

+2

@Dr. Zim, 'JSONP' funciona solo con solicitudes GET implementadas por jQuery. Aquí no hay magia, jQuery simplemente inyecta una etiqueta '