Home » ASP » ASP.MVC » Enterprise Asp.Net MVC Part 3: Controller

Enterprise Asp.Net MVC Part 3: Controller

In this third part, we will discuss about controller. We aren’t done yet with the model (still require to add more validation) but let’s talk about the controller. In Asp.Net MVC, the controller act has the gate for the Http Request and answer back to any request with a Http Response. That’s it. It’s role should be limited to this task to respect the Single Responsability Principle.

But, we need to do a lot of thing when a client send information to the server. We need to convert the data in input to object, we need to convert this information to the model domain, we need to get into the database to load information and maybe to save information, we need to manipulate the data and we need to send back an answer. How can the controller be clean and in the same time be able to do all those things? Well, we will need to use the principle of seperation of concern and to split every task into multiple classes.

We will start with the model binding, which is the first step of any request.

Auto-mapping

In Asp.Net Mvc, the transformation of HTTP Get parameter or HTTP Post parameters into C# code is called Model Binding. The Model binding by default try to convert any data to primitive type or try to instantiate your model object if the request contain a Json object that fit the schema of your classes. That mean that you can simply use Asp.Net MVC to send back all properties values of your model back to the server and Asp.Net MVC is bright enough to build a new object for you.

[HttpPost]
public ActionResult Create(WorkoutModel model)
{
	//1)Validate model
	//2)Do manipulation
	//3)Save into the database

	return View("Create);//4)Return a response to the client
}

The problem with this approach is, it works fine if you use Model object to send information to the view but we are using ViewModel (this was an architecture decision we took in the first part of this series). ViewModel give us the leverage to add additional information like a list of exercises that could be used in the workout, etc. So, before the task 1 of validating the model, we need to convert back the view model into model object. This is where automapper come to the rescue.

An automapper is a library that map property from an object to an other one. In our example, we will use AutoMapper. It’s a free, open source, and widely used automapper. It can be configurable or by default map property name automatically. I won’t show you how to use automapper in this article but you can find good example in this blog or anywhere on the web.

So, once we have receive the view model back to from the view to the controller, we need to automap the view model to the model. That mean that every time we use a controller action that we need to do this task. This can be repetitive and error prone. That’s why a better approach is to implement a “Model” object. A little bit like Microsoft did with Asp.Net MVC with the View. We will create a Model property that will hold the converted view model. To do so, we will need to modify the BaseController.

Automapper and BaseController

We will modify the BaseController and override the method OnActionExecuting. This will give us the opportunity to modify the code before entering the code of the action defined inside the controller.

This is an overview of what we are going to do. First, we will have a concrete controller for every entity. In our case, the WorkoutController. Each controller inherit of the BaseController which is generic with 2 types. The first one is the model type, and the second is the view model type. The BaseController contain a reference to a IMapperFactory, which is a layer of abstraction to the AutoMapper implementation. We will come back later with the IMapperFactory. Finally, the BaseController contain a property of TModel type. That mean that for the WorkoutController that we will be able to use “this.Model” to get the model from the view model. For another entity, the Model will be of the entity type because it will use the TModel type defined by the BaseController. Here is the code that reflect the illustration above.

public class WorkoutController : BaseController<Workout, WorkoutViewModel>
{

	public WorkoutController(IMapperFactory mapperFactory):base(mapperFactory)
	{
	}


	public ActionResult Index()
	{
	}

	[HttpGet]
	public ActionResult Details(int id)
	{
	}

	[HttpGet]
	public ActionResult Create()
	{

	}

	[HttpPost]
	public ActionResult Create(WorkoutViewModel viewModel)
	{
	}

	[HttpGet]
	public ActionResult Edit(int id)
	{
	}

	[HttpPost]
	public ActionResult Edit(WorkoutViewModel viewModel)
	{
	}
}

public abstract class BaseController<TModel, TViewModel>:Controller
{
	private readonly IMapperFactory _mapperFactory;
	
	protected TModel Model { get; private set; }

	protected BaseController(IMapperFactory mapperFactory)
	{
		_mapperFactory = mapperFactory;
	}

	protected override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		base.OnActionExecuting(filterContext);
		if(filterContext.ActionParameters.Any())
		{
			var possibleViewModel = filterContext.ActionParameters.FirstOrDefault(x => x.Value.GetType() == typeof(TViewModel));
			if (possibleViewModel.Value!=null)
			{
				var viewModel = (TViewModel) possibleViewModel.Value;
				var model = (TModel) Activator.CreateInstance(typeof (TModel));
				Model = _mapperFactory.Map(viewModel, model);
			}
		}
	}
}

