MVC 6 - концепция ViewModel Builder

Я начал рефакторинг веб-приложения ASP.Net 5, которое использует MVC 6 и Entity Framework 7, когда мне стало интересно о некоторых моментах. Мои контроллеры в настоящее время используют 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);
    }
}

Я провел некоторое исследование и нашел несколько постов в блоге ( вроде этого), в которых содержится просьба содержать контроллеры в чистоте. Хорошо Почему бы и нет? Я начал создавать своего рода конструктор моделей представлений, чтобы передать логику методов контроллера конструктору моделей представлений. В приведенной выше статье есть подсказка, чтобы создать для каждой модели представления собственный класс конструктора моделей представлений, что имеет смысл в моих глазах. Для модели User существуют два вида и, следовательно, две модели (UserIndexViewModel а также UserEditViewModel). Когда я создаю связанные классы модели представления-модели, они должны быть производными от одного и того же (абстрактного) класса, потому что может быть так, что оба дочерних класса нуждаются в вспомогательном методе (например, 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);
    }
}

Таким образом, с помощью этого абстрактного класса я могу создать реализацию UserIndexViewModelBuilder а также UserEditViewModelBuilder классы, а также, например, UserDeleteViewModelBuilder а также UserCreateViewModelBuilder занятия в будущем...

Теперь вопрос:

  1. Это правильный подход, чтобы отделить логику от контроллера? Если да, нужна ли мне какая-то фабрика для всех сборщиков моделей представлений, к которой можно получить доступ через DI на всех моих контроллерах? Если это способ, который является своего рода лучшей практикой для приложений MVC. Есть ли что-то отличное от упомянутого руководства, которое можно / нужно использовать в приложениях MVC 6?
  2. Является ли абстрактный класс правильным местом для вызова DbContext реализация через DI? Это нехорошо для меня.
  3. Некоторые другие моменты, которые я пропустил? Некоторые if-операторы для проверки ответа были удалены из UserController для лучшей читаемости.

Спасибо!:-)

0 ответов

Другие вопросы по тегам