MVC Routing: Fundamentals and Advanced Techniques

Jun 19, 2023 | .NET

So, you’ve dipped your toes into the immense pool of C# programming and ASP.NET MVC, eh? Exciting, isn’t it?

Well, hold on to your coding hat, because we’re about to plunge into the deeper depths of MVC, particularly, MVC Routing. Intrigued?

Great, because by the end of this article, you’ll be an MVC Routing whizz, handling the feature like a pro!

What is MVC Routing?

Before we dive headfirst into MVC routing, let’s start with the basics.

MVC Routing is a feature in ASP.NET MVC framework that maps URLs to specific actions in controllers. It helps in directing user requests to the right controller actions, making navigation and browsing of web applications possible and meaningful

You know how a postman delivers letters to the correct houses based on their addresses? MVC Routing is like our website’s postman.

It helps deliver the users’ clicks on links to the right pages. Just like how the postman knows which letter goes to which house, MVC Routing knows which click should open which page. Pretty cool, huh?

Understanding the Basics of Routing in MVC

Ever wondered how web applications deal with all those URLs and manage to show you just the right page you asked for? Well, MVC Routing is the sheriff in town that takes care of matching URLs to their corresponding actions. You can think of it as the postman of a web application, always knowing exactly where to deliver your request.

// Define a simple route
routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

This is a basic route in MVC. Here we have a single route named “Default”. It has three components, controller, action and id, with some default values.

EnableEndpointRouting in ASP.NET Core MVC Routing

Now, we can’t ignore the elephant in the room when discussing MVC Routing – EnableEndpointRouting. This setting, introduced in ASP.NET Core, plays quite a pivotal role.

// Set EnableEndpointRouting to false
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options => options.EnableEndpointRouting = false);
}

What’s happening here? Well, we’re switching off the endpoint routing system. I know what you’re thinking: “Why would we need to do that?” Remember, each setting adjustment serves a purpose. But don’t worry, we’ll explore this in the sections to follow!

Types of ASP.NET Core Routing Attributes

Routing attributes in ASP.NET Core provide developers with a lot of flexibility and control over their applications. These attributes allow us to specify how our application responds to specific HTTP verbs and how it handles requests via certain routes.

In this section, we’re going to delve into the different types of routing attributes in ASP.NET Core. Buckle up, because we’re about to embark on an insightful journey.

Route Attribute

First up is the Route attribute, a versatile one that provides us with the ability to apply a routing template directly to a controller or an action.

// The Route attribute applied to a controller
[Route("api/[controller]")]
public class ProductsController : Controller
{
    //...
}

In the above code, [controller] is a token for the controller’s name. So, any request that starts with api/Products will be routed to this controller. It’s your very own URL shortcut maker!

Http Method Attributes

Then, we have the Http Method attributes that let us restrict actions to specific HTTP methods.

HttpGet Attribute

The HttpGet attribute restricts an action method to only respond to HTTP GET requests.

// Responds only to HTTP GET requests
[HttpGet]
public IActionResult GetAll()
{
   // Code to fetch all products
}

In this snippet, GetAll action will only respond to GET requests.

HttpPost Attribute

The HttpPost attribute comes into play when an action should handle only HTTP POST requests.

// Responds only to HTTP POST requests
[HttpPost]
public IActionResult Create(Product product)
{
   // Code to create a new product
}

Here, the Create action will be triggered when the server receives a POST request.

HttpPut Attribute

Similarly, the HttpPut attribute is used when an action should handle only HTTP PUT requests.

// Responds only to HTTP PUT requests
[HttpPut("{id}")]
public IActionResult Update(int id, Product product)
{
   // Code to update an existing product
}

In the given code, the Update action is designed to handle PUT requests for updating a product.

HttpDelete Attribute

The HttpDelete attribute restricts an action method to HTTP DELETE requests.

// Responds only to HTTP DELETE requests
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
   // Code to delete a product
}

The Delete action will answer to the call of a DELETE request to remove a product.

HttpPatch Attribute