Anytime, inside the Update or Create, instead of using the viewModel parameter which is of WorkoutViewModel type, you can use the base.Model. This way to code give us few advantages. First, the controller is clean. No mapping is done on any concrete controller. Second, we still have access to the view model if required. Third, we do not repeat work on all controllers.

Service layer

Now that we have the data from the view, we need to do some manipulation. We will skip the validation process because it will be in another part of this series. Let’s jump to the service layers. The service layer is a layer between the service layer is above the controller and could be used not only by the web controller but by the web api controller or any other application. It’s the layer between the user interaction and the repository. It’s the one that can contact the repository, the cache, or manipulate many entity to return a unique one. The service layer will be used by the controller to access the repository and to build the view model. For example, it will load a specific workout if the user call the Edit action of the Workout controller. Not only it will load the workout, but it will give us the view model filled correctly with the extra properties that could contain additional choices to be selected (like a list of exercise) and additional localized text for example.

So, we need to modify the WorkoutController to have a service reference.

public class WorkoutController : BaseController<Workout, WorkoutViewModel>
{
	public WorkoutController(IMapperFactory mapperFactory):base(mapperFactory)
	{
	}
//...

will become:

public class WorkoutController : BaseController<Workout, WorkoutViewModel>
{
	private readonly IWorkoutService _service;
	public WorkoutController(IWorkoutService service, IMapperFactory mapperFactory):base(mapperFactory)
	{
		_service = service;
	}
//...

As you can see, the IWorkoutService has been added. This will give us the possibility to inject the service into the controller. Every controller will have its own service.

Because most of the service will look the same we can create a base service class, that I’ll call IService. The IService will contain the primitive call that are concerning getting the model, saving the model and deleting the model.

public interface IService<TModel, TViewModel>
{
	IEnumerable<TViewModel> GetAll();
	TViewModel Get(TModel model);
	int Create(TModel model);
	int Update(TModel model);
	int Delete(TModel model);
}

public interface IWorkoutService : IService<Workout, WorkoutViewModel>
{
}

We could add in IWorkoutService more specific method. For example, one could require to have a specicial Get that will return a extended view model with more data. Or, someone might want to have to model from the Get instead of the view model. This type of architecture let a flexibility.

If we check the concrete implementation of IWorkoutService we will see all repository access and the automapper to convert the model to view model.

public class WorkoutService : BaseService, IWorkoutService
{
	public WorkoutService(IRepositoryFactory repositoryFactory, IMapperFactory mapperFactory) : base(repositoryFactory, mapperFactory)
	{
	}

	#region Implementation of IService<Workout>

	public IEnumerable<WorkoutViewModel> GetAll()
	{
		var listModel = Repository.Workout.GetAll().ToList();
		return Mapper.Map<List<Workout>,List<WorkoutViewModel>>(listModel);
	}

	public WorkoutViewModel Get(Workout model)
	{
		var modelToBound = Repository.Workout.Get(model.Id);
		return Mapper.Map<Workout, WorkoutViewModel>(modelToBound);
	}

	public int Create(Workout model)
	{
		return Repository.Workout.Insert(model);
	}

	public int Update(Workout model)
	{
		return Repository.Workout.Update(model);
	}

	public int Delete(Workout model)
	{
		return Repository.Workout.Delete(model);
	}

