簡體   English   中英

如何讓ModelBinder為參數返回null?

[英]How do I make the ModelBinder return null for a parameter?

我有一個POCO,我用它作為MVC3中一個動作的參數。 像這樣的東西:

我的風格

public class SearchData
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string Property3 { get; set; }
}

我的行動

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

目前, query作為SearchData的實例傳遞,所有屬性都為null 我更喜歡我的querynull ,所以我可以在上面的代碼中進行null檢查。

我總是看ModelBinder.Any()或只是在各個鍵ModelBinder ,看它是否有任何的屬性query ,但我不希望有過的屬性,使用反射來循環query 另外,我只能使用ModelBinder.Any()檢查查詢是否是我唯一的參數。 只要我添加其他參數,該功能就會中斷。

使用MVC3中的當前模型綁定功能,是否可以獲得將POCO參數返回null的行為?

您需要實現自定義模型綁定器才能執行此操作。 您可以只擴展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;
}

具體實施

這是綁定器的實際實現,如果所有屬性都為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;
    }
}

在global.asax中將其添加為綁定器

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

    MvcHandler.DisableMvcResponseHeader = true;
}

在路線嘗試

new { controller = "Articles", action = "Index", query = UrlParameter.Optional }

將自定義模型綁定器實現為參數的屬性。

注意:模型上的所有屬性都必須可以為空

  1. 這是上面的ModelBinderClass

     public class NullModelBinder : DefaultModelBinder { public override 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; } } 
  2. 創建屬性

     public class NullModelAttribute : CustomModelBinderAttribute { public override IModelBinder GetBinder() { return new NullModelBinder(); } } 
  3. 在控制器方法上使用Attribute

     public ActionResult Index([NullModel] SearchData query) { // I'd like to be able to do this if (query == null) { // do something } } 

我不知道你的具體問題的答案,但我可以想到一個解決方法。 為什么不直接向SearchData類添加方法?

public bool IsEmpty(){
  return Property1 == null 
      && Property2 == null 
      && Property3 == null;
}

當然,如果您嘗試使用多種類型,則可能會變得乏味。

實現自定義模型綁定器,但使用接口來確定對象是否為空。 我更喜歡這種模式有兩個原因:

  1. 對每個綁定使用反射可能非常昂貴
  2. 它封裝了如何確定對象是否為該對象的null的邏輯。

     public class NullValueModelBinder : DefaultModelBinder, IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { object model = base.BindModel(controllerContext, bindingContext); if (model is INullValueModelBindable && (model as INullValueModelBindable).IsNull()){ return null; } return model; } } public interface INullValueModelBindable { bool IsNull(); } 

我發現DefaultModelBinderSetProperty只有在找到屬性並嘗試設置它時才會被調用。

考慮到這一點,這是我的NullModelBinder。

public class NullModelBinder : DefaultModelBinder
{
    public bool PropertyWasSet { get; set; }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        object model = base.BindModel(controllerContext, bindingContext);
        if (!PropertyWasSet)
        {
            return null;
        }

        return model;
    }

    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
    {
        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
        PropertyWasSet = true;
    }
}

因此,只有框架在請求中找到屬性並嘗試將其設置為模型時, BindModel返回由BindModel創建的模型。

注意:

我的方法與之前答案的NullBinders不同,因為它只在每個屬性中進行一次,而在最壞的情況下,其他NullBinders進行兩次。

在這段代碼中snnipet:

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    object model = base.BindModel(controllerContext, bindingContext);

    // loop through every property for the model in the metadata
    //CODE HERE
}

base.BindModel被調用時,.Net會遍歷模型上的每個屬性,試圖找到它們並在模型創建時設置它們。

然后CustomModelBinder再次遍歷每個屬性,直到它在請求中找到一個屬性,在這種情況下返回由.Net創建的模型,否則返回null。

因此,如果沒有設置屬性,我們將有效地遍歷模型的每個屬性兩次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM