0% found this document useful (0 votes)
507 views

Asp Net MVC 6 Changes Every Developer Should Know PDF

The document discusses the changes in ASP.NET MVC 6 from previous versions. Some key changes include: - The project structure and many files have been reorganized, including removing App_Start, Global.asax, and Web.config files. - Modularity is improved through dependency on the OWIN pipeline instead of IIS, allowing for cross-platform hosting. - Embraces new front-end tools like Bower and Gulp for package management and automation. - Startup and configuration is now handled by the Startup.cs file instead of multiple locations previously.

Uploaded by

Ripperina
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
507 views

Asp Net MVC 6 Changes Every Developer Should Know PDF

The document discusses the changes in ASP.NET MVC 6 from previous versions. Some key changes include: - The project structure and many files have been reorganized, including removing App_Start, Global.asax, and Web.config files. - Modularity is improved through dependency on the OWIN pipeline instead of IIS, allowing for cross-platform hosting. - Embraces new front-end tools like Bower and Gulp for package management and automation. - Startup and configuration is now handled by the Startup.cs file instead of multiple locations previously.

Uploaded by

Ripperina
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

ASP.

NET MVC 6 CHANGES


EVERY DEVELOPER
SHOULD KNOW

CONTENTS

Overview 3
MVC 6 New Project Tour

MVC 6 Routing Redefined

10

Taking Control of Configuration in MVC 6

13

Dependency Injection in ASP.NET MVC 6

20

Stay Sharp with Razor TagHelpers

27

A New Direction

30

A publication of

OVERVIEW

ASP.NET MVC 6 is a ground-up rewrite of the popular .NET web framework. While the
fundamental concepts of Model View Controller remain the same, many of the underlying
layers of the framework have changed. This new version of MVC pushes the framework
forward with improved modularity, cross-platform adoption and web standardization.
Modularity
MVC 6 enables developers to use as little or as many features as they see fit. In this
version, developers have the option to write directly "to the metal." In other words,
developers can create middleware that interacts directly with the request pipeline.
MVC 6 is based on the Open Web Interface for .NET or OWIN. OWIN provides the
underlying pipeline infrastructure, while MVC itself consists of a collection of
middleware or modules that can be added to the pipeline to compose an application.
Cross-Platform
Rewriting the framework from scratch provides an added benefit: there is no longer a
dependency on IIS. ASP.NET applications can run in new environments. Now, its possible
to self-host MVC applications, as well as host them on Linux and OSX platforms.

A publication of

Web Standardization
Web development technologies move at a rapid pace. New tools such as Bower, Grunt, Gulp
and Node have become mainstream in a relatively short period of time. Microsoft chose to
not resist the trend but embrace it by supporting these new tools and workflows in Visual
Studio and in MVC 6. The tools also create common ground for cross-platform developers.
In addition to supporting open-source tooling, MVC 6 adopts other web practices such as
using JSON-based configuration files. JSON parses faster than XML, and is easier to read
and edit than XML. JSON configuration files replace files such as: web.config, package.
config, *.sln, and .*proj.
Embracing Change
Understanding why MVC is changing is only part of learning about what's new in MVC
6. Throughout this piece, we'll look at big changes vital to developing an MVC 6 project
such as the new project template, routing, configuration, dependency injection and
tag helpers. We'll explore each of these topics through practical examples, and get an
understanding of how to implement them in a project.

A publication of

MVC 6 NEW PROJECT TOUR

Sweeping changes were made throughout MVC; even some of the most basic elements
have been reorganized. These changes are apparent immediately, when starting a new
MVC 6 project, especially if youre familiar with previous versions of the framework.
Let's click File > New Project and take a tour of the new MVC 6 project template. We'll look
at what's missing from MVC 5, what we can expect to stay the same and what's new.

What's Missing
Before beginning work on a new project, it's important to understand where some familiar items have gone.
Considering MVC 6 is a complete rewrite, you should expect some changes; however, you may be surprised
to find some key items missing.
Well explain all items with replacement counterparts in detail under "What's new."
App_Start: The App_Start folder previously contained various startup processes and settings such as
configuration, identity and routing. Those items have been replaced by the Startup.cs class, which is now
responsible for all app startup tasks.

A publication of

