Announcing .NET Core 2.0 | .NET Blog

This post is a reblog from the Official .NET Blog on MSDN.

.NET Core 2.0 is available today as a final release. You can start developing with it at the command line, in your favorite text editor, in Visual Studio 2017 15.3, Visual Studio Code or Visual Studio for Mac. It is ready for production workloads, on your own hardware or your favorite cloud, like Microsoft Azure.

We are also releasing ASP.NET Core 2.0 and Entity Framework Core 2.0. Read the ASP.NET Core 2.0 and the Entity Framework Core 2.0 announcements for details. You can also watch the launch video on Channel 9 to see many of the new features in action.

The .NET Standard 2.0 spec is complete, finalized at the same time as .NET Core 2.0. .NET Standard is a key effort to improve code sharing and to make the APIs available in each .NET implementation more consistent. .NET Standard 2.0 more than doubles that set of APIs that you have available for your projects.

.NET Core 2.0 has been deployed to Azure Web Apps. It is available today in a small number of regions and will expand globally quickly.

.NET Core 2.0 includes major improvements that make .NET Core easier to use and much more capable as a platform. The following improvements are the biggest ones and others are described in the body of this post. Please share feedback and any issues you encounter at dotnet/core #812.



Visual Studio

  • Live Unit Testing supports .NET Core
  • Code navigation improvements
  • C# Azure Functions support in the box
  • CI/CD support for containers

For Visual Studio users: You need to update to the latest versions of Visual Studio to use .NET Core 2.0. You will need to install the .NET Core 2.0 SDK separately for this update.


On behalf of the entire team, I want to express our gratitude for all the direct contributions that we received for .NET Core 2.0. Thanks! Some of the most prolific contributors for .NET Core 2.0 are from companies investing in .NET Core, other than Microsoft. Thanks to Samsung and Qualcomm for your contributions to .NET Core.

The .NET Core team shipped two .NET Core 2.0 previews (preview 1 and preview 2) leading up to today’s release. Thanks to everyone who tried out those releases and gave us feedback.

Using .NET Core 2.0

You can get started with .NET Core 2.0 in just a few minutes, on Windows, MacOS or Linux.

You first need to install the .NET Core SDK 2.0.

You can create .NET Core 2.0 apps on the command line or in Visual Studio.

Creating new projects is easy. There are templates you can use in Visual Studio 2017. You can also create new application at the command line with dotnet new, as you can see in the following example.

You can also upgrade an existing application to .NET Core 2.0. In Visual Studio, you can change the target framework of an application to .NET Core 2.0.

If you are working with Visual Studio Code or another text editor, you will need to update the target framework to netcoreapp2.0.

It is not as critical to update libraries to .NET Standard 2.0. In general, libraries should target .NET Standard unless they require APIs only in .NET Core. If you do want to update libraries, you can do it the same way, either in Visual Studio or directly in the project file, as you can see with the following project file segment that target .NET Standard 2.0.

You can read more in-depth instructions in the Migrating from ASP.NET Core 1.x to ASP.NET Core 2.0 document.

Relationship to .NET Core 1.0 and 1.1 Apps

You can install .NET Core 2.0 on machines with .NET Core 1.0 and 1.1. Your 1.0 and 1.1 applications will continue to use the 1.0 and 1.1 runtimes, respectively. They will not roll forward to the 2.0 runtime unless you explicitly update your apps to do so.

By default, the latest SDK is always used. After installing the .NET Core 2.0 SDK, you will use it for all projects, including 1.0 and 1.1 projects. As stated above, 1.0 and 1.1 projects will still use the 1.0 and 1.1 runtimes, respectively.

You can configure a directory (all the way up to a whole drive) to use a specific SDK by creating a global.json file that specifies a specific .NET Core SDK version. All dotnet uses “under” that file will use that version of the SDK. If you do that, make sure you have that version installed.

.NET Core Runtime Improvements

The .NET Core 2.0 Runtime has the following improvements.

Performance Improvements

There are many performance improvements in .NET Core 2.0. The team published a few posts describing the improvements to the .NET Core Runtime in detail.

.NET Core 2.0 Implements .NET Standard 2.0

The .NET Standard 2.0 spec has been finalized at the same time as .NET Core 2.0.

We have more than doubled the set of available APIs in .NET Standard from 13k in .NET Standard 1.6 to 32k in .NET Standard 2.0. Most of the added APIs are .NET Framework APIs. These additions make it much easier to port existing code to .NET Standard, and, by extension, to any .NET implementation of .NET Standard, such as .NET Core 2.0 and the upcoming version of Universal Windows Platform (UWP).

