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

时间:2011-09-29 21:20:19

标签: c# asp.net-mvc asp.net-mvc-3 code-reuse

我有以下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");
}

我不喜欢在两个不同的位置使用此代码。是否有任何常见的做法可以将其重构为一个点,所以我不需要重复这段代码?

3 个答案:

答案 0 :(得分:0)

鉴于c#是一种面向对象的语言,有很多选择。

最简单的方法是将其包装在控制器内的方法中:

private SelectList GetFooTypesList()
{
    return new SelectList(repository.GetFooTypes(), "Id", "Value);
}

在设置模型时调用它

或者如果你在多个类中使用它,你可以在另一个接受存储库或IEnumerable作为参数的类中创建一个辅助方法。

如果你想获得真正的高级,你可以使用ModelFactory为你创建FooType模型,使用预先填充的FooType属性,这样控制器根本不需要担心它。

有很多选择,您只需要选择最适合您的选项。

我个人的偏好是控制器中的简单帮助方法。

答案 1 :(得分:0)

我之前已经在模型中完成了它(当时它是该项目团队的编码实践),但这取决于您对什么是“业务逻辑”以及什么是“数据访问”的理念,以及模型中的内容vs控制器。存在不同且合理的观点。

模型,您需要FooType的可空类型:

public class EditViewModel
{
    public int? FooType { get; set; }
    public IEnumerable<SelectListItem> GetFooTypes(object selectedFooType = null)
    {
        return new SelectList(repository.GetFooTypes(), "Id", "Value", selectedFooType);
    }
}

“获取”控制器,您需要首先创建模型以确保视图中的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))

答案 2 :(得分:0)

在“nekno”的回复中(9月30日22:19回答),ViewModel有两种选择,它们返回'IEnumerable&lt; SelectListItem&gt;'或'IEnumerable&lt; int?&gt;'。 这两种方法都使用了存储库但没有实际创建它,所以我想稍微扩展一下代码示例,并选择第二种方法,即类型为'IEnumerable&lt; int?&gt;'的类。 :

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>();
        }
    }   
}

上面带有“Dependecy Lookup”的代码现在使用依赖于第三方库,在本例中是Common Service Locator库。

我的问题是如何将上述代码替换为“依赖注入”? 实现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();
        }
    }
}

问题是当ASP.NET MVC框架将实例化'EditViewModel'并将其作为参数发送到Action方法(例如tihs方法签名)时,如何使ViewModel注入实现;

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教程似乎没有提供任何好的解决方案。 在下面的页面中的“处理编辑”(方法'公共ActionResult编辑(...)')部分中,他们以与您正在阅读的此stackoverflow问题的海报类似的方式复制选项的创建。< / p>

http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-5

http://mvcmusicstore.codeplex.com/SourceControl/changeset/view/d9f25c5263ed#MvcMusicStore%2fControllers%2fStoreManagerController.cs

如果有关于如何使用数据检索器(例如存储库)构建框架注入视图模型的解决方案,那么我相信可能会使用“IModelBinderProvider”或“IModelBinder”的某些实现,但我已经进行了实验这些没有真正成功......

那么,任何人都可以使用ASP.NET MVC 3代码提供一个完整工作示例的链接,该代码可以将数据检索器注入到框架实例化的视图模型的构造函数中,并将其作为参数发送到操作方法中吗?

更新2012-01-01 : 对于那些关于构造函数注入ViewModel实例的特定问题的解决方案感兴趣的人,当框架实例化它并将其作为参数发送到MVC Action Method参数时,我创建了一个具有更具体主题的新问题,因此希望更有可能有解决方案的人会找到它并发布一个好的答案: Constructor injection of a View Model instance used as an Action method parameter