App_data: The App_data folder once held application data such as local database files and log files.
The folder isn't included in this release, but you can add it back. If you choose to use the app_data folder,
proceed with caution as to not make files publicly available by accident. See: App_Data directory in ASP.
NET5 MVC 6 on Stack Overflow for details.
Global.ASAX: The Global.ASAX is no longer needed, because it was yet another place for startup
routines. Instead, all startup functionality has been placed in startup.cs.
Web.Config: The root Web.Config file has been eliminated. The Web.Config was once the XML
equivalent to a settings junk drawer; now all application settings are found in appsettings.json.
Note: A Web.Config can still be found in MVC for configuring static application resources.
Scripts: The scripts directory used to house the application's JavaScript files has a new home. All
JavaScript files now reside under wwwroot/js as a static resource.
Content: Much like the aforementioned Scripts folder, static site resources are in wwwroot.

What's (Mostly) the Same


Very few things remain unchanged in the MVC 6 project template. In fact, the only three items that stayed
the same are the fundamental components of the MVC pattern itself: Models, Views and Controllers.
Models: The models folder remains with a minor change: it now contains data Models only.
Views: Views in MVC 6 are as they were in previous versions; they are dynamic HTML (or .cshtml)
rendered on the server before being sent to the client. Views contain the application UI and are, by
default, built with Bootstrap. One new addition to the views folder is the _ViewImports.cshtml. The
_ViewImports file provides namespaces that can be used by all other views. In previous MVC projects, this
functionality was the responsibility of the web.config file in the Views folder. However, the web.config no
longer exists, and global namespaces are now provided by _ViewImports.
ViewModels: The ViewModels folder was added to differentiate between models used for data and
models used specifically for View data. This addition helps separate concerns within the application.
Controllers: In MVC 6, the controllers folder retains its responsibility to hold application controllers.
Controllers were commonly used to return views, but can serve as Web API endpoints, now that Web API
and MVC have merged. In MVC 6, both MVC controllers and Web API controllers use the same routes and
Controller base class.

A publication of

What's New
At first glance, youll see a lot of new parts to an MVC project. From the root folder down, there are many
new files and folders that come with all new conventions. Let's explore the new items and understand their
purpose in the project.

Src: The absolute root folder of the project is the src (source) folder. This folder is used to identify the
source code of the project. It was added in this version of .NET to match a convention commonly found in
open-source projects, including many popular ones on GitHub.
Wwwroot: The wwwroot folder is used by the host to serve static resources. Sub-folders include js
(JavaScript), CSS, Images and lib. The lib folder contains third-party JavaScript libraries added via Bower
package manager.
Dependencies: More package management options are available in MVC 6. This version includes Bower
and NPM support, which you can configure by GUI. Additionally, you can manage configuration by their
respective .json files, found in the root src folder.

A publication of