.NET Core 2.0 implements the .NET Standard 2.0 spec: all 32k APIs that the spec defines.

You can see a diff between .NET Core 2.0 and .NET Standard 2.0 to understand the set of APIs that .NET Core 2.0 provides beyond the set required by the .NET Standard 2.0 spec.

Much easier to target Linux as a single operating system

.NET Core 2.0 treats Linux as a single operating system. There is now a single Linux build (per chip architecture) that works on all Linux distros that we’ve tested. Our support so far is specific to glibc-based distros and more specifically Debian- and Red Hat-based Linux distros.

There are other Linux distros that we would like to support, like those that use musl C Standard library, such as Alpine. Alpine will be supported in a later release.

Please tell us if the .NET Core 2.0 Linux build doesn’t work well on your favorite Linux distro.

Similar improvements have been made for Windows and macOS. You can now publish for the following “runtimes”.

  • linux-x64linux-arm
  • win-x64win-x86
  • osx-x64

Linux ARM32 is now supported, in Preview

The .NET Core team is now producing Linux ARM32 builds for .NET Core 2.0+. These builds are great for using on Raspberry Pi. These builds are not yet supported by Microsoft and have preview status.

The team is producing Runtime and not SDK builds for .NET Core. As a result, you need to build your applications on another operating system and then copy to a Raspberry Pi (or similar device) to run.

There are two good sources of .NET Core ARM32 samples that you can use to get started:

Globalization Invariant Mode

.NET Core 2.0 includes a new opt-in globalization mode that provides basic globalization-related functionality that is uniform across operating systems and languages. The benefit of this new mode is its uniformity, distribution size, and the absence of any globalization dependencies.

See .NET Core Globalization Invariant Mode to learn more about this feature, and decide whether the new mode is a good choice for your app or if it breaks its functionality.

.NET Core SDK Improvements

The .NET Core SDK 2.0 has the following improvements.

dotnet restore is implicit for commands that require it

The dotnet restore command has been a required set of keystrokes with .NET Core to date. The command installs required project dependencies and some other tasks. It’s easy to forget to type it and the error messages that tell you that you need to type it are not always helpful. It is now implicitly called on your behalf for commands like runbuild and publish.

The following example workflow demonstrates the absence of a required dotnet restore command:

Reference .NET Framework libraries from .NET Standard

You can now reference .NET Framework libraries from .NET Standard libraries using Visual Studio 2017 15.3. This feature helps you migrate .NET Framework code to .NET Standard or .NET Core over time (start with binaries and then move to source). It is also useful in the case that the source code is no longer accessible or is lost for a .NET Framework library, enabling it to be still be used in new scenarios.

We expect that this feature will be used most commonly from .NET Standard libraries. It also works for .NET Core apps and libraries. They can depend on .NET Framework libraries, too.

The supported scenario is referencing a .NET Framework library that happens to only use types within the .NET Standard API set. Also, it is only supported for libraries that target .NET Framework 4.6.1 or earlier (even .NET Framework 1.0 is fine). If the .NET Framework library you reference relies on WPF, the library will not work (or at least not in all cases). You can use libraries that depend on additional APIs,but not for the codepaths you use. In that case, you will need to invest significantly in testing.

You can see this feature in use in the following images.

The call stack for this app makes the dependency from .NET Core to .NET Standard to .NET Framework more obvious.

.NET Standard NuGet Packages no longer have required dependencies

.NET Standard NuGet packages no longer have any required dependencies if they target .NET Standard 2.0 or later. The .NET Standard dependency is now provided by the .NET Core SDK. It isn’t necessary as a NuGet artifact.

The following is an example nuspec (recipe for a NuGet package) targeting .NET Standard 2.0.

The following is an example nuspec (recipe for a NuGet package) targeting .NET Standard 1.4.

Visual Studio 2017 version 15.3 updates

Side-by-Side SDKs

Visual Studio now has the ability to recognize the install of an updated .NET Core SDK and light up corresponding tooling within Visual Studio. With 15.3, Visual Studio now provides side-by-side support for .NET Core SDKs and defaults to utilizing the highest version installed in the machine when creating new projects while giving you the flexibility to specify and use older versions if needed, via the use of global.json file. Thus, a single version of Visual Studio can now build projects that target different versions of .NET Core.

Support for Visual Basic

