MVC 6 - ViewModel Builder概念

时间:2015-12-08 19:17:57

标签: asp.net-mvc viewmodel asp.net-core asp.net-core-mvc asp.net-mvc-viewmodel

当我想知道一些问题时,我开始重构一个使用MVC 6和Entity Framework 7的ASP.Net 5 Web应用程序。我的控制器当前通过依赖注入使用DbContext实现来填充视图模型并返回它们以使用视图进行渲染。像:

public class UserController : Controller
{
    [FromServices]
    public MyContext myContext { get; set; }

    //route which renders all users
    public IActionResult Index()
    {
        var users = myContext.User.OrderBy(u => u.Name);
        List<UserIndexViewModel> v = new List<UserIndexViewModel>();
        foreach (var item in users)
        {
            v.Add(new UserIndexViewModel { Name = item.Name, City = item.City, DateOfBirth = item.DateOfBirth });
        }
        return View(v);
    }

    //route to edit user
    public async Task<ActionResult> Edit(int id)
    {
        User user = await FindUserAsync(id);
        UserEditViewModel v = new UserEditViewModel { Name = user.Name, City = user.City };

        return View(v);
    }

    [HttpPost]
    [ValidateAntiForgeryToken] 
    public async Task<ActionResult> Update(int id, UserEditViewModel userModel)
    {
        User user = await FindUserAsync(id);

        try
        {
            user.Name = userModel.Name;
            user.City = userModel.City;
            myContext.User.Attach(user);
            myContext.Entry(user).State = EntityState.Modified;
            await myContext.SaveChangesAsync();
            return RedirectToAction("Index");
        }
        catch (Exception)
        {
            ModelState.AddModelError(string.Empty, "Unable to save changes.");
        }
        return View(userModel);
    }

    private Task<User> FindUserAsync(int id)
    {
        return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
    }
}

我做了一些研究,发现了一些博客文章(like this),要求保持控制器清洁。好啊,为什么不? 我开始创建一种视图模型构建器,将逻辑从控制器方法中移出到视图模型构建器。在上面的链接文章中,提示为每个视图模型创建一个自己的视图模型构建器类 - 这在我眼中是有意义的。 对于模型User,存在两个视图,因此存在两个视图模型(UserIndexViewModelUserEditViewModel)。当我创建相关的视图模型构建器类时,它们应该从相同的(抽象)类派生,因为它可能是两个子类都需要一个辅助方法(如FindUserAsync() - 在我的例子中并非如此但是想象一下)。所以我会有如下构造:

public interface IViewModelBuilder<TController, TViewModel>
{
    TViewModel Build(TController controller, TViewModel viewModel);
    Task<TViewModel > BuildAsync(TController controller, TViewModel viewModel);
}

public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel> { ... }

public class UserIndexViewModelBuilder : SiteViewModelBuilder<UserIndexViewModel> { ... }

public class UserEditViewModelBuilder : SiteViewModelBuilder<UserEditViewModel> { ... }

一个模型的多个视图模型构建器所需的这个提到的函数应该在抽象类中实现(在我的例子中是UserViewModelBuilder),对吗?

我是这样做的:

public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel>
{
    [FromServices]
    public MyContext myContext { get; set; }

    public abstract TViewModel Build(UserController controller, TViewModel viewModel);
    public abstract Task<TViewModel> BuildAsync(UserController controller, TViewModel viewModel);

    public Task<User> FindUserAsync(int id)
    {
        return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
    }
}

因此,通过这个抽象类,我可以创建UserIndexViewModelBuilderUserEditViewModelBuilder类的实现,以及将来的UserDeleteViewModelBuilderUserCreateViewModelBuilder类...

现在的问题是:

  1. 这是将逻辑与控制器分开的正确方法吗?如果是,我是否需要一种适用于所有视图模型构建器的工厂,可以通过所有控制器中的DI访问它们?如果它是MVC应用程序的最佳实践方式。是否可以/应该在MVC 6应用程序中使用提到的guide不同的内容?
  2. 抽象类是通过DI调用DbContext实现的正确位置吗?对我来说感觉不好。
  3. 我错过了其他一些观点?检查响应的一些if语句已从剪切的UserController中删除,以提高可读性。
  4. 谢谢! : - )

0 个答案:

没有答案