Lastly, we have the HttpPatch attribute, which is meant for handling HTTP PATCH requests, typically for partial updates.

// Responds only to HTTP PATCH requests
[HttpPatch("{id}")]
public IActionResult Patch(int id, Product product)
{
   // Code to partially update a product
}

In this example, the Patch action is linked to PATCH requests for partially updating a product.

Name Attribute

The Name attribute offers a convenient way to name routes, making it effortless when generating URLs.

// Naming the route
[HttpGet("/products/display/{id}", Name = "DisplayProduct")]
public IActionResult Display(int id)
{
   // Code to display a product
}

Here, we’ve named the route “DisplayProduct”. This name can then be used while generating URLs or redirects to this action.

Produces and ProducesResponseType Attributes

Finally, the Produces and ProducesResponseType attributes are essential cuando queremos definir the type of content an action method produces and the kind of HTTP status codes it can return.

// Defining the type of content the action method produces
[Produces("application/json")]
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult Get(int id)
{
   // Code to get a product
}

In this code, the Get action is configured to produce JSON responses and is expected to return either a 200 OK or 404 Not Found HTTP status code.

Core Techniques for Routing in MVC

Underneath the smooth operations of MVC, there is a robust mechanism connecting URLs and actions: MVC Routing. It’s like a backstage hero that ensures every click leads to the perfect act. Let’s dig deeper into this world and explore its core techniques and how to work them up in your ASP.NET MVC magic show.

Implementing ASP.NET Core MVC Routing

In the land of web applications, URLs are the wayfinder’s tool. However, what magic happens on clicking a URL that transports you to a precise web page? Well, it’s time to unveil the secret: ASP.NET Core MVC Routing!

MVC Routing revolves around defining patterns and mapping them to specific actions. In the ASP.NET Core Universe, the startup file holds the wand to set these up.

Take this example:

// Define routes in Startup
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "blog",
        template: "Blog/{*article}",
        defaults: new { controller = "Blog", action = "ReadArticle" });
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

That’s a beautiful spell, isn’t it? The template is the enchantment that defines the route’s format. It is the guideline MVC follows to understand your URL and fetch the required page.

The controller=Home and action=Index provide default values to the route, ensuring smooth operation even when not everything loaded perfectly.

Now, the wildcard {*article} and optional parameters {id?} are the secret ingredients, adding flexibility to the spell. These parameters allow our routes to effectively handle a broader range of URLs.

For instance, in our ‘blog’ route, the wildcard takes in everything after ‘Blog/’ as ‘article’. Similarly, {id?} accepts an optional id parameter. These guys make dealing with URLs a piece of cake!

Custom Routing in MVC: Step by Step Guide

Now, let’s move to Custom Routing. Custom Routing in MVC is like sketching your own treasure map – you create your peculiar directional cues and path configurations. It gives you the freedom to define your unique routes to accommodate your application’s different requirements.

Let’s draw a custom map:

// Define a custom route
routes.MapRoute(
    name: "SuperHero",
    url: "SuperHero/{action}/{type}",
    defaults: new { controller = "SuperHero", action = "Index", type = UrlParameter.Optional }
);

In this code, we’re setting a new path exclusively for our superhero fans! The URL starts with “SuperHero”, pointing to the SuperHeroController.

The {action} then specifies the action within the controller. And we’re also throwing in an optional type parameter – if the user specifies a type, that’s great, else we avoid kryptonite and move on smoothly!

Now, if a request arrives with a URL like ‘/SuperHero/Fly/Batman’, MVC interprets Fly as the action and ‘Batman’ as the type of superhero! How cool is that?

Effective Use of Routes MapRoute in MVC

You may be pondering – where does Routes MapRoute fit in all this routing magic? Time to reveal – MapRoute is the magic wand that binds the routing universe together! It’s an all-powerful method to define our routes with precision.

Imagine a scenario where you want different URLs for a video overview and its detailed review:

// Define route for Overview
routes.MapRoute(
    name: "VideoOverview",
    url: "Video/{name}/Overview",
    defaults: new { controller = "Video", action = "Overview" }
);