Migrations: MVC 6 ships with Entity Framework 7 (EF7), which no longer supports EDMX database
modeling. Because EF7 focuses on code first, database creation, initialization and migration code are
located in the migrations folder.
Services: Services are at the forefront of MVC 6. Because MVC 6 was built with dependency injection
at its core, you can easily instantiate and use services throughout the application (see the chapter
Dependency Injection in ASP.NET MVC 6 for more details).
bower.json & package.json: To support "all things web," MVC 6 now offers first-class support for Bower
and NPM. These popular package management systems were born from the web and open-source
development communities. Bower hosts popular packages such as Bootstrap, while NPM brings in
dependencies such as Gulp. The bower.json and package.json files are used to register and install Bower
and NPM packages with full intellisense support.
{
"name": "ASP.NET",
"private": true,
"dependencies": {
"bootstrap": "3.0.0" ,
"bootstrap-touch-carousel": "0.8.0",
"hammer.

"jquery"

"jquery"-

bootstrap-touch-carousel

"jquery-

github.com/ixisio/bootstrap-touch-carousel

"jquery}
}

bootstrap-touch-carousel

gulpfile.js: Gulp is another tool built for the web, by the web. It is given first-class support in MVC
6. Gulp is a Node.js-based task runner with many plug-ins available from NPM. There are packages
for compiling, minifying and bundling CSS. There are also packages for .NET developers for invoking
MSBuild, NuGet, NUnit and more. gulpfile.js is where you can define Gulp tasks for the application.
hosting.ini: ASP.NET 5 has a pluggable server layer, which eliminates the hard dependency on IIS. The
hosting.ini file is mainly used for configuring WebListener for hosting without IIS & IIS Express.

A publication of

project.json: The project.json file describes the application and its .NET dependencies. Unlike prior
versions of MVC, you can add and remove .NET dependencies for your application using the project.json
file. These dependencies are resolved through NuGet, and full intellisense is enabled within the file; simply
begin typing the desired NuGet package name, and suggestions will appear on-the-fly. You can also
configure cross-platform compilation and build scripts here.
"dependencies": {
"EntityFramework.SqlServer": "7.0.0-beta5",
"EntityFramework.Commands": "7.0.0-beta5",
"Microsoft.AspNet.Mvc": "6.0.0-beta5",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta5",

startup.cs: In previous versions, MVC application startup was handled in App_Start and Global.asax, with
ASP.NET 5 startup handled in Startup.cs. The Startup method is the first method in the application to run,
and is only run once. During startup, the application's configuration is read, dependencies are resolved
and injected, and routes created.
appsettings.json: The appsettings.json file is the primary replacement for the Web.Config. In this
file, you'll specify application settings such as connection string, email endpoints and more. The new
configuration model supports the JSON format which is used throughout MVC 6.

Wrapping Up
The MVC 6 project template embraces the web in many ways. From the root folder and below, most of
the project structure has been revised to align with the ever-changing web. Including NPM and Bower
in addition to NuGet provides developers a wide range of options for bringing modular components
to an application. The standardization on the JSON format for configuration further aligns with web
methodologies. While many things have changed in the project template, the core MVC components have
remained.
"File > New Project" may be a bit intimidating at first, but knowing where to find each piece and its purpose
will give you a head start.

A publication of

MVC 6 ROUTING REDEFINED


Routing has evolved over the MVC framework's history. In MVC 6, routing continues to
improve upon advances made in MVC 5. In this section, we'll look at those changes by
examining where and how routes are defined, reviewing improvements made to attributebased routes, and learning how special attributes can help fine-tune application routing.
Defining Routes
The ASP.NET Routing module is responsible for mapping incoming browser requests to particular MVC
controller actions. Although defining routes in MVC is relatively simple, this task has a long history of being
moved throughout the framework. In past versions, routes were defined in Global.ASAX or App_Start/
RouteConfig.cs; in MVC 6, the location has changed yet again.
Routes in MVC 6 are defined in the Configure method of Startup.cs, when MVC is registered as middleware,
upon app.UseMvc execution.

Convention-Based Routing
Routes defined during configuration are convention-based routes. In MVC 6, you can define
convention-based routes using an Action<IRouteBuilder>, which is a parameter of the UseMvc method.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
// Route to "~/Home/Index/123"
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
// Route to "~/public/blog/posts/show/123"
routes.MapRoute(
name: "blogPost",
template: "public/blog/{controller}/{action}/{postId}");
});
}

A publication of

10

While convention-based routes look and work much like they did in previous versions, a new default way of
specifying default values has been added. Now you can define default values for controller, action or value
in-line; previously, you had to set them in an additional attribute. Simply using an equal sign inside the
template specifies which value to use if no value is present {controller=defalutValue}. Likewise, you can use
nullable types as placeholders for optional parameters {id?}.
// defaults in MVC 6
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
// defaults in previous MVC
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional }
);

While convention-based routes have been updated in this version, they are completely optional. In MVC 6,
attribute-based routing is enabled from the start.

