在GET/POST上为ViewModel填充SelectList的最佳方式
本文关键字:SelectList 最佳 方式 填充 ViewModel GET POST 上为 | 更新日期: 2023-09-27 18:10:08
我有以下ViewModel:
public class EditViewModel
{
public int FooType { get; set; }
public IEnumerable<SelectListItem> FooTypes { get; set; }
}
我最初在我的编辑操作中填充它,像这样:
public ActionResult Edit(int id)
{
EditViewModel model = new EditViewModel();
model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value");
return View(model);
}
当我创建POST值的操作时,我必须重复相同的代码:
public ActionResult Edit(int id, EditViewModel model)
{
if( !ModelState.IsValid )
{
model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value");
return View(model);
}
return RedirectToAction("Index");
}
我不喜欢把这段代码放在两个不同的位置。有什么常见的做法可以将它重构成一个点,这样我就不需要重复这段代码了吗?
考虑到c#是一种面向对象的语言,有很多可用的选项。
最简单的方法是将其封装在控制器内的方法中:
private SelectList GetFooTypesList()
{
return new SelectList(repository.GetFooTypes(), "Id", "Value);
}
并在设置模型时调用
或者如果你在多个类中使用它,你可以在另一个类中创建一个助手方法,该方法接受存储库或IEnumerable作为参数。
如果你想获得真正的高级,你可以使用一个ModelFactory来为你创建FooType模型,用一个预先填充的FooType属性,这样控制器根本不需要担心它。
有很多选择,你只需要选择一个最适合你的。
我的个人偏好是控制器中的简单helper方法
我之前在模型中做过(当它是该项目团队的编码实践时),但这取决于您对什么是"业务逻辑"和什么是"数据访问"的哲学,以及属于模型与控制器的内容。不同的、有道理的意见是存在的。
模型,其中需要为FooType提供一个可空类型:
public class EditViewModel
{
public int? FooType { get; set; }
public IEnumerable<SelectListItem> GetFooTypes(object selectedFooType = null)
{
return new SelectList(repository.GetFooTypes(), "Id", "Value", selectedFooType);
}
}
"Get"控制器,您需要首先创建模型,以确保Model
属性在视图中可用:
public ActionResult Edit(int id)
{
EditViewModel model = new EditViewModel();
return View(model);
}
The View(没有Barbara Wawa):
@Html.DropDownListFor(m => m.FooType, Model.GetFooTypes(Model.FooType))
另一种将"视图内容"从模型中取出的方法可能如下所示:
模型:
public class EditViewModel
{
public int? FooType { get; set; }
public IEnumerable<int?> FooTypes
{
get
{
// declare/define repository in your model somewhere
return repository.GetFooTypes();
}
}
}
视图:
@Html.DropDownListFor(m => m.FooType, new SelectList(Model.FooTypes, "Id", "Value", Model.FooType))
在"nekno"(回答9月30日22:19)的回复中,有两种ViewModel的选择,要么返回'IEnumerable
using Microsoft.Practices.ServiceLocation; // ServiceLocator , http://commonservicelocator.codeplex.com/
using MyOwnRepositoryNameSpace; // IRepository
public class EditViewModel
{
public int? FooType { get; set; }
public IEnumerable<int?> FooTypes
{
get
{
return Repository.GetFooTypes();
}
}
private IRepository Repository
{
get
{
return ServiceLocator.Current.GetInstance<IRepository>();
}
}
}
上面带有"依赖查找"的代码现在使用了对第三方库的依赖,在本例中是公共服务定位器库。
我的问题是如何将上面的代码替换为"依赖注入"?ViewModel本身确实很容易实现,就像这样:
using MyOwnRepositoryNameSpace; // IRepository
public class EditViewModel
{
private readonly IRepository _repository;
public EditViewModel(IRepository repository)
{
_repository = repository;
}
public int? FooType { get; set; }
public IEnumerable<int?> FooTypes
{
get
{
return _repository.GetFooTypes();
}
}
}
问题是如何使ViewModel被注入实现,当ASP。. NET MVC框架将实例化'EditViewModel',并将其作为参数发送到一个Action方法中,例如下面的方法签名:
public ActionResult Edit(int id, EditViewModel model) {
// How do we make the framework instantiate the above 'EditViewModel' with an implementation of 'IRepository' when the Action method is invoked ???
官方的MVC教程似乎没有提供任何很好的解决方案,据我所见。在下面页面的"处理编辑"部分(方法'public ActionResult Edit(…)')中,他们以类似于您现在正在阅读的这个stackoverflow问题的海报的方式复制了选项的创建。
http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-5http://mvcmusicstore.codeplex.com/SourceControl/changeset/view/d9f25c5263ed MvcMusicStore % 2 fcontrollers % 2 fstoremanagercontroller.cs
如果有一个关于如何使框架注入视图模型与您的数据检索器(如存储库)的解决方案,那么我相信它可能是使用一些实现要么'IModelBinder'或'IModelBinder',但我已经试验了这些没有真正的成功…
那么,谁能提供一个链接到一个完整的工作示例与ASP。. NET MVC 3代码,可以将数据检索器注入到框架实例化的视图模型的构造函数中,并将其作为参数发送到动作方法中?
更新2012-01-01:对于那些有兴趣的解决这个特定问题的构造函数注入一个ViewModel实例,当框架实例化它,并将其作为参数发送到MVC动作方法参数,我已经创建了一个新的问题与一个更具体的主题,因此希望更有可能的人有一个解决方案会找到它,并张贴一个很好的答案:作为Action方法参数的View Model实例的构造函数注入