// Define route for Detailed Review
routes.MapRoute(
    name: "VideoDetail",
    url: "Video/{name}/Detail",
    defaults: new { controller = "Video", action = "Detail" }
);

The routes specified above are for ‘/Video/ComicCon/Overview’ and ‘/Video/ComicCon/Detail’ respectively. The MapRoute method here defines two distinct paths for the video overview and its detailed review.

Thus, Routes MapRoute is like the all-knowing guardian of MVC that can guide the system to make any routing possible.

Now that we have delved deeper into Core Techniques, are you ready to control your MVC routing like a composer leading a symphony? It’s time to dive right into creating some beautiful music, or rather, some perfectly routed web applications!

Core Techniques for Routing in MVC

Routing in MVC isn’t a one-size-fits-all scenario, it’s more like a custom-made suit, tailored to fulfill your unique requirements. Once you grasp the fundamental concepts, the core techniques such as implementing ASP.NET Core MVC routing, custom routing and effectively using routes.MapRoute in MVC set the stage for your play. Let’s delve deeper into each of these categories.

Implementing ASP.NET Core MVC Routing

One critical aspect that distinguishes ASP.NET Core MVC routing from the traditional MVC routing is the level of control it offers. It provides much more flexibility for complex routed services.

For instance, you can have control over how routes are ordered by assigning order values.

// Defining order in routes
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    endpoints.MapControllerRoute(
        name: "OrderedRoute",
        pattern: "{controller}/{action}",
        order: 1); // The order value here gives this route precedence over the default route.
});

This allows the route with the ‘OrderedRoute’ name to take precedence over the default route due to the order value, a truly powerful way to customize your app routing.

Custom Routing in MVC

Step 1: Define your custom route. This involves specifying the route name, URL pattern and default values.

// Define your custom route
routes.MapRoute(
    name: "Categories",
    url: "categories/{name}",
    defaults: new { controller = "Categories", action = "ViewCategory" }
);

In this setup, URLs starting with “categories/{name}” will be directed to the ViewCategory action in CategoriesController.

Step 2: Implement the corresponding action in the controller.

// Implement the `ViewCategory` action in `CategoriesController`. 
public ActionResult ViewCategory(string name)
{
    // Fetch category details based on the name from your database
    return View(category);
}

Astoundingly simple, isn’t it?

Effective Use of Routes MapRoute in MVC

Now, routes.MapRoute isn’t a mere method in MVC. It’s a robust mechanic station that fixes our routing under the hood.

Let’s say we want to display the blog entries by categories. A sample routes.MapRoute could be defined as follows:

routes.MapRoute(
    name: "BlogByCategory",
    url: "Blog/Category/{categoryName}",
    defaults: new { controller = "Blog", action = "ByCategory" }
);

In this route registration, we defined a URL pattern where any URL that starts with “Blog/Category/{categoryName}” is handled by the ByCategory action of BlogController. This way, we can neatly categorize our blog entries.

Advanced Routing Techniques in ASP.NET MVC

Feeling confident about navigating the MVC routing map? Let’s venture onto some uncharted territories. Advanced routing techniques offer tailor-made solutions for tricky situations. Think of these like your best reserve tools when the regular ones don’t quite hit the nail.

Advanced Features of Routing in ASP.NET Core MVC

Say, we have URL constraints for date formats, which must only be numerical. A perfect case for URL constraints!

// Ensure only numerical values are accepted for date parameters
routes.MapRoute(
    name: "Archive",
    url: "Archive/{year}/{month}/{day}",
    defaults: new { controller = "Blog", action = "Archive" },
    constraints: new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" }
);

Here, we’re using Regex to specify that year should be a 4-digit number, while month and day should be 2-digit numbers. It’s like a protective shield for our URLs!

Creating Customized Routing Solutions

Creating custom routing solutions really heats things up! Remember, constraints are your elixir here.

// Custom Constraint
public class WeekendConstraint : IRouteConstraint
{
    public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        DateTime date;
        if (DateTime.TryParse(values[routeKey].ToString(), out date))
        {
            return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
        }
        return false;
    }
}

