Search code examples
c#asp.net-mvcscaffolding

MVC best practice for seperation of concerns


I am using MVC5 to make a website.

I am using scaffolding to generate my controllers from my model-class. Whenever it creates a scaffold of a controller, the db-connection and model-manipulation happens within the controller class (look below). By looking at this thread I can tell that most people agree that this should instead be happening in the model class.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Username")] User user)
{
    if (ModelState.IsValid)
    {
        db.Entry(user).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
  return View(user);
}

Instead of having a controller do this, should i instead have it look like this?:

User-Controller

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Username")] User user)
{
    if (ModelState.IsValid)
    {
        UserModel userModel = new userModel();
        userModel.editUser(user);
        return RedirectToAction("Index");
    }
  return View(user);
}

User-Model

public void editUser(User user){
    db.Entry(user).State = EntityState.Modified;
    db.SaveChanges();
}

To specifiy what "db" is, it would be a reference to my db context.


Solution

  • I think you misunderstood what is meant with "Model" in the answers you referenced (In a MVC application, should the controller or the model handle data access?).

    The answer of tereško states:

    The business logic in MVC and MVC-inspired patterns has to be in the model layer. And yes, model is supposed to be a layer, not a class or object.

    So do not put database access into your ViewModel. Instead, you want a service class in your business layer that does the DB access and maps the database entities to Data Transfer Objects or ViewModels. Note how I use Command and Query classes to decouple the access to the business layer from any frontend classes like ViewModels (use AutoMapper to translate between DTO <-> ViewModel <-> Command/Query).

    public interface IUserService {
    
        public UserDto CreateUser(CreateUserCommand command);
    
        public UserDto EditUser(EditUserCommand command);
    
        public void DeleteUser(DeleteUserCommand command);
    
        public UserDto[] FindUsers(FindUsersQuery query);
    }
    

    Controller uses this Business Layer:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(UserViewModel postData) {
         if (!ModelState.IsValid) {
             return View("Edit", postData);
         }
    
         var command = Mapper.Map<EditUserCommand>(postData);
         var updatedUserDto = _userService.EditUser(command);
    
         var updatedUserViewModel = Mapper.Map<UserViewModel>(updatedUserDto);
         return View("Show", updatedUserViewModel);
    }