Search code examples
c#asp.net-corecoding-styleasp.net-core-routinghard-coding

Are path templates defined using Attribute Routing considered hard coded?


If I'm using Attribute Routing in an ASP.NET controller, are those path templates considered hard coded? For instance, if I add [HttpGet("/employee")] or [Route("/employee")], is the /employee path a hard-coded value?


Solution

  • As others have noted in the comments, these routes are definitely hard-coded—but that may not be a real concern. It would be useful to better understand what requirements are driving this concern, as the solution will ultimately depend on that. In the meanwhile, I can provide some high-level guidance based on common scenarios.

    Single Tier Web Application

    If your controllers are distributed as part of your web application, and your routes are always defined at design time (i.e., as part of your development process), then it's just a stylistic preference as to whether your route paths are hard-coded as part of your controllers or hard-coded as part of your Startup class. This is the typical scenario for most web applications.

    Distributable Class Library

    If you're distributing your controllers as part of a Class Library (or a Razor Class Library) which is intended to be used on multiple web applications, then this is a bigger consideration. In that scenario, hard-coding the routes as part of your controller prevents consumers of your class library from modifying the paths.

    This could be advantageous if you want to ensure the same routes are always used while simultaneously eliminating the need to configure them on a per-application basis. But it may instead make sense to allow each application to customize these routes in their Startup class, thus giving consumers flexibility to customize where your library's endpoints live. If that's the case, hard-coding these values in your class library's controllers is undesirable.

    Extension Methods

    If the latter is the requirement, it's common to include an extension method for IRouteBuilder and/or IEndpointRouteBuilder so that consumers can easily configure routes for your library, while accepting parameters for any variables you expect them to override, such as a path prefix. This provides a balance between flexibility and ease of configuration. For example, this might look something like the following:

    public static ControllerActionEndpointConventionBuilder MapEmployeeRoute(
      this IEndpointRouteBuilder routes,
      string pathPrefix = "Employee",
      string controller = "Employee",
      string action = "Index"
    ) =>
     routes.MapControllerRoute(
       name: "Employee-" + pathPrefix?.Replace("/", "", System.StringComparison.OrdinalIgnoreCase),
      pattern: pathPrefix?.Trim('/') + "/{action}",
      defaults: new { controller, action, pathPrefix }
    );
    

    Which could be used with any of the following calls:

    public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) > {
      …
      app.UseRouting();
      app.UseEndpoints(endpoints => {
        endpoints.MapEmployeeRoute();                           //Maps /Employee
        endpoints.MapEmployeeRoute("Administration/Staff");     //Maps /Administration/Staff/
        endpoints.MapEmployeeRoute("/Administration/Staff/");   //Tolerate variations
        endpoints.MapEmployeeRoute("Staff", "MyEmployee");      //Reference derived controller
        endpoints.MapEmployeeRoute("Staff", "Employee", "Add"); //Default to the Add() action
      });
    }
    

    Dynamic Route Configuration

    Note: This is a pretty uncommon scenario, and so I hesitate to even bring it up. That said, I'm including it for completeness in case it relates to your requirements.

    Another scenario where hard-coding the routes may be a concern is if, for some reason, you need them to be dynamically configured at run-time and/or are using configuration values from an external data source.

    For example, if you're building a platform as a service (PAAS), it's sometimes desirable to provide a web interface where users can configure routes associated with particular services, and then have those dynamically registered, instead of hard-coding them into the platform itself. That's a far more involved approach, though.