【问题标题】:ASP.NET MVC 3 JSONP: Does this work with JsonValueProviderFactory?ASP.NET MVC 3 JSONP:这适用于 JsonValueProviderFactory 吗?
【发布时间】:2011-06-15 06:38:53
【问题描述】:

Phil Haack 在如何使用 JSON、数据绑定和数据验证方面拥有出色的 blog post

输入浏览器的“同源策略安全限制”。和 JSONP,您使用 $.getJSON() 来检索内容。

是否有内置的 MVC 3 方法可以做到这一点,还是我需要遵循 posts like this 的建议?可以发内容吗?我问是因为我的同事实施了一个 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。这是 Nathan Bridgewater here 发布的原始代码。此行没有找到 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;
        }
    }
}

【问题讨论】:

    标签: asp.net-mvc-3 jsonp model-binding


    【解决方案1】:

    就接收 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);
    });
    

    【讨论】:

    • 我编辑了这个问题以反映你的答案(很好的答案),只需要再工作。
    • @Dr. Zim, JSONP 仅适用于 jQuery 实现的 GET 请求。这里没有魔法,jQuery 只是将<script> 标签注入到指向远程服务器的托管页面的 DOM 中,正如您所知,<script> 标签只能向该远程资源发送 GET 请求。所以甚至不要尝试使用 JSONP 的$.ajax({ type: 'POST' });,这永远不会奏效。事实上,你可以通过使用隐藏的 iframe 和隐藏的表单来使其工作,但这不是 jQuery 用来实现 JSONP 的。
    • 但要回答您的一般问题,context.HttpContext.Request["jsoncallback"]; 也会查看已发布的值(如果存在)。
    • 太棒了。我会在不知不觉中一直追求它。
    • 我在考虑使用 ActionFilterAttribute 但我认为您的派生类是一个更好的解决方案,谢谢。
    猜你喜欢
    • 2011-05-20
    • 1970-01-01
    • 2012-12-25
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    • 2012-06-11
    相关资源
    最近更新 更多