2016-10-18 154 views
0

我正在做一個簡單的搜索頁面在MVC與其中的一些過濾器。過濾器由ViewModel中的屬性表示。我的ViewModel綁定到cshtml中的GET表單,所以我的過濾器將出現在querystrings中,用戶將能夠爲他的搜索添加書籤。默認值爲ViewModel

我想要做的是給我的一些過濾器分配一個默認值。

我(簡化)視圖模型:

public class SearchViewModel 
{ 
    //Filter I want to set a default value to 
    public OrganizationType? OrganizationType {get; set;} 

    //Results of the search 
    public IEnumerable<ItemViewModel> Items {get; set;} 
} 

我想爲OrganizationType設置的默認值。我不能簡單地將其設置在構造SearchViewModel,因爲它依賴於當前用戶:

public void InitViewModel(SearchViewModel vm) 
{ 
    vm.OrganizationType = _someLogic.GetDefaultValue(_currentUser); 
} 

首先解決方式是檢查是否OrganizationType爲空,則指定一個默認值:

public ActionResult Search(SearchViewModel vm) 
{ 
    if(vm.OrganizationType == null) 
     vm.OrganizationType = _someLogic.GetDefaultValue(_currentUser); 

    return View(vm); 
} 

但是,此解決方案不起作用null值對應於空過濾器,它是用戶可以選擇的選項。所以我不能重寫它。

我試圖爲指定控制器的默認值應該是在搜索行動無效的第二個解決方案:

public ActionResult Search(SearchViewModel vm = null) 
{ 
    if (vm == null) 
    { 
     vm = new SearchViewModel(); 
     InitViewModel(vm); 
    }  
    ... 

    return View(vm); 
} 

但在實踐中,變量VM永遠不能爲null,所以默認值從未設置。

我也試過有wihout一個ViewModel兩項行動,一個在那裏我實例化一個新的視圖模型爲默認值,然後調用第二個動作:

public ActionResult Search() 
{ 
    var vm = new SearchViewModel(); 
    InitViewModel(vm); 

    //Simply call the second action with the initizalied ViewModel   
    return Search(vm); 
} 

public ActionResult Search(SearchViewModel vm) 
{  
    ... 
    return View(vm); 
} 

但它不工作,因爲現在是一個有這兩個動作之間的歧義,而asp.net不知道選哪一個。

總之,我想找到一種方法來爲ViewModel設置默認值,而不必在構造函數中設置它並覆蓋用戶選擇。

另一種說法,我怎麼區分一個「空的」ViewModel與某些值綁定在窗體上的ViewModel。

有什麼想法?

+0

爲什麼你不能使用'_currentUser'? – markpsmith

+0

@markpsmith,_currentUser是我的控制器的成員變量,取決於當前的HttpContext。我可以在我的控制器中使用它,但是我無法在ViewModel構造函數中使用它,因爲我沒有乾淨的方式從那裏訪問HttpContext。 – cpaulus

+0

假設你正在使用MVC5和C#5,你可以試試這個嗎? public OrganizationType? OrganizationType {get; set;} = null; //或者你想設置的任何值作爲默認設置 –

回答

0

好吧,我想我找到了解決我自己的問題......

我可以使用CONTROLER的的ModelState屬性來檢查它的視圖模型是還是從形式綁定:

public ActionResult Search(SearchViewModel vm = null) 
{ 

    if (ModelState.Count == 0) 
    {   
     InitViewModel(vm); 
    }  
    ... 
    return View(vm); 
} 

所以,如果ModelState.Count等於0,則意味着用戶沒有改變任何過濾器。所以表單是空的,我們可以綁定我們的默認值。一旦用戶將更改其中一個過濾器或提交請求,即ModelState 。計數將大於0,所以我們不應該設置默認值。否則,我們將覆蓋用戶選擇。

0

你在做什麼的邏輯是有點兒的。一般來說,如果一個值可以爲空,那麼null是默認值。但是,您似乎試圖在此之間區分值是否爲null,因爲它沒有設置,或者因爲用戶明確將其設置爲null,所以它沒有設置爲null。這種類型的語義差異通常是一個壞主意。如果null有含義,那麼它應該總是帶有這個含義。否則,您的代碼會變得更加混亂,因此通常會引入錯誤。

這就是說,你不能指望ModelState沒有物品。我真的從來沒有在ModelState的情況下充分利用沒有發佈數據的情況,但可能有一些情況下沒有發佈數據,但ModelState可能有項目。即使沒有,這也是一個實現細節。如果微軟做了一項更新,在以前沒有的情況下將項目添加到ModelState。然後,你的代碼爲什麼沒有明顯的原因。

您唯一能真正指望的是請求方法是GET還是POST。在您的操作的GET版本中,您可以合理地假定用戶未做任何修改。因此,在這種情況下,您可以簡單地將值設置爲您喜歡的任何值,而無需擔心。

在您的操作的POST版本中,用戶進行了某種修改。然而,在這一點上,沒有辦法再區分這個值是否爲null,因爲它是或者因爲用戶明確地希望它是。因此,您必須尊重原來的價值。

+0

我同意區分用戶設置的「默認空值」和空值並不是最好的想法。但我想保持我的ViewModel初始化是一個簡單的可能。爲某些用戶設置默認值是一種特殊情況,而不是一般性。 我只關心GET請求,請求來自HTML表單,所以用戶可能已經做了修改。 – cpaulus