// Applying custom weekend constraint
routes.MapRoute(
    name: "Weekend",
    url: "{controller}/{action}/{date}",
    defaults: new { controller = "Event", action = "View" },
    constraints: new { date = new WeekendConstraint() }
);

With this, our application honors the weekend like it deserves. It only allows routing on Saturdays and Sundays, giving weekdays a break!

Overcoming Challenges in Advanced MVC Routing

Given the intricate nature of advanced routing that includes dealing with concepts like Route Constraints, Attribute Routing, Areas, Route Names and beyond, mastering these isn’t child’s play. But don’t get overwhelmed; persistence is key.

// Areas in routing
routes.MapRoute(
    name: "Admin",
    template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);

Here, we’ve used Areas, another advanced concept, which simplifies routing by grouping a large set of related controllers into a common area.

Remember, for every challenge that advanced routing throws at you, there exists a solution to navigate. Don’t shy away from experimenting and exploring tailored niche solutions. Your programming journey is what you make of it! Happy coding!

Real-world Applications and Examples of MVC Routing

Let’s realign our focus and dive into the depths where MVC Routing exists in the wild, away from the comfort of our well-groomed tutorials. Welcome to the life center of MVC Routing!

Learning from Real-world Applications of Routing in MVC

Let’s play detective and track down MVC routing in our everyday web applications. One place routing leaves its footprints is Unique Resource Identifiers (URIs).

// Defining a product's route
routes.MapRoute(
    name: "ProductDetail",
    url: "{product}/{ID}",
    defaults: new { controller = "Product", action = "Detail" },
);

The route above is designed for an e-commerce application. In this representation, {product} and {ID} form variables that will be dynamically replaced by actual values.

For instance, if your end user wants to see details about a book with an ID of 123, they would navigate to www.websitename.com/Book/123 which would trigger this route and direct them to the Detail action of the Product controller.

But let’s imagine we have a product page and it has reviews. In that case, we’ll want a place to store individual reviews, right?

// Defining a product's reviews route
routes.MapRoute(
    name: "ProductReview",
    url: "{product}/{productID}/Review/{reviewID}",
    defaults: new { controller = "Product", action = "ReviewDetail" },
);

This route maps to a specific review (reviewID) for a particular product (productID). Quite handy, isn’t it?

If you’ve ever booked a room in an online hotel chain, you’ve seen MVC routing in action. The page URL reads something like www.bookingsite.com/hotels/hotelID/room/roomID, doesn’t it?

Case Study: Building a Robust System Using Custom Routing in MVC

Alright, let’s play around with our toolbox and dive into the land of custom routing.

Imagine we’re designing a blog website, where articles are categorized by year, month and day of publishing. We’ll want to design routes to filter articles based on their publishing date, right?

// Defining a date-specific article route
routes.MapRoute(
    name: "DateSpecific",
    url: "article/{year}/{month}/{day}",
    defaults: new { controller = "Article", action = "Index" },
    constraints: new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" }
);

In this route, the constraints ensure that the year, month and day parameters are in the correct format. Take a look at the URL www.blogsite.com/article/2020/02/20. It directs you to all the articles published on February 20 of 2020!

Moving on, let’s say you’re creating a multi-language site where URLs need to be language specific. Ever done online shopping where you select a country and see the page rendered in that locale’s language? Yep, MVC routing magic right there!

// Define a multi-language route
routes.MapRoute(
    name: "Multilanguage",
    url: "{language}/{controller}/{action}",
    defaults: new { controller = "Home", action = "Index", language = "en" }
);

The URL www.websitename.com/es/Home/Index will show you the Home page in Spanish. Equally, www.websitename.com/fr/Home/Index would show you the same page, but translated into French. It’s almost like your website becomes a world traveler who can switch languages effortlessly, meeting local user needs as it goes!

So you see, the limits of MVC routing are bound only by the edges of your imagination. Keep exploring and remember, in the world of routing, you are the artist and the web application is your canvas. Paint away!

