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