Attribute-Based Routing
Attribute-based routing is an improvement that debuted in MVC 5 and is enabled in MVC 6. Attributebased routing uses attributes to define routes and gives finer control over the URIs in your web application.
The following code shows how you can use attribute-based routing to specify a route for /home/index.
Notice we combine the controller-level attribute with the action-level attribute to complete the full route.
[Route("Home")]
public class HomeController : Controller
{
[Route("Index")]
public IActionResult Index()
{
return View();
}

A publication of

11

You can combine multiple route attributes, as well. For example, you can add a secondary route of
[Route("/")] to enable the index action to be visited from the path http://myapp.com/home/index as well as
from the root of the URL of the application http://myapp.com.
[Route("Home")]
public class HomeController : Controller
{
[Route("Index")]
[Route("/")]
public IActionResult Index()
{
return View();
}
}

In MVC 6, routes have new [controller] and [action] tokens that can reference controller and action names
in the route template. These tokens enable you to name routes after their respective controller or action,
while maintaining flexibility. If you rename the controller or action, the route changes without requiring you
to update the route.
// Route to "~/public/blog/posts/show/123"
[Route("public/blog/[controller]")]
public class PostsController : Controller
{
[Route("[action]/{id}")]
public IActionResult Show(int id)
{
return View();
}
}

Conclusion
Routing in MVC 6 provides multiple options for mapping URIs. The inclusion of both convention-based and
attribute-based routes enables you to mix and match to fit your application's needs.

A publication of

12

TAKING CONTROL OF
CONFIGURATION IN MVC 6

If you're coming to ASP.NET MVC 6 from using prior versions, you'll quickly begin to notice
changes. One of the major changes in this version is the lack of a Web.Config file. In this
section, we'll learn where configuration has moved, what the new features are and how to
get values from configuration to the application.

Where's My Web.Config?
XML configuration is a thing of the past. In ASP.NET MVC 6, the Web.Config was completely removed and
the configuration experience overhauled. The new configuration consists of a variety of options, including
JSON-based files and environment variables.

V
M

Let's take a look at whats provided in a new MVC project.

A publication of

13

New Configuration Options


The new configuration options are available through the Startup routine in startup.cs. In the Startup,
method is a ConfigurationBuilder; it is new to MVC 6 and provides a chain-able API with which you can
define multiple configurations. Out-of-the-box, you have two configuration options in Startup: appsettings.
json and appsettings.{env.EnvironmentName}.json.
// Setup configuration sources.
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

The default configurations use AddJsonFile, which specifies that the configuration will be in JSON format.
If JSON isn't your preferred format, multiple configuration builders are available, including INI, Command
Line and Environment Variables. You can even create your own by implementing the IConfigurationBuilder
interface.
In the standard MVC template, we have appsettings.json and a second optional appsettings defined at
runtime, based on the EnvironmentName, if available. This second appsettings comes in handy when you
need to overload an option.

Overloads

In previous versions of MVC, managing application settings for different environments such as
development and production meant using transformations. In MVC 6, this system is replaced by
configuration overloading.
When you register a configuration in the ConfigurationBuilder, the last value applied wins over any
previous value of the same key.

A publication of

14

//foo.json
{ "mykey" : "Foo" }
//bar.json
{ "mykey" : "Bar" }
//startup.cs
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("foo.json")
.AddJsonFile("bar.json");
//result
Configuration.Get("mykey"); // => Bar

Using configuration overloads, we can have much greater control over how the application behaves in a
given environment.

Getting Values from Configuration in MVC 6


Getting values from configuration has also changed from previous versions of MVC. Before, you could
retrieve values from the ConfigurationManager at the controller level; however, in MVC 6, the values are
available to the application through dependency injection.
At the end of the Startup method, we use ConfigurationBuilder to create a single instance of IConfiguration
when the Build method is called.
Configuration = builder.Build();

Once the configuration is built, the values are injected into the project in the ConfigureServices method.
Inside the ConfigureServices method, you can add settings using services.Configure<T>. You can fetch the
value from configuration by convention, when the key matches the property name, or by specifying the
key explicitly.
In this example, we fetch MyOptions, a POCO with the property ConfigMessage, from configuration and
add it to the services collection.

A publication of

15

//MyOptions.cs (POCO)
public class MyOptions
{
public string ConfigMessage { get; set; }
}
//appsettings.json
{
"MyOptions": {
"ConfigMessage": "Hello from appsettings.json"
}
}
//Startup.cs
//convention
services.Configure<MyOptions>(Configuration.GetConfigurationSection("MyOptions"));
//explicit
services.Configure<MyOptions>(Configuration("MyOptions:ConfigMessage"));

We make the values available to the application's controller by adding the options to any controllers
constructor. Since we're using the dependency injection that has already been made available in MVC 6,
we'll just need to reference the value. Using IOptions<T> as an argument in the constructor will resolve
the dependency. This works because the service provider is resolved for us when we create a controller
instance.
//HomeController.cs
private readonly string configMessage;
public HomeController(IOptions<MyOptions> myConfigOptions)
{
configMessage = myConfigOptions.Value.ConfigMessage;
}
public IActionResult Index()
{
ViewData["Message"] = configMessage; //=> Hello from appsettings.json
return View();
}

A publication of

16

Putting It Together... and In the Cloud

Having seen how appsettings.json works, what overloads do and how to retrieve values, we can put it to
use. We'll continue with the MyOptions example and see how different overrides take place in scenarios
such development, staging and cloud deployment on Azure.

Toggling Config Files


First, let's revisit ConfigurationBuilder in Startup.cs. The configuration builder has two configs, appsettings.
json and config.{env.EnvironmentName}.json. We can use the second config to override settings when
specific environment variables are available. We will start by adding the following configs to our project:
//appsettings.development.json
{
"MyOptions": {
"ConfigMessage": "Hello from config.development.json"
}
}
//appsettings.staging.json
{
"MyOptions": {
"ConfigMessage": "Hello from config.staging.json"
}
}
//appsettings.production.json
{
"MyOptions": {
"ConfigMessage": "Hello from config.production.json"
}
}

A publication of

17

Running the application with the default environment variables will use the ConfigMessage "Hello from
config.development.json." This is because the default EnvironmentName is "development." Changing the
ASPNET_ENV value to "staging" or "production" will get the configuration from the corresponding config
file. To see this in action using Visual Studio, open the project's properties and change ASPNET_ENV value
under the debug menu.

Overriding Using Environment Variables


In addition to toggling appsettings files, you can override set values through environment variables.
Environment variables are ideal for Azure deployment because they separate the server configuration from
the project. Using environment variables for values such as database connection strings and API keys will
ensure the deployed application is always using production values.
Add environment variables to ConfigurationBuilder near the end of the Startup method using the
AddEnvironmentVariables(); method:
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Setup configuration sources.
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// This reads the configuration keys from the secret store.
// For more details on using the user secret store see http://go.microsoft.com/
fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}