In addition to supporting C# and F#, 15.3 now also supports using Visual Basic to develop .NET Core apps. Our aim with Visual Basic this release was to enable .NET Standard 2.0 class libraries. This means Visual Basic only offers templates for class libraries and console apps at this time, while C# and F# also include templates for ASP.NET Core 2.0 apps. Keep an eye on this blog for updates.

Live Unit Testing Support

Live Unit Testing (LUT) is a new feature we introduced in Visual Studio 2017 enterprise edition and with 15.3 it now supports .NET Core. Users who are passionate with Test Driven Development (TDD) will certainly love this new addition. Starting LUT is as simple as turning it ON from the menu bar: Test->Live Unit Testing->Start.

When you enable LUT, you will get unit test coverage and pass/fail feedback live in the code editor as you type. Notice the green ticks and red x’s shown in the code editor in image below.


IDE Productivity enhancements

Visual Studio 2017 15.3 has several productivity enhancements to help you write better code faster. We now support .NET naming conventions and formatting rules in EditorConfig allowing your team to enforce and configure almost any coding convention for your codebase.

With regards to navigation improvements, we’ve added support for camelCase matching in GoToAll (Ctrl+T), so that you can navigate to any file/type/member/symbol declaration just by typing cases (e.g., “bh” for “BusHelpers.cs”). You’ll also notice suggested variable names (Fig.2) as you are typing (which will adhere to any code style configured in your team’s EditorConfig).

We’ve added a handful of new refactorings including:

  • Resolve merge conflict
  • Add parameter (from callsite)
  • Generate overrides
  • Add named argument
  • Add null-check for parameters
  • Insert digit-separators into literals
  • Change base for numeric literals (e.g., hex to binary)
  • Convert if-to-switch
  • Remove unused variable

Project System simplifications

We further simplified the .csproj project file by removing some unnecessary elements that were confusing to users and wherever possible we now derive them implicitly. Simplification trickles down to Solution Explorer view as well. Nodes in Solution Explorer are now neatly organized into categories within the Dependencies node, like NuGet, project-to-project references, SDK, etc.

Another enhancement made to the .NET Core project system is that it is now more efficient when it comes to builds. If nothing changed and the project appears to be up to date since the last build, then it won’t waste build cycles.


Several important improvements were made to .NET Core support for Docker during the 2.0 project.

Support and Lifecycle

.NET Core 2.0 is a new release, supported by Microsoft . You can start using it immediately for development and production.

Microsoft has two support levels: Long Term Support (LTS) and Current release. LTS releases have three years of support and Current releases are shorter, typically around a year, but potentially shorter. .NET Core 1.0 and 1.1 are LTS releases. You can read more about these support levels in the .NET Support and Versioning post. In that post, “Current” releases are referred to as “Fast Track Support”.

.NET Core 2.0 is a Current release. We are waiting to get your feedback on quality and reliability before switching to LTS support. In general, we want to make sure that LTS releases are at the stage where we only need to provide security fixes for them. Once you deploy an app with an LTS release, you shouldn’t have to update it much, at least not due to platform updates.

.NET Core 1.1

.NET Core 1.1 has transitioned to LTS Support, adopting the same LTS timeframe as .NET Core 1.0.

.NET Core 1.0 and 1.1 will both go out of support on June 27, 2019 or 12 months after the .NET Core 2.0 LTS release, whichever is shorter.

We recommend that all 1.0 customers move to 1.1, if not to 2.0. .NET Core 1.1 has important usability fixes in it that make for a significantly better development experience than 1.0.

Red Hat

Red Hat also provides full support for .NET Core on RHEL and will be providing a distribution of .NET Core 2.0 very soon. We’re excited to see our partners like Red Hat follow our release so quickly. For more information head to RedHatLoves.NET.


We’re very excited on this significant milestone for .NET Core. Not only is the 2.0 release our fastest version of .NET ever, the .NET Standard 2.0 delivers on the promise of .NET everywhere. In conjunction with the Visual Studio family, .NET Core provides the most productive development platform for developers using MacOS or Linux as well as Windows. We encourage you to download the latest .NET Core SDK from and start working with this new version of .NET Core.

Please share feedback and any issues you encounter at dotnet/core #812.

Watch the launch video for .NET Core 2.0 to see this new release in action.

Original Post

[ASP.NET Core MVC Pipeline] Controller Initialization – Action Selection

So, we just finished looking at the Routing Middleware, and that also completes our walk-through the Middleware Pipeline! What happens next? Now we enter the realm of the Controller Initialization, and the first thing we need to do is the Action Selection. Let’s revisit our MVC Core Pipeline flow.

