假設我有複雜的視圖模型,並且每次創建ViewModel時都需要從數據庫中獲取大量數據,例如國家/地區列表,產品/類別等。在視圖模型中使用存儲庫可以嗎?
我要解決的主要問題是,當我處理POST行爲和一些TestModel
與不正確的值,這將導致ModelState.IsValid
發佈是false
,然後我不得不返回與目前發佈的模型同樣的觀點。這迫使我再次獲取我的類別列表,因爲我在GET操作中這樣做了。這在控制器中添加了很多重複的代碼,我想刪除它。目前,我做了以下內容:
我的模型和視圖模型:
模型,實體存儲在數據庫中:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Category> SubCategories { get; set; }
}
查看模型:
public class CategoryModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TestModel
{
[Required]
[MaxLength(5)]
public string Text { get; set; }
public int SelectedCategory { get; set; }
public IEnumerable<CategoryModel> Categories { get; set; }
public SelectList CategoriesList
{
get
{
var items = Categories == null || !Categories.Any()
? Enumerable.Empty<SelectListItem>()
: Categories.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
});
return new SelectList(items, "Value", "Text");
}
}
}
我的控制器:
public class HomeController : Controller
{
private readonly Repository _repository = ObjectFactory.GetRepositoryInstance();
public ActionResult Index()
{
var model = new TestModel
{
Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(TestModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Succes");
}
model.Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
});
return View(model);
}
public ActionResult Succes()
{
return View();
}
}
我想刪除重複的關鍵字提取和映射,基本上是這樣的代碼:
.Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
從控制器。另外我想刪除ModelState
有效性檢查,我想只在ModelState.IsValid
保持控制器代碼AS CLEAN AS POSSIBLE時才執行操作。到目前爲止,我有去除ModelState
有效性檢查以下解決方案:
創建自定義ValidateModelAttribute
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var viewData = filterContext.Controller.ViewData;
if(viewData.ModelState.IsValid) return;
viewData.Model = filterContext.ActionParameters["model"];
filterContext.Result = new ViewResult
{
ViewData = viewData,
};
}
}
現在行動執行前驗證模型。如果出現驗證錯誤,我們使用與最近發佈的模型相同的視圖。因此,控制器POST操作是這樣的:
[HttpPost]
[ValidateModelAttribute]
public ActionResult Index(TestModel model)
{
// Do some important stuff with posted data
return RedirectToAction("Success");
}
這是很好的,但現在我的我的TestModel
Categories
屬性爲空,因爲我必須從數據庫中獲取的類別,並相應地映射。 因此,它是確定修改我的視圖模型看起來像這樣:
public class TestModel
{
private readonly Repository _repository = ObjectFactory.GetRepositoryInstance();
...
public int SelectedCategory { get; set; }
public IEnumerable<CategoryModel> Categories {
get
{
return _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
});
}
}
...
}
這將使我們有很乾淨的控制器,但不會是引起某種性能或建築問題?它不會打破視圖模型的單一責任原則嗎? ViewModels應該負責提取它需要的數據嗎?
理想情況下,您的視圖模型不會直接與您的存儲庫進行交互。如果您需要從存儲庫中填充模型,則會發生在您的控制器中。如果您不想在單獨的控制器路由中複製類別種羣,則可以嘗試將此邏輯重構爲單獨的方法。 – timothyclifford