【问题标题】:How do I get MVC Model Binder to only bind non Null values for a list?如何让 MVC 模型绑定器仅绑定列表的非 Null 值?
【发布时间】:2011-12-08 11:16:11
【问题描述】:

question 之后,我想知道是否有办法让 MVC 模型绑定器仅将元素绑定到列表(如果有填充它们的值)。例如,如果有一个包含三个同名输入且未输入一个值的表单,我该如何停止 MVC 绑定一个包含 3 个元素的列表,其中一个为空?

【问题讨论】:

    标签: asp.net-mvc-3 model-binding defaultmodelbinder custom-model-binder


    【解决方案1】:

    自定义模型绑定器

    您可以实现自己的模型绑定器以防止将空值添加到列表中:

    查看:

    @model MvcApplication10.Models.IndexModel
    
    <h2>Index</h2>
    
    @using (Html.BeginForm())
    {
        <ul>
            <li>Name: @Html.EditorFor(m => m.Name[0])</li>
            <li>Name: @Html.EditorFor(m => m.Name[1])</li>
            <li>Name: @Html.EditorFor(m => m.Name[2])</li>
        </ul>
    
        <input type="submit" value="submit" />
    }
    

    控制器:

    public class HomeController : Controller
    {
        public ViewResult Index()
        {
            return View();
        }
    
        [HttpPost]
        public ActionResult Index(IndexModel myIndex)
        {
            if (ModelState.IsValid)
            {
                return RedirectToAction("NextPage");
            }
            else
            {
                return View();
            }
        }
    }
    

    型号:

    public class IndexModel
    {
        public List<string> Name { get; set; }
    }
    

    自定义模型绑定器:

    public class IndexModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
            string searchPrefix = (hasPrefix) ? bindingContext.ModelName + "." : "";
    
            List<string> valueList = new List<string>();
    
            int index = 0;
            string value;
    
            do
            {
                value = GetValue(bindingContext, searchPrefix, "Name[" + index + "]");
    
                if (!string.IsNullOrEmpty(value))
                {
                    valueList.Add(value);
                }
    
                index++;
    
            } while (value != null); //a null value indicates that the Name[index] field does not exist where as a "" value indicates that no value was provided.
    
            if (valueList.Count > 0)
            {
                //obtain the model object. Note: If UpdateModel() method was called the model will have been passed via the binding context, otherwise create our own.
                IndexModel model = (IndexModel)bindingContext.Model ?? new IndexModel();
                model.Name = valueList;
                return model;
            }
    
            //No model to return as no values were provided.
            return null;
        }
    
        private string GetValue(ModelBindingContext context, string prefix, string key)
        {
            ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key);
            return vpr == null ? null : vpr.AttemptedValue;
        }
    }
    

    您需要在Application_Start() (global.asax) 中注册模型绑定器:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
    
            //this will use your custom model binder any time you add the IndexModel to an action or use the UpdateModel() method.
            ModelBinders.Binders.Add(typeof(IndexModel), new IndexModelBinder());
    
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    

    自定义验证属性

    或者,您可以使用自定义属性验证是否填充了所有值:

    查看:

    @model MvcApplication3.Models.IndexModel
    
    <h2>Index</h2>
    
    @using (Html.BeginForm())
    {
        @Html.ValidationMessageFor(m => m.Name)
        <ul>
            <li>Name: @Html.EditorFor(m => m.Name[0])</li>
            <li>Name: @Html.EditorFor(m => m.Name[1])</li>
            <li>Name: @Html.EditorFor(m => m.Name[2])</li>
        </ul>
    
        <input type="submit" value="submit" />
    }
    

    控制器:

    使用上面定义的相同控制器。

    型号:

    public class IndexModel
    {
        [AllRequired(ErrorMessage="Please enter all required names")]
        public List<string> Name { get; set; }
    }
    

    自定义属性:

    public class AllRequiredAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            bool nullFound = false;
    
            if (value != null && value is List<string>)
            {
                List<string> list = (List<string>)value;
    
                int index = 0;
    
                while (index < list.Count && !nullFound)
                {
                    if (string.IsNullOrEmpty(list[index]))
                    {
                        nullFound = true;
                    }
                    index++;
                }
            }
    
            return !nullFound;
        }
    }
    

    【讨论】:

    • 感谢我已经做了所有这些。目的是通过停止模型绑定器绑定列表中的空值来防止空值到达控制器。
    • @GraemeMiller 道歉,在看到链接的答案是一个自定义属性来检查最小数量的值后,我认为你真正想要的是一个自定义属性来检查你没有提供任何空值.我已更新我的答案以提供自定义模型绑定器,并留下我之前的答案以供参考。
    • 非常适合字符串列表。我只需要弄清楚您的代码将其转换为 HttpPostedFileBase 列表
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多