The ASP.NET Core MVC Pipeline
The ASP.NET Core MVC Pipeline

We will now focus on the green part of our pipeline, the Controller Initialization.

Controller Initialization
Controller Initialization

The objective of the process in the green box is:

  1. Find the most suitable Action in the application for that request
  2. Call the Controller Factory informing the required Action
  3. Get an instance of a Controller from the Controller Factory

That is all it does, and it is a very important job 🙂 But, how can we interfere with this process? The first thing we can do is add some rules to make the Action Selection behave as we want it to.

The easiest way

You don't have to customize everything
You don’t have to customize everything

It’s true! You probably already used some alternatives to bend the process of Action Selection towards your objectives. The most common method is to use the Verb Attributes. Let’s imagine you want to create 4 actions in a single controller and each of them will respond to a different HTTP Verb:

What is wrong with this code? All the methods claim the same action path on the route, and the Action Selector has no good way to define which one to call! What will happen when we try to access the /index route?

Ambiguous Exception
Ambiguous Exception

Ambiguous Exception! and that happens, as you can see in the underscored line, because the framework does not have enough information to decide which one is the best candidate action, and that is where we can use a MethodSelectorAttribute:

Now the framework will know the best action to choose based on the HTTP Verb of the Request 🙂

That code exemplifies the kind of intervention that we can do in the process of choosing the most fitting Action Method. But, what if we want to change this behavior in a way that is specific to some kind of logic that we envisioned? That is when you should think about adding an Action Constraint.

What is an Action Constraint?

An Action Constraint is a way that we have to tell the Action Selection process that some method should be a better candidate than the other options for that request. It is really that simple. An action constraint is a class that implements the following Interface:

The Order property will help you define the priority in which that constraint must be evaluated and the Accept method is where the true logic is implemented. Whenever an ActionConstraint is evaluated and the return of the Accept method is TRUE, then it will tell the Action Selection process that this Action is a better suitable match for the request.

Customizing the Action Selection – Custom Action Constraint

Now let’s implement our own IActionConstraint and force the Action Selection process to work as we want it to. Let’s imagine a scenario where we want to serve specific content to our users who access our application through a Mobile Browser, and we want to handle that on the back-end, as we really will serve different data to this users. In this situation we have the following Action Methods:

That would, again, give us the AmbiguousException because, as it is, is impossible to the framework to choose a better Action between those two, so what can we do to help? Let’s implement our action constraint:

I know, I know… there are sure better ways to implement this behavior and that not fool-proof at all, but it is enough for our intents. We set the Order property of our Action Constraint to “0” so it will be one of the first to be evaluated by the framework, and the implementation of our Accept Method returns true if the request’s user-agent container either “Android” or “iPhone” in its value.

So, how to hookup this component to our pipeline? Easy enough:

Ha! Simple, isn’t it?


Default Content
Default Content

When accessing through a common browser, you are going to be redirected to the default implementation of our View…

Mobile Content
Mobile Content

…and when accessed through a Mobile Browser, you will be presented with the specific implementation of our View. Cool, right?

This is one of my favorite pluggable components in the entire framework pipeline. It doesn’t feel too much invasive, and it can help us bend the flow of the request in a very useful way!

What do you think of it? Can we think of a way to use it on your applications?


[ASP.NET Core MVC Pipeline] Routing Middleware – Route Handler

Let’s move on with our series about the Core MVC Pipeline. What is the next step? Last time we learned how to point a request to a specific Router, and what if we need to handle a route in a custom way? Let’s create our custom Route Handler.

Middleware Pipeline
Middleware Pipeline

As we can see, the Route Handler is the last step inside our Routing Middleware and, as long as the request matches any of the routes, is also the last step inside the Middleware Pipeline, we are almost ready to move on to the next phase on the Core MVC Pipeline.

But what exactly does the Route Handler do? Let’s think functionally:

  1. Our Web Server received a request and, since it is a valid request, passed it to our application.
  2. Our application passed the request to our Middleware pipeline which running the request through every middleware until one of them decides to end the request.
  3. The request went through a lot of processes and reached our Routing Middleware.
  4. Our routing middleware will pass the request to our Router who will see if this request matches any known route. If it doesn’t, the middleware will pass the request to the next middleware, or initiate the response.

But what if the request matches any known route? What is next? That is where our Route Handler gets to do its magic!

The Route Handler is the component that defines what to do with the Request that matches a Route on our system. The default implementation for this component is the MvcRouteHandler, which usually handle every single request accepted by the Router, but now we are going to implement our own Route Handler.

