在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");
}

我不喜欢把这段代码放在两个不同的位置。有什么常见的做法可以将它重构成一个点,这样我就不需要重复这段代码了吗?

在GET/POST上为ViewModel填充SelectList的最佳方式

考虑到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'或'IEnumerable<int?>'。这两种选择都使用存储库,但没有实际创建它,所以我想扩展一下代码示例,并选择第二种选择,即具有属性类型为'IEnumerable<int?>':

的类
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-5

http://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实例的构造函数注入