	#endregion
}

As you can see, we are using the IMapperFactory to map data and not directly the automaper. This abstraction give us the possibility to mock the mapping easily later. Also, you can see that we are doing the same with the repository. We are using IRepositoryFactory which is not tightly bound to any repository, neither bound to the workout. That mean that workout could load exercises without problem. The detail about the repository will be defined in another article.

Conclusion

We have seen that we can have clean controller and the use of service help us to separate the request from the repository. We also have seen that it’s better to use interface instead of concrete classes because it gives us the possibility to mock later on, give us a layer of abstraction between concrete implementation of the controller and from the repository, mapper and so on. In the next article of this series we will discuss about the repository and Entity Framework in an enterprise Asp.Net MVC web application. We will come back with controller in the article concerning validation of the model. Indeed, the controller will have its role with validation and we will see how to implement a solution that will still respect the single responsibility principle.

Series Articles

Article #1: Asp.Net MVC Enterprise Quality Web Application
Article #2: Asp.Net MVC Enterprise Quality Web Application Model
Article #3: Asp.Net MVC Enterprise Quality Web Application Controller
Article #4: Asp.Net MVC Enterprise Quality Web Repository Layer
Article #5: Asp.Net MVC Enterprise Quality Web with Entity Framework
Article #6: Asp.Net MVC Enterprise Quality Layers
Article #7: Asp.Net MVC Enterprise Quality Web Security

If you like my article, think to buy my annual book, professionally edited by a proofreader. directly from me or on Amazon. I also wrote a TypeScript book called Holistic TypeScript

14 Responses so far.

  1. marco says:

    Cher Patrick,

    Votre blog est très intéressant, et votre découpe de votre programme, est pour l’instant une des meilleur que j’ai vue

    J’ai deux questions : votre service layer va servir de interface pour les clients (site web) et la couche métiers(business).

    Ma question est la suivante, si par exemple, un client de type web service (WCF) veut utiliser la couche Service, il va devoir implémenter la couche viewModel ?

    Pourquoi ne pas utiliser directement la couche Model et implémenter les infos supplémentaire (“extra properties” list of exercices ) ?

    2/Quand vous regrouper les “repositories” pour partager le dbcontex, cela serait équivalent au Pattern “Unit of Work” ?

    Merci, et bonne continuation.
    MArco

    • Pour la deuxième question, c’est un peu comme le Unit of Work qui permet de commiter l’ensemble des modifications sur plusieurs repositories. La différence est que les changements sont garder dans le DbContext donc pas besoin de réinventer la roue en gardant les changements nous même. Donc, nous avons deux avantages : possibilité de faire des changements sur plusieurs repositories et d’avoir un commit pour l’ensemble, ainsi que d’avoir la gestion des changements directement dans Entity Framework et donc pas de gestion ou répétition de code à faire vue que Entity Framework DbContext gère le tout.

      Pour la première question, votre interrogation est pertinente. Il serait très intelligent d’utiliser dans votre service WCF la couche de service. Cependant, que cette couche retourne le Modèle ou le ViewModel, dans les deux cas, la majorité des entreprises vont envoyés un DTO (un objet bête sans logique avec des types primitifs). Dans la situation actuel, ce “DTO” pourrait être le ViewModel qui est une représentation bête du modèle 🙂 C’est vraiment selon les politiques de l’entreprises rendus là.

  2. Martin says:

    Hi, great series of posts. I read all of your parts and I’m still asking me a question…(not about this part itself, but with the general solution) If your viewmodel has to have something that is not persisted by the viewmodel, like a selectlist for example, where do you populate it and re-populate it if errors occured ?
    My first idea will be to populate it in the service layer, because it is responsable to create the viewmodel from the multiple repository if neceseary. This is ok when you call the “Get” service function but what about the Create, Update or Delete function, since they are not returning the viewModel, but throwing errors when they are not valid.

    Thanks

    N.B. I don’t understand why your blog are not in top list in google for mvc subjects!

    Je suis également de Québec, j’ai écrit ma questions en anglais, histoire d’en faire profiter un plus grand nombre. Si ma question n’est pas clair, gène toi surtout pas.

    • Hi Martin,

      If an error occur, I usually handle it inside the controller/service. The reason is that the error could have occurred inside the repository, the service or the controller itself. In all case, you would want to load your properties that require to have data from the database. The controller will know that an error occurs and will be able to delegate (to the service layer) the task to get the stuff from list to the view model correctly. I say that it’s inside the controller AND the service because the controller will get the object loaded back form the service with the appropriate list.

      You example of selectlist if excellent. If you have an error, the model state will have values of your form and will store them back into inputs but not for selectlist. This let you get (from the service) with the “Get New” a new ViewModel that you can send back with View(“xyz”, yourViewModelFromService) but since the ModelState will have the inputs value will still show the values from the user and in the same time having the remaining property (like the list).