Let's Code
Let’s Code

The Code

This component suffered a great deal of changes in the way it is structured on the Full .NET Framework in comparison with the .NET Core implementation.

To implement our Route Handler we are simply going to need a RequestDelegate. This request delegate will contain all the logic that must be executed against a matched route and create a response.

The code for this example will be very simple, as this is a very specialized component, and I don’t see it getting overriding frequently.

It is this simple! In this example any request matched and sent to our RouteHandler will redirect the user to this Blog 🙂 The object “c” is a HttpContext object, so anything that can be done with a request/response flow can be done in the RouteHandler as well.

Now we only have to hook up our RouteHandler on the Routing Middleware:

In the case (line 3) we created a Route that will match ANY request in which the URI starts with “blog/” and send it to our custom router, which will redirect the request.

And that is all there is for a simple custom router 🙂
There is of course other ways to implement Route Handlers but this should be more than enough for the very specific cases where this is necessary.

This wraps up our talk about the Middleware part of the MVC Pipeline! In the next post we start the talk on the Controller Initialization!

See you next time 🙂

That's All Folks
That’s All Folks


Surviving Success: Performance Tuning Under Pressure

You are part of a team responsible for an awesome application that is facing a great and sudden success! Awesome! But success will also, usually, expose some problems with your application that you are not prepared for… And now you are expected to fix a plane that is already on flight! How the hell are you supposed to do that?

I actually stole the title from this post from the name of the interesting video that I would like to share with you that is all about how to deal with this kinds of “success-related problems”.

Slow Down to Move Fast

Source: MS Build 2017

The Fallacy of Premature Optimization

I guess most of the professionals working on the software industry have already heard the following quote about optimization.

Premature optimization is the root of all evil.

This quote was popularized by Donald E. Knuth on his paper Structured Programming with go to statements, what most of us ignore is that the quote, in his most acknowledged form was taken out of the context. A more complete quote goes like this:

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
Yet we should not pass up our opportunities in that critical 3%.

A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code.

As you can see, in a more complete context, the quote has quite a different perspective from ignoring the opportunity of optimizing your code prematurely.

You can, and you should, identify the 3% of your application that is really the critical path for your users, and the optimization of this part of the code should never be ignored, as it can cause you big problems at some point in the future.

Application performance is a subject that has been ignored for a few years with the increase of computational power, but now we are in a moment where users and systems demand the best possible performance from your application, so they can also deliver their results.

It is, of course, you option to identify this 3% as soon as you can, or to let your users find it for you. 🙂

Sources: Surviving Success

Favor Composition Over Inheritance Part 2 | Source: Coding Delight

And here is the second part of the article

Yesterday I wrote part one of my two-part series on why we should favor the technique of composition over inheritance. I began by looking at how a purely inheritance-based model quickly becomes unworkable as the properties and methods of base classes often lead to an inflexible design. Today, by contrast, I will look at solving the same problem by the use of composition. Specifically, we will look at how using interfaces for composition in C# allows for a highly flexible design.

The problem posed yesterday was to model the behavior of a car when a driver applies changes to it. I want to be able to track the angle of the wheels and the speed at which the wheels have been turned by the engine. The first car to model is the Toyota Corolla.

Yesterday, the first class that was designed was the BaseCar class, which contained a number of abstract methods which defined our behavior. It also contained our wheels. Today, instead, I am going to look at the behaviors of the car. It seems to me that there are two separate behaviors which are independent of each other. There is steering and there is driving (or accelerating). These behaviors will form the basis for our interface design. A car also has a manufacturer, so we will create an interface for that too.

There are a couple of ways that we could look at designing the car interface. We could say that an ICar inherits from both ISteering and IDriving, but instead I think we should say that an ICar has both an ISteering and IDriving. This seems to make the most sense.

Already we can see that simply by thinking about the components and how they logically relate to each other, we have created a different design from before. The interfaces help us think more abstractly than base classes would otherwise had. Now that we have designed our interfaces (and the astute reader might have noticed that the Wheel class has now become an IWheel interface too, though defining either is beyond the scope of these articles) we can get started on defining the functionality of our classes.

First we will create a TwoWheelDrive class which implements the IDriving interface.

Immediately it can be seen that this class can be used for both types of two-wheel drive car – front or rear. All we will have to do is pass either the front or rear wheels to it. Next up we’ll implement the two-wheel steering functionality in much the same way. Note that in this case, the steering class has to be a “front” steering class or a “rear” steering class, as each type of steering requires the wheels to turn in opposite directions to achieve the same outcome for the driver.