A publication of

18

You can set a value in Azure through the management portal from the application's Configure menu.
Under App Settings, enter a key/value pair that corresponds to the value needed by the application. If the
setting has a hierarchy, be sure to use the full name space for the key using : as a separator.
Continuing with the example, we can set the ConfigMessage by adding an environment variable with the
key MyOptions:ConfigMessage and the value Hello from Azure.

The application will only receive the value Hello from Azure when it is deployed; otherwise, it will get its
value from the config file.

Conclusion
Configuration is completely different in MVC 6. The new implementation follows a more modular
development approach common throughout MVC 6. In addition, the JSON format feels ubiquitous with
modern web practices. The new style of configuration may come with a learning curve, but it allows for
greater flexibility.

A publication of

19

DEPENDENCY INJECTION IN
ASP.NET MVC 6

Web API
MVC

SignalR

Dependency injection (DI) has been possible in previous versions of MVC. With each new
version, DI has become easier to implement, and MVC 6 supplies DI right out of the box. In
this section, we'll look at how the new DI implementation works, its weaknesses and how
can we replace it with our favorite DI framework.
What's New
The unification of APIs across ASP.NET is a common theme throughout ASP.NET 5, and DI is no different.
The new ASP.NET stack, which includes MVC, SignalR, Web API and more, relies on a built-in minimalistic
DI container. The core features of the DI container have been abstracted to the IServiceProvider interface
and are available throughout the stack. Because the IServiceProvider is the same across all components of
the ASP.NET framework, you can resolve a single dependency from any part of the application.
The DI container supports just four modes of operation:
Instance: A specific instance is given all the time. You are responsible for its initial creation.
Transient: A new instance is created every time.
Singleton: A single instance is created and acts like a singleton.
Scoped: A single instance is created inside the current scope. It is equivalent to Singleton in
the current scope.

A publication of

20

Basic Setup
Let's walk through setting up DI in an MVC application. To demonstrate the basics, we'll resolve the
dependency for the service used to get project data. We don't need to know anything about the service
,other than that it implements the IProjectService interface, an interface custom to our demo project.
IProjectService has one method, GetOrganization(). This method retrieves an organization and its
corresponding list of projects.
public interface IProjectService
{
string Name { get; }
Organization GetOrganization();
}
public class Organization
{
public string Name { get; set; }
[JsonProperty("Avatar_Url")]
public string AvatarUrl { get; set; }
public IQueryable<Project> Projects { get; set; }
}

