假设我有复杂的视图模型,有很多数据,如国家/地区,产品,类别等的列表,我每次创建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应该负责获取所需的数据吗?