在ASP.NET CORE中将属性路由值转换为Model / FromBody参数

时间:2019-07-01 13:04:57

标签: c# .net-core asp.net-core-webapi modelbinders custom-model-binder

我正在开发.NET核心Web API应用程序,在该应用程序中,我希望URL路由值进入Model / FromBody参数。如果发件人模型中存在路由属性。

是否有任何通用解决方案,即适用于所有模型类型。

我们已经找到了自定义模型绑定器,但是它适用于特定于模型类型的绑定器。我正在寻找适用于所有模型类型的自定义模型活页夹。

例如:

Action route: [Route("AH/{userId}")]
Url : ../AH/123
From body: 
{
"userId":"",
"Value" : "Some value"
}

现在,路由值123需要映射到FromBody模型属性“ userId”

2 个答案:

答案 0 :(得分:0)

您无法从请求正文中填充路线参数。路由参数是URL的一部分,因此必须独立于实际发布的正文而存在。

无论如何,您永远都不应信任来自发帖请求正文的ID之类的东西。始终从URL获取该信息。该URL定义了唯一资源,因此发布到该URL只能影响该唯一资源。如果您依赖发布主体,则恶意用户可以操纵发布的值来潜在地更改他们不应该访问的资源。

答案 1 :(得分:0)

对于您当前的请求,"userId":""将使请求失败,因为无法将""转换为int值。

要解决此问题,可以通过以下步骤在模型绑定之前修改请求正文:

  1. ModelResourceFilterAttribute

    public class ModelResourceFilterAttribute : Attribute, IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.HttpContext.Request.EnableRewind();
            var routeData = context.RouteData;
            var stream = context.HttpContext.Request.Body;
            using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
            {
                var json = streamReader.ReadToEnd();
                if (json != "")
                {
                    var jsonObj = JObject.Parse(json);
                    foreach (var item in routeData.Values)
                    {
                        JToken token;
                        if (jsonObj.TryGetValue(
                            item.Key,
                            StringComparison.InvariantCultureIgnoreCase,
                            out token))
                        {
                            var jProperty = token.Parent as JProperty;
                            if (jProperty != null)
                            {
                                jProperty.Value = item.Value.ToString();
                            }
                        }
                    }
                    var body = jsonObj.ToString(Formatting.Indented);
                    byte[] byteArray = Encoding.UTF8.GetBytes(body);
                    //byte[] byteArray = Encoding.ASCII.GetBytes(contents);
                    context.HttpContext.Request.Body = new MemoryStream(byteArray);
                }
    
            }            
        }
    }
    
  2. 注册ModelResourceFilterAttribute

    services.AddMvc(options =>
    {
        options.Filters.Add(typeof(ModelResourceFilterAttribute));
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);