Tips and Best Practices for MVC Routing

Taking a stroll through the virtual world of routing can seem like a labyrinth at times. There are numerous pathways and the challenge lies in navigating effectively and efficiently. Let’s say you’ve got the basics of MVC Routing down.

That’s great, but remember, every journey to mastery is filled with tips and tricks learnt along the way. So let’s dive into some of mine, shall we?

Optimizing the Performance of Routes MapRoute in MVC

MVC routing is a versatile creature. It can be tailored to fit any web application, but like a tuxedo, it requires precise customization. One cardinal rule in optimization is understanding the importance of sequence.

routes.MapRoute(
    "Blog", // Name of the route
    "Blog/{action}", // URL structure
    new { controller = "Blog", action = "Index" } // Defaults
);
routes.MapRoute(
    "Default", // Name of the route
    "{controller}/{action}/{id}", // URL structure
    new { controller = "Home", action = "Index", id = "" } // Defaults
);

In the above code, we’ve defined two routes: one for the blog section of our web application (Blog) and the other as a default route (Default). The Blog route is placed first because it’s more specific.

If we didn’t, requests meant for the blog would instead default to the home page. Now, we wouldn’t want our users greeted with a homepage when they’re trying to catch up on some reading, would we?

Now, let’s introduce default values for our route parameters:

routes.MapRoute(
    "Api",
    "api/{controller}/{id}", 
     new { action = "DefaultAction", id = UrlParameter.Optional } // Defaults
);

By setting the id parameter as optional (UrlParameter.Optional), we’re allowing requests with and without an id to be handled. Remember, our goal is to give our users a smooth experience. These tiny tweaks go a long way in helping us achieve that.

Keeping Your MVC Routing Solution Maintainable and Scalable

As a developer, your role is akin to a city planner. You’re presented with a vast landscape (your web application) and your job is to ensure every road (or route, in our case) leads exactly where it should. Over time, as you add more and more routes, it becomes increasingly crucial to keep this routing map maintainable and scalable.

Hence, one key tip I can give you is to split your routes logically. MVC supports areas that can help you to group your routes:

public class AdminAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get
        {
            return "Admin";
        }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "Admin_default",
            "Admin/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
        );
    }
}

Area registration provides a way to separate different parts of your application into their own namespaces, which can simplify the routing. Plus, it will make your life much easier when the project grows.

Attribute-based routing is another practice that can be employed to improve maintainability. It allows you to specify your routes directly in the action and controller. It’s like giving your postman a GPS and a detailed map.

[Route("api/[controller]")]
public class ShoppingController : Controller
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        ...
    }
}

In this example, we’re defining our route in the ShoppingController itself. The HttpGet attribute implies that this action responds to the HTTP GET method. This code is immensely readable and clean, isn’t it?

Lastly, like any good coder, comment as much as necessary to make your work easily understandable, especially when you’re working in teams. It may seem unnecessary when you’re knee-deep in code, but when you’re bundled up in bed wondering why you routed your e-commerce site a particular way, you’ll thank yourself for those comments.

Remember, the goal is to put on the hat of a simple user when creating web applications. You might know the ins and outs of your application, but your user doesn’t. With thoughtful routing, we can create user-friendly URLs, ultimately enhancing the user’s overall experience. So remember, every line of code you write down needs to ultimately benefit the user. If it doesn’t, you might want to rethink it.

The Role of AI and Machine Learning in Routing

Imagine a system intelligently routing your requests based on your usage patterns. Will AI and Machine Learning mark the dawn of intelligent routing? Only time will tell.

Remember, friends, MVC routing isn’t a monster to be afraid of. Try to make it your friend. We’ll meet again with another interesting topic from the glorious world of MVC!

Until then, keep routing and keep exploring. Happy coding!

You May Also Like

Sign up For Our Newsletter

Weekly .NET Capsules: Short reads for busy devs.

  • NLatest .NET tips and tricks
  • NQuick 5-minute reads
  • NPractical code snippets
.