Asp.Net Core 1.1 MVC Routing in VS2017

For single page applications you can easily use Mvc middleware with following method.

app.UseMvcWithDefaultRoute();

But for an application that presents more than one pages and navigate between those pages often demands a better management of the routes to those pages. You can use Mvc middleware with following method where you can pass route configurations.

app.UseMvc(Action configureRoutes);

As it accepts an action you can pass an action in the form of lambda expression.

app.UseMvc(routes => { });

Simplest Routes

Every route you define in asp.net Mvc points to a controller and an action of that controller. You can map routes to controllers and actions as follows.

app.UseMvc((routes) => {
                routes.MapRoute(name: "default", template: "{controller}/{action}");
            });

MapRoute is a method which helps to create a map between routes and the controllers along with the desired actions to be called. Naming of the route is optional, it is better to name it for the sake of separation of concern. Template provides a basic string template which will match the URL in the request. {controller} is a placeholder to hold the controller name and {action} is a placeholder to hold the action name. If anything goes wrong i.e., controller or actions are not found a 404 page will be returned.

You can also provide the default values for a route map in case controller or action is not found the default will be loaded.

app.UseMvc((routes) => {
    routes.MapRoute(name: "default", template: "{controller}/{action}", defaults: new {
        controller = "Home",
        action = "Index"
    });
});

default is an Object that is why the properties are provided as an anonymous type. If the base URL is requested in the browser i.e., http://localhost:50384/. Asp.net Core execution pipeline will entertain the request and send the request to Home controller’s Index action by default. Defaults can also be provided using assignment operator in the templates.

app.UseMvc((routes) =>
    {
        routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}");
});

Static Routes

You can also add static strings in the route maps and configure the default controllers or actions for these static URLs. All of the following templates are valid to map the routes.

template: “Enterprise/{controller}/{action}”
template: “{controller}-shop/{action}”
template: “payment-{controller}/{action}”
template: “payment/{action}”
template: “payment/checkout”

As long as you have defaults set in a route even the “payment/checkout” template will work since asp.net core knows where to route the request.

Route Ordering

It is always better to keep more specific routes at the top. Asp.net core will match the request URI to each route sequentially and will forward the request to the controller of the first matched template.

Keeping the generic routes at the end will help in solving the problem of mapping specific URI to a generic route on priority.

Action Parameters in Routes

You can also send additional URL segments and map them to the parameters of actions in a controller.

template: “{controller=Home}/{action=Index}/{filter=none}”

Filter is additional segment to the URL that will directly map to the methods parameter with the same name. If no value is provided for the filter segment, none will be passed to the action’s parameter as value.  You can also use ? to mark it as null-able.

template: “{controller=Home}/{action=Index}/{filter?}”

Constraints

You can also make the matching of the URL a little strict by adding constraints to the route. Constraints can be added as a separate named parameter just like template and name or it can be placed inline in the template string.

template: “{controller=Home}/{action=Index}/{id:int?}”

int? enforce the id to be null or an integer. If a string is passed in this segment of the URL it will not match and a 404 page will be returned. Like defaults, constraints can also be set in templates using inline expressions as well as using a separate argument with the name “constraints”. As it’s a fourth argument you will need to pass defaults as well to set the constraints on the route. If you are using inline constraints you can see available constraints list here. Following is an example of route constraints implementation with named parameters.

Add following namespace reference to the class

using Microsoft.AspNetCore.Routing.Constraints;

routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}",
    defaults: new { controller = "Home", action = "Index"},
    constraints: new { id = new IntRouteConstraint()});

There are other built-in RouteConstraints including regex constraints as well implemented in the added namespace. You can also create your own custom constraint and use it with the MapRoute. You can also combine two or more constraints for a MapRoute.

template: “{controller=Home}/{action=Index}/{id:alpha:minlength(6)?}”);

If you are using constraints with named parameter, you can use CompositeRouteConstraint and then you can add your collection of constraints to the CompositeRouteConstraint.

Custom Constraints

You can create your own constraint by creating a class that inherits from “IRouteConstraint“. IRouteConstraint has one method to implement which is

public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)

In your implementation you can write your own logic to return true or false letting asp.net core know that your constraint accepts the URL or reject it.

You can register your constraint in the asp.net core pipeline in ConfigureServices method from Startup class.

services.Configure(options =>
options.ConstraintMap.Add(“MyConstraint”, typeof(MyConstraint)));

Attribute Routes

Cleanest approach to implement routes is to use attribute routes with your controllers and actions.

Attribute routes are enabled by default when app.AddMvc() is called. Its better to use app.UseMvcWithDefaultRoute(); so that default route is added for you automatically.

namespace VenueApp.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            //return Ok("AspNetCore Mvc Content Loaded!");
            return View();
        }

        [Route("[controller]/hello")]
        public IActionResult Greet() {
            return Ok("Hello World");
        }

        public IActionResult Bye() {
            return Ok("Bye");
        }
    }
}

“Greet” method is decorated with an attribute Route having a template of [Controller]/hello which helps Asp.net core Mvc to pass the matching requests to this action.

http://localhost:50384/home/hello

Above URL will point to the Greet action. You can also add RoutePrefix and Route attributes to the controller class which applies to all of the actions in the class. Attribute route template works just like the conventional route template in our previous examples, you can set defaults and constraints using inline expressions.

Attribute Route is cleaner but it is difficult to manage if the application is not properly divided into separation of concerns with respect to controllers. It becomes difficult to keep record of which formation of the URL has been used already in the application since URLs are not managed centrally in a file.

Advertisements

One thought on “Asp.Net Core 1.1 MVC Routing in VS2017

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s