All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.csharp.S6931.html Maven / Gradle / Ivy

There is a newer version: 10.2.0.105762
Show newest version

Route templates for ASP.NET controller actions, defined via a RouteAttribute or any derivation of HttpMethodAttribute, should not start with "/".

Why is this an issue?

Routing in ASP.NET Core MVC maps controllers and actions to paths in request URIs. Similar routing happens in ASP.NET Framework MVC.

In ASP.NET Core MVC, when an action defines a route template starting with a "/", the route is considered absolute and the action is registered at the root of the web application.

In such a scenario, any route defined at the controller level is disregarded, as shown in the following example:

[Route("[controller]")]  // This route is ignored for the routing of Index1 and Index2
public class HomeController : Controller
{
    [HttpGet("/Index1")] // This action is mapped to the root of the web application
    public ActionResult Index1() => View();

    [Route("/Index2")]   // The same applies here
    public ActionResult Index2() => View();
}

The behavior can be found confusing and surprising because any relative action route is relativized to the controller route.

Therefore, in the vast majority of scenarios, controllers group all related actions not only in the source code, but also at the routing level.

In ASP.NET Framework MVC with attribute routing enabled via MapMvcAttributeRoutes, the mere presence of an absolute route at the action level will produce an InvalidOperationException at runtime.

It is then a good practice to avoid absolute routing at the action level and move the "/" to the root level, changing the template defined in the RouteAttribute of the controller appropriately.

Exceptions

The rule only applies when all route templates of all actions of the controller start with "/". Sometimes some actions may have both relative and absolute route templates, for example for backward compatibility reasons (i.e. a former route needs to be preserved). In such scenarios, it may make sense to keep the absolute route template at the action level.

How to fix it

Code examples

Noncompliant code example

[Route("[controller]")]  // This route is ignored
public class ReviewsController : Controller // Noncompliant
{
    // Route is /reviews
    [HttpGet("/reviews")]
    public ActionResult Index() { /* ... */ }

    // Route is /reviews/{reviewId}
    [Route("/reviews/{reviewId}")]
    public ActionResult Show(int reviewId)() { /* ... */ }
}

Compliant solution

[Route("/")] // Turns on attribute routing
public class ReviewsController : Controller
{
    // Route is /reviews
    [HttpGet("reviews")]
    public ActionResult Index() { /* ... */ }

    // Route is /reviews/{reviewId}
    [Route("reviews/{reviewId}")]
    public ActionResult Show(int reviewId)() { /* ... */ }
}

Resources

Documentation

Articles & blog posts





© 2015 - 2024 Weber Informatics LLC | Privacy Policy