And next, my Toyota manufacturer class. I’ve implemented it as a singleton because that will be sufficient for this problem.

Finally, I can create my ToyotaCorolla class.

Now when the customer comes along and asks for the rear wheel drive sports edition, I can create the following class for them.

In fact, it is at this point that you can quite easily see that the only difference between ToyotaCorollas lies in the parameters that are passed into the driving constructor. A pattern is emerging. We now have the ability to do away entirely with our ToyotaCorolla class. The only difference is in our constructor parameters. What I can do instead is refactor my code and use constructor parameters to define our classes.

So as you can see, by using composition we have created a much more flexible design. We can reuse the bits that make sense to be reused and ignore the bits that don’t. The interfaces have helped us think abstractly and separated out how the objects relate to each other from how the objects work. We can use a car without knowing how the steering is implemented or whether it is a front, rear or four-wheel drive. We no longer have a complicated object hierarchy and adding new car designs takes a little effort. When it comes time to design a car with four-wheel drive, all we need to do is create a four-wheel drive class and a factory method.

Far too many professional developers think in an “is-a” mindset when they want to reuse code. I hope that I have sufficiently demonstrated that composition helps us reuse code far more efficiently and with a lot less complexity than using inheritance. As always, leave a comment, I would love to hear your feedback!

I am taking two weeks holiday, after which I will be (hopefully) blogging on a regular basis.


Source: Favor Composition Over Inheritance part 2 | Coding Delight

[ASP.NET Core MVC Pipeline] Routing Middleware – Custom IRouter

What if you want to add some custom logic to the routing system?

There are two main components where we can inject our code to bend some rules on the framework. The first one is the IRouter.

Middleware Pipeline - Routing
Middleware Pipeline

In our flow the IRouter is represented by the “Matching to Route Entry” box and that is what it is. The role of the IRouter in the Routing system is to match something on a request, usually on the URI, and point it to the right IRouteHandler. We are going to learn more about the RouteHandler component in a future post.

Why would I do that?

As previously said, the role of the IRouter in the pipeline is to evaluate the request and pass it to the IRouteHandler that is the best fit, but what might be mentioned is that you can also use the IRouter to make modifications to the incoming request. In this way, whenever you have a request that matches a certain criteria you can add, remove or edit some information and let the default RouteHandler do the rest.

In my experience, that is the most common case. I don’t see complete custom implementation of the Routing system so frequently.

The Basics

A bit different from the custom middleware, which is entirely implemented through conventions, the custom Router must implement an Interface called IRouter. This interface is quite simple:

The first method, GetVirtualPath, is used internally by the framework to generate urls based on this route in methods like the HTML.ActionLink one, the second method, RouteAsync, is where our logic will really reside.

Our class should start with something like this:

Routing our Requests

The concept behind the RouteAsync method is quite simple and straightforward, we do all the checking necessary to see if the provided route matches our IRouter context and, if it does, we execute the needed logic and inform the Routing middleware that the request has been handled.

We are doing the checking part on the if statement where we analyze if the request comes from a Mobile User-Agent (there are certainly better and more secure ways to do this but it is enough for the purpose of the demonstration) and if our Router finds that the request comes from such an agent, we apply some logic to change the controller and action values in our RouteData, therefore ensuring that our request will be redirected to the right Action.

If everything works as expected, then we send our modified context to the Default RouteHandler, and let it process it. The RouteHandler will set the value for the Handler property in our context, and it will let the framework know that the request has been Handled by our Router and no longer need to be processed by other Routers.

Hooking up to the Routing Middleware

Now we have a nice and functional Custom Router but if you run the application you will see that it is never touched by your request and that is because we never hooked our Router to the Routing Middleware.

The Routing Middleware has a stack of Routers that it will use to try and match a request, hence we need to add our Custom Router to this Stack. Let’s do it.

Now we add a new Router to the Routes collection and we passed the Default Handler, which will be used by our Routing flow.

And that is all we have to do to make our Router capture every request that comes from a mobile User-Agent and redirect them to specific controllers/actions.

To be completely honest, creating a custom Router will usually be a bit of an overkill as you can achieve most of the desired behaviors through the usage of easier components on the pipeline (including the middleware), but I think that is important to go through all the major components that we can customize.

What do you think? Sounds like something that you can use in your application?

Thanks for Reading! Tot ziens 🙂

MVC Pipeline Series