如何让ModelBinder为参数返回null?

All*_*ice 4 c# asp.net-mvc model-binding modelbinders

我有一个POCO,我用它作为MVC3中一个动作的参数.像这样的东西:

我的风格

public class SearchData
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的行动

public ActionResult Index(SearchData query)
{
    // I'd like to be able to do this
    if (query == null)
    {
        // do something
    }
}
Run Code Online (Sandbox Code Playgroud)

目前,query作为SearchData所有属性的实例传递null.我更喜欢我得到一个null,query所以我可以在上面的代码中进行空检查.

我总是可以查看ModelBinder.Any()或只是ModelBinder查看各种键,看看它是否有任何属性query,但我不想使用反射来循环遍历属性query.此外,我只能使用ModelBinder.Any()检查查询是否是我唯一的参数.只要我添加其他参数,该功能就会中断.

使用MVC3中的当前模型绑定功能,是否可以获得将POCO参数返回null的行为?

bha*_*lin 6

您需要实现自定义模型绑定器才能执行此操作.你可以扩展DefaultModelBinder.

public override object BindModel(
    ControllerContext controllerContext, 
    ModelBindingContext bindingContext)
{
    object model = base.BindModel(controllerContext, bindingCOntext);
    if (/* test for empty properties, or some other state */)
    {
        return null;
    }

    return model;
}
Run Code Online (Sandbox Code Playgroud)

具体实施

这是绑定器的实际实现,如果所有属性都为null,则将为模型返回null.

/// <summary>
/// Model binder that will return null if all of the properties on a bound model come back as null
/// It inherits from DefaultModelBinder because it uses the default model binding functionality.
/// This implementation also needs to specifically have IModelBinder on it too, otherwise it wont get picked up as a Binder
/// </summary>
public class SearchDataModelBinder : DefaultModelBinder, IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // use the default model binding functionality to build a model, we'll look at each property below
        object model = base.BindModel(controllerContext, bindingContext);

        // loop through every property for the model in the metadata
        foreach (ModelMetadata property in bindingContext.PropertyMetadata.Values)
        {
            // get the value of this property on the model
            var value = bindingContext.ModelType.GetProperty(property.PropertyName).GetValue(model, null);

            // if any property is not null, then we will want the model that the default model binder created
            if (value != null)
                return model;
        }

        // if we're here then there were either no properties or the properties were all null
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

在global.asax中将其添加为绑定器

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    ModelBinders.Binders.Add(typeof(SearchData), new SearchDataModelBinder());
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    MvcHandler.DisableMvcResponseHeader = true;
}
Run Code Online (Sandbox Code Playgroud)