Table of contents

Last updated .

< Previous chapterNext chapter >

The architecture of an ASP.Net MVC application

In this chapter I will explore in depth the principles of the MVC architecture as it's implemented in ASP.Net and also other high-level aspects.

The model-view-controller pattern lends itself well to the web, with its stateless architecture. The three piers in MVC are:

MVC architecture
MVC architecture

Model objects are agnostic of the views and controllers and views do not have any direct knowledge of models. Controllers orchestrate the interactions of the models and views. The MVC pattern thus enforces the principle of separation of concerns, which is a sound principle that enhances maintainability of the solution. Business logic is best kept out of the controllers and in separate components. Model objects, too, are best implemented in one or more separate assemblies, which encourages encapsulation and separation of concerns.

The ASP.Net version of MVC facilitates test-driven development. The framework uses interfaces extensively, thus decoupling abstract contracts from implementations. This enables swapping one component for another, for example mock objects. Controllers can thus be tested independently. The use of abstract interfaces also make it possible to plugin custom components to replace the default ASP.Net components, for example it is possible to use a custom view engine or URL router.

The ASP.NET URL-routing component lets you build applications that have comprehensible and searchable URLs. URLs do not have to include filename extensions, and support URL naming patterns that work well for search engine optimization (SEO) and representational state transfer (REST) addressing.

.Net eXecution environment

In contrast with previous versions, ASP.Net is built on DNX which stands for .Net eXecution environment. It is both an SDK and a runtime environment that make it possible to build and run .Net applications on Windows, Linux and Mac. It provides a host process and CLR hosting logic. DNX was mainly built for running cross-platform ASP.NET Web applications. DNX is based on .Net Core, which is a downscaled version of the full .Net library. This has the very important implication that, by default, there are quite a lot of .Net components, types and methods that can no longer be used in a ASP.Net web application. A DNX project is a folder with a project.json file. The name of the project is the folder name. The output from DNX projects is one or more NuGet packages. The project.json file defines package metadata, your project dependencies and which frameworks you want to build for. More details on DNX can be found here.

Dependency injection

ASP.Net comes with dependency injection (DI) built in. The main motivation for using dependency injection is that of testability. When testing components that have their dependencies injected, these dependencies can be mocked and passed to a constructor instead of the "real" component. A classic example of this is the mocking of a data access component to decouple a datastore in test scenarios.

Classes that depend on one or more services should declare the dependency via constructor parameters. The component that is responsible for instantiating objects is termed a "Inversion of Control" (IoC) container. It is essentially a factory that can create an object, based on which interface is requested. ASP.Net comes with such a built-in container, identified by the interface IServiceProvider. A dependent type is referred to as a "service".

The ConfigureServices method of the Startup class is the place to add services for dependency injection. The method receives a IServiceCollection parameter, which exposes methods for configuring various services for injection. Most of these methods are extension methods that add a particular service or group or services, for example AddAuthorization to add services related to authorization. The ConfigureServices method has already been used in the previous chapters to add MVC to the game, with the code services.AddMvc(). In addition, there are four more general methods for adding a service. They accept two parameters, namely an abstract type and a concrete type, respectively. The difference is in the lifetime of the objects they create:

ASP.NET MVC 6 controllers should request their dependencies explicitly via their constructors. In some instances, individual controller actions may require a service, and it may not make sense to request at the controller level. In this case, you can also choose to inject a service as a parameter on the action method. Sometimes you don’t need a service for more than one action within your controller. In this case, it may make sense to inject the service as a parameter to the action method. This is done by marking the parameter with the attribute [FromServices].

< Previous chapterNext : Using the Razor view engine >

2016 by Niels Hede Pedersen Linked in