We'll use the IProjectService to get the organization data and display it in a view. Let's start by setting up
the controller where the service will be used. We'll use constructor injection by creating a new constructor
method for our controller that accepts an IProjectService. Next, the Index action will call GetOrganization,
sending the data to the view to be rendered.
private readonly IProjectService projectService;
public HomeController(IProjectService projectService)
{
this.projectService = projectService;
}
public IActionResult Index()
{
Organization org = projectService.GetOrganization();
return View(org);
}

If we try to run the application at this point, we'll receive an exception, because we haven't yet added a
concrete implementation of our IProjectService to the DI container.

A publication of

21

InvalidOperationException: Unable to resolve service for type 'DependencyInjectionMVC 6Demo.


Services. IProjectService' while attempting to activate 'DependencyInjectionMVC 6Demo.
Controllers. HomeController'.
Microsoft. Framework. DependencyInjection.
ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean
isDefaultParameterRequired)
The exception message shows that the code fails during a call to ActivatorUtilities.GetService. This is
valuable information, because it shows that in MVC 6, the DI container is already involved in the controller's
construction. Now we just need to tell the container how to resolve the dependency.
To resolve the dependency, we need a concrete implementation of IProjectService. We'll add a
DemoService class, and for simplicity, it will use static dummy data.
public class DemoService : IProjectService
{
public string Name { get; } = "Demo";
public Organization GetOrganization() => new Organization
{
Name = this.Name,
AvatarUrl = $"http://placehold.it/100&text={this.Name}",
Projects = GetProjects()
};
private IQueryable<Project> GetProjects() => new List<Project> {
new Project {
Id = 0,
Description = "Test project 0",
Name = "Test 0",
Stars = 120
},
//...
new Project {
Id = 4,
Description = "Test project 4",
Name = "Test 4",
Stars = 89
}
}.AsQueryable();
}

Finally, we'll instruct the DI container to instantiate a new DemoService whenever IProjectService is
required. To configure the container, we'll modify the ConfigureServices method in Startup.cs. Well add our
configuration to the end of this method.

A publication of

22

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//... other services
// Add MVC services to the services container.
services.AddMvc();
//our services
}

We add the service by using the AddTransient extension method on the services collection, and setting
the IProjectService as the type of Service and the DemoService as the implementation.
public void ConfigureServices(IServiceCollection services)
{
//... other services
// Add MVC services to the services container.
services.AddMvc();
//our services
services.AddTransient<IProjectService, DemoService>();
}

With the service added, DemoService will now be instantiated when we create the controller, and the
exception will no longer be thrown.

GitHub Repos
Demo

Demo

Test 0 (120 Stars)


Test project 0

Test 1 (0 Stars)
Test project 1

Test 2 (5 Stars)
Test project 2

Test 3 (15 Stars)


Test project 3

Test 4 (89 Stars)


Test project 4

A publication of

23

Weaknesses

What I expected my first car to be...

What my first car was...

Having a baked in DI layer throughout the ASP.NET stack is helpful, but you should reserve your
expectations. While it is useful for simple scenarios, it is very limited. The default container only
supports constructor injection, and it can only resolve types with one public constructor. There's no
need to worry though; you have complete control over the DI container, and it's easy to replace with
your favorite DI solution.

Replacing Default MVC 6 DI Container


Setting up a replacement DI container does not require a lot of code, but the process could be more
discoverable. We'll continue with our previous example to show exactly where the extensibility point is.
The method we are using, ConfigureServices, is actually one of two delegates the application
will use to register the DI container and its services. The first and default delegate is an
Action<IServiceCollection>, which was used in the previous example to resolve our DemoService.
The second is a Func<IServiceCollection, IServiceProvider>, which is used to replace the default
container by returning a custom implementation IServiceProvider.
To change from the default and enable use of an alternative IServiceProvider, we'll need to change
the method signature. We can test this easily by modifying our example; we'll change the method
from returning void to IServiceProvider, then at the very end of the method return services.
BuildServiceProvider(). At this point the method does exactly the same thing as before, and we're still
using the default DI container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//... other services
// Add MVC services to the services container.
services.AddMvc();
//our services
services.AddTransient<IProjectService, DemoService>();
return services.BuildServiceProvider();
}

