Asp Net MVC 6 Changes Every Developer Should Know PDF
Asp Net MVC 6 Changes Every Developer Should Know PDF
CONTENTS
Overview 3
MVC 6 New Project Tour
10
13
20
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
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.
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
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
A publication of
13
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.
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
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.
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.
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
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 1 (0 Stars)
Test project 1
Test 2 (5 Stars)
Test project 2
A publication of
23
Weaknesses
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.
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
.As<IProjectService>().InstancePerLifetimeScope();
Restarting the application reveals our new GitHubService was successfully resolved without touching our
controller code.
GitHub Repos
Telerik
less.js (4 Stars)
Leaner CSS
jquery-ui-vs-kendo-ui (8 Stars)
A publication of
26
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
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
<>...</>
<>...</>
<>...</>
}
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.