      This of course work only if you have (and you should have) inside the service a method “GetNew” that return a new ViewModel with everything loaded.

      I will write a better explication soon on this blog concerning how to handle MVC error with complexe ViewModel that contains list. You will see more clearly what I try to explain 🙂

      Thank you for the kind words 🙂 et ton anglais est parfait.

      • Martin says:

        Ok thanks, this is work… You’re right, error can occurs in the controller layer (i.e. at ModelBinding, DataAnnotations or anything else)… I realized this just after my post. Just to add to your reply, let modify my example. Instead of having selectlist with a “CreateNew” Action, we’ll have “Display“ members (non-editable members) in the ViewModel for a Get Action (with a specific Id as parameter). In that case, we’ll need to Get the ViewModel again (in the HttpPost Action) by calling the Get service function as we did in the HttpGet same action function, right ? Then the ModelState will fill the form with the original post values for input members. What I don’t like with that, if that we have a desynchronized model… We pass a model to our view, and the form will not have the same values as our model. This case is out of scope because we have the same problem if we want to modify a ViewModel property in a HttpPost action. The ModelState will always overwrite the viewmodel and it’s a normal behavior… but I still found weird that we profit of this behavior by overwritting all editables properties with the original get values and pass them to the view because we know that these properties will be overwritten by the ModelState. All of this only to get the display members, lists or anything else not persisted in the viewmodel. There something magic that I don’t like, but it works great and I don’t have a better idea 😉

        Thanks again.

  3. Hi Patrick, thank you for this great series on EnterPrise architecture with ASP.NET MVC4 and EF5.
    I have tried to reproduce the solution you have given us to produce a clean controller. However it seems that the concrete controller are tied up to a single viewmodel. I have understood that we should use a narrow viewmodel that fits to the view and that means we should have many viewmodels. But when the viewmodel are bound to the controller, how can we use the same controller for different actionmethods with different viewmodels?
    One solution would be to create a controoler pr. viewmodel, but that does not seems elegant and might be confusing.

    • Hi Jesper,

      This is normal that you are tight to a single view model because Asp.Net MVC tight you to a single model per view by default. With the View Model, your view is not tight to a single view model and therefore, your controller is tight to a single view model. I have been in several complex case since few years and I never needed to have a controller to be handle many view model. In fact, you can have a controller that interact with several model classes but in the end, when this one want to push information to the view can always return a single view model to the view. Nothing force you to have a view model that is similar to your model. In a complex case, you can have your view model having several model property to expose.

      Controller should always be for a single view so you it should be the same controller for different view model. In fact, the cross-logic that you have should be in business logic classes or/and in service layers. Controller should only be there to act as a “proxy” between your view and your model, not the be the main actor of anything else.

  4. […] Enterprise Quality Web Application Article #2: Asp.Net MVC Enterprise Quality Web Application Model Article #3: Asp.Net MVC Enterprise Quality Web Application Controller Article #4: Asp.Net MVC Enterprise Quality Web Repository Layer Article #5: Asp.Net MVC Enterprise […]

  5. pawg says:

    I wanted to thank you for this wonderful read!!
    I absolutely loved every bit of it. I’ve got you bookmarked to check out new stuff you post…

  6. […] Asp.Net MVC, you will need to override the default method. This can be easily done if you have a base controller where all your controller inherit. In fact, you should have a base […]

  7. […] Enterprise Quality Web Application Article #2: Asp.Net MVC Enterprise Quality Web Application Model Article #3: Asp.Net MVC Enterprise Quality Web Application Controller Article #4: Asp.Net MVC Enterprise Quality Web Repository Layer Article #5: Asp.Net MVC Enterprise […]

  8. Anton says:

    Can you please check the following line of the article?
    “The service layer is a layer between the service layer is above the controller…”

    Can you please explain the purpose of the BaseService?
    It is defined in this part of the article, but never used.
    public class WorkoutService : BaseService, IWorkoutService

    Thank you for excellent article series!

    • The purpose of the BaseService is to have shared objects between all you services. In the article, I am passing the MappingFactory and RepositoryFactory. Depending of how your system is designed, you could pass additional information like a “ContextClass” or a “User” class.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.