A publication of

24

The application will still build and run just as it did before, except now we've exposed the extensibility point
we need.
Next, we need to add a third-party DI container. There are a variety of DI contaiers to choose from, all with
their own strengths and weaknesses. For this example, we'll be using a DNX compatible alpha version of
Autofac.
To install Autofac, we'll open our package.json file and add the Autofac alpha binaries.
"dependencies": {
...
"Autofac": "4.0.0-alpha2",
"Autofac.Dnx": "4.0.0-alpha2"
}

In the Startup.cs, we'll modify the ConfigureServices method again. This time, we'll add our dependencies
to Autofac and resolve the container back to an IServiceProvider, replacing the default container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//... other services
// Add MVC services to the services container.
services.AddMvc();
//Autofac config
var builder = new ContainerBuilder();
builder.RegisterType<DemoService>()
.As<IProjectService>().InstancePerLifetimeScope();
//Populate the container with services that were previously registered
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}

Now our application is using the Autofac container in place of the default container. We can fully take
advantage of Autofac's features, and because ASP.NET was developed against the IServiceProvider, we
wont need to change any other code in our project.
Let's make one final change to the example by swapping our DemoService to another implementation
using GitHub's REST API to populate our project list. The GitHubService implements the same
IProjectService as DemoService; however, it takes a name parameter in its constructor. Using Autofac, we
can set the Name value of the constructor in the configuration.

A publication of

25

public IServiceProvider ConfigureServices(IServiceCollection services)


{
//...
builder.Register(svc => new GitHubService("Telerik"))
.As<IProjectService>().InstancePerLifetimeScope();
//builder.RegisterType<DemoService>()
//

.As<IProjectService>().InstancePerLifetimeScope();

Restarting the application reveals our new GitHubService was successfully resolved without touching our
controller code.

GitHub Repos
Telerik

razor-converter (143 Stars)

Tool for converting WebForms Views to Razor (C# Only)

less.js (4 Stars)
Leaner CSS

kendo-examples-asp-net (59 Stars)


kendo-examples-asp-net-mvc (81 Stars)
Kendo UI Examples for ASP.NET MVC

jquery-ui-vs-kendo-ui (8 Stars)

A technical comparison of jQuery UI and Kendo UI.

Wrap up & Resources


The new ASP.NET provides out-of-the-box DI throughout the stack. The new DI container is basic enough
to get the job done, but lacks robust configurations. The container is easy enough to replace if you know
where to look, and enables you to use feature-rich third-party tools. You can find the source code for both
the framework and examples for this project at GitHub.
Microsoft.Framework.DependencyInjection
https://github.com/aspnet/DependencyInjection
Article Demo
https://github.com/EdCharbeneau/DependencyInjectionMVC 6Demo

A publication of

26

STAY SHARP WITH RAZOR


TAGHELPERS
TagHelpers syntax looks like HTML: it uses elements and attributes but is processed by Razor on the
server. TagHelpers are an alternative syntax to HTML Helper methods, and they improve the developer
experience by providing a rich and seamless API. This cant be achieved with Razor alone. By seeing
HTMLHelpers used alongside the new TagHelpers, we can easily identify the benefits they provide.
Let's use a simple button as an example. Here we have an HTML link that uses the bootstrap button style
btn btn-primary and an href of /index. The button also includes the text Go Home.
<a href="/index" class="btn btn-primary">Go Home</a>

Go Home
We could create this same markup using the ActionLink HTMLHelper to render the button. However, the
developer experience starts to suffer once we begin adding the button style to the element.
<!-- just a link, no style -->
@Html.ActionLink("Go Home", "Index")
<!-- desired style -->
@Html.ActionLink("Go Home", "Index", "Home", null, new { @class = "btn btn-primary" })

When we add a CSS class to an ActionLink helper, the method signature must be satisfied completely. In
addition to the long method signature, the syntax for adding a CSS class requires additional declaration,
including escape characters. All of this leads to overly complex code intermixed with HTML markup.

A publication of

27

The TagHelper Way


MVC 6 implemented TagHelpers to help remediate the mess that HTMLHelpers made. TagHelpers
continue to use Razor to generate HTML, but they do so in a less obtrusive way. Because TagHelpers rely
on elements and attributes instead of escaping into server-side code, they can behave more like HTML.
Let's revisit the previous example and see how a TagHelper compares to the HTML and HTMLHelper
syntax. This time, we'll start with an anchor tag <a and use the asp-action attribute to initialize the tag
helper. When Razor sees the asp-action attribute, it recognizes the attribute's value is C# code.
When the parser recognizes TagHelper code, the code changes to bold with a purple highlight. (Note:
colors may vary due to system preferences.)
<!-- HTMLHelper -->
@Html.ActionLink("Go Home", "Index", "Home", null, new { @class = "btn btn-primary" })
<!-- TagHelper -->
<a asp-action="Index" class="btn btn-primary">Go Home</a>
<!-- Rendered HTML -->
<a href="/index" class="btn btn-primary">Go Home</a>

Simplified Forms
TagHelpers also excel is in HTML form creation. Previously, MVC relied on complicated HTMLHelpers
to accomplish this task. HTMLHelpers are not ideal for scenarios in which the helper must contain child
elements. To render content within an HTMLHelper, the helper must encapsulate the content within a
using statement. The using statement leads to a poor developer experience by interrupting the normal
flow of HTML with pure C# syntax.
In the following example, the same password reset form is shown using both TagHelpers and
HTMLHelpers. In the code below, notice how TagHelpers provide a much clearer picture of what the
rendered HTML will be like.

A publication of

28

<!-- Form using TagHelpers -->


<form asp-controller="Manage" asp-action="ChangePassword" method="post" class="formhorizontal" role="form">
<h4>Change Password Form</h4>
<hr />
<div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
<div class="form-group">
<label asp-for="OldPassword" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="OldPassword" class="form-control" />
<span asp-validation-for="OldPassword" class="text-danger"></span>
</div>
</div>
<>...</>
<>...</>
<>...</>
</form>
<!-- Form using HTMLHelpers -->
@using (Html.BeginForm("ChangePassword", "Manage", FormMethod.Post, new { @class = "formhorizontal", role = "form" }))
{
<h4>Change Password Form</h4>
<hr />
@Html.ValidationSummary(false,"", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.OldPassword, new { @class = "form-control" })
@Html.ValueFor(m => m.OldPassword)
</div>
</div>

<>...</>
<>...</>
<>...</>
}

Your Choice
TagHelpers are a new addition but not the only choice. TagHelpers improve the developer experience by
making client- and server-side HTML creation virtually seamless. Although TagHelpers are great for the
examples shown here, HTMLHelpers excel at scenarios in which you use Fluent API chaining to construct
complex UIs such as Charts, Grids and Spreadsheets. Consider using a "right tool for the job" approach
when deciding which type of helper to use to build the view.

A publication of

29

A NEW
DIRECTION
ASP.NET MVC 6 takes familiar concepts in
new directions. While MVC6 still follows its
theoretical roots, it is a completely different
framework built for the future of web
development.
Starting with the new project template, we
examined how many of the basic elements
have moved, changed or improved. Routing
received updates that enable better developer
control by mixing convention- and attributebased routing. Vast improvements in handling
configuration and DI can have direct impact on
an application. Finally, new TagHelpers enable
a better developer experience by making
client- and server-side HTML creation virtually
seamless. Understanding these essential
changes to MVC will help you excel on your
next project.

Looking to speed up your MVC 6


development?
Try Telerik UI for ASP.NET MVC, 70+ UI
components and thousands of features weve
developed over the years, so you dont have
to build any UI from the ground up. Enjoy a
wide variety of controls ranging from musthave HTML helpers for every app like Grids,
Dropdowns and Menus to advanced line-ofbusiness UIs such as Charts, Gantt, Diagram,
Scheduler, PivotGrid and Maps.

Try ASP.NET MVC extensions

About the Author


Ed Charbeneau is a web enthusiast, speaker,
writer, design admirer and Developer Advocate
for Telerik. He has designed and developed
web-based applications for business,
manufacturing, systems integration as well as
customer facing websites. Ed enjoys geeking
out to cool new tech, brainstorming about future
technology and admiring great design. You can
find out more at http://edcharbeneau.com.

You might also like