【问题标题】:Retrieve a value from a request with content type application/json从内容类型为 application/json 的请求中检索值
【发布时间】:2012-05-31 15:55:51
【问题描述】:

我有以下脚本正在向 MVC 中的控制器发送数据:

$.ajax({
    url: '/products/create',
    type: 'post',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify({
        'name':'widget',
        'foo':'bar'
    })
});

我的控制器如下所示:

[HttpPost]
public ActionResult Create(Product product)
{
    return Json(new {success = true});
}

public class Product 
{ 
    public string name { get; set; }
}

有没有一种方法可以在我的控制器操作中获取“foo”变量而无需

  • 修改模型
  • 修改动作的签名

如果是常规的表单提交,我可以访问 Request.Form["foo"],但是这个值为 null,因为它是通过 application/json 提交的。

我希望能够从操作过滤器访问此值,这就是我不想修改签名/模型的原因。

【问题讨论】:

    标签: c# asp.net-mvc json


    【解决方案1】:

    我今天想做几乎完全相同的事情,但发现这个问题没有答案。我也用与 Mark 类似的解决方案解决了它。

    这对我在 asp.net MVC 4 中非常有效。也许可以帮助其他人阅读这个问题,即使它是一个旧问题。

            [HttpPost]
            public ActionResult Create()
            {
                string jsonPostData;
                using (var stream = Request.InputStream)
                {
                    stream.Position = 0;
                    using (var reader = new System.IO.StreamReader(stream))
                    {
                        jsonPostData = reader.ReadToEnd();
                    }
                }
                var foo = Newtonsoft.Json.JsonConvert.DeserializeObject<IDictionary<string, object>>(jsonPostData)["foo"];
    
                return Json(new { success = true });
            }
    

    重要的部分是重置流的位置,因为它已经被一些 MVC 内部代码或其他东西读取。

    【讨论】:

    • 虽然这可行,但我面临的问题是我在 onAuthorize 上读取流,现在流为空,因此当控制器收到请求正文时,其中没有任何内容。
    【解决方案2】:

    我希望能够从动作过滤器中访问该值,并且 这就是我不想修改签名/模型的原因。

    如果不更改方法的签名,从 Action 过滤器访问值会很棘手。原因从这个post会更好理解。

    此代码将在授权过滤器或模型绑定之前运行的代码中运行。

    public class CustomFilter : FilterAttribute, IAuthorizationFilter
      {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
          var request = filterContext.RequestContext.HttpContext.Request;
    
          var body = request.InputStream;
          var encoding = request.ContentEncoding;
          var reader = new StreamReader(body, encoding);
          var json = reader.ReadToEnd();
    
          var ser = new JavaScriptSerializer();
    
          // you can read the json data from here
          var jsonDictionary = ser.Deserialize<Dictionary<string, string>>(json); 
    
          // i'm resetting the position back to 0, else the value of product in the action  
          // method will  be null.
          request.InputStream.Position = 0; 
        }
      }
    

    【讨论】:

      【解决方案3】:

      即使这个 'foo' 没有被绑定,它也会在你的动作过滤器中通过:

      filterContext.HttpContext.Current.Request.Params
      

      如果您看到您的参数,请查看这些集合。

      所以是的,只需创建您的操作过滤器,不要更改它将起作用的签名。

      以防万一调试您的过滤器以确定值在哪里。

      最后,您需要在 global.asax 中注册 json 值提供程序:

      protected void Application_Start() 
      {
        RegisterRoutes(RouteTable.Routes);
        ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
      }
      

      你的参数也是错误的,它需要更像:

      $.ajax({
          url: '/products/create',
          type: 'post',
          contentType: 'application/json; charset=utf-8',
          data: JSON.stringify({
              name:'widget',
              foo:'bar'
          })
      });
      

      没有引号。

      编辑(更准确地说):

      您的过滤器将包含这些方法

      public void OnActionExecuting(ActionExecutingContext filterContext)
      {
      
      }
      public void OnActionExecuted(ActionExecutedContext filterContext)
      {
      
      }
      

      【讨论】:

      • 在ActionFilter中,所有方法都有参数“filterContext”
      • public void OnActionExecuting(ActionExecutingContext filterContext) { }
      • 你说得对,对不起。检查我的编辑,这次是我犯的一个小错误。
      • 投反对票除了告诉别人答案不正确还有什么目的?
      • 如果是这种情况,那么当您的数据参数应该始终执行键/值时,您会遇到问题。您是否尝试过像这样的数据删除引号: JSON.stringify({ name:'widget ', foo:'bar' }),
      猜你喜欢
      • 2019-08-01
      • 2012-12-16
      • 2015-09-07
      • 2013-06-28
      • 2018-03-22
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 2015-04-29
      相关资源
      最近更新 更多