ASP.NET MVC 3 JSONP: это работает с JsonValueProviderFactory? - PullRequest
7 голосов
/ 25 января 2011

У Фила Хаака есть отличное сообщение в блоге о том, как использовать JSON, привязку данных и проверку данных.

Введите в браузере "то же ограничение безопасности политики происхождения".и JSONP, где вы используете $ .getJSON () для извлечения контента.

Есть ли встроенный в MVC 3 способ сделать это, или мне нужно следовать совету сообщений, подобных этой ?Вы можете разместить контент?Я спрашиваю, потому что мой коллега реализовал JsonPfilterAttribute среди прочего, чтобы сделать эту работу.Очевидно, что лучше избегать этого, если что-то уже существует в MVC 3.

Редактировать:

Резюме: все работает, за исключением доступа к POSTпеременная, т. е. как мне получить доступ к переменной POST в контексте? (комментарий помечает ее в последнем разделе кода)

Я решил использовать этот формат для вызова сервера:

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

, который дает такой ответ:

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

И все это работает очень хорошо, если я использую GET.Тем не менее, я все еще не могу заставить это работать как POST.Вот оригинальный код, опубликованный Натаном Бриджуотером здесь .Эта строка не находит данные POST:

context.HttpContext.Request["callback"];

Либо я должен каким-то образом получить доступ к Form, либо валидаторы данных MVC удаляют переменные POST.

Как записать context.HttpContext.Request["callback"]; для доступа к переменной POST или MVC по каким-то причинам отбрасывает эти значения?

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

1 Ответ

39 голосов
/ 25 января 2011

Что касается получения строки JSON и ее привязки к модели, JsonValueProviderFactory выполняет эту работу из коробки в ASP.NET MVC 3. Но для вывода JSONP нет ничего встроенного. Вы можете написать кастом 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(")");
        }
    }
}

А затем в вашем контроллере действие:

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

, который может быть использован из другого домена с $.getJSON():

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