Automatically generate lowercase dashed routes in ASP.NET Core

后端 未结 5 753
花落未央
花落未央 2020-12-09 09:15

ASP.NET Core uses CamelCase-Routes like http://localhost:5000/DashboardSettings/Index by default. But I want to use lowercase routes, which are delimitted by dashes: http://

相关标签:
5条回答
  • 2020-12-09 09:42

    Thanks for the information, however it's better to filter the selectors, in order to skip those with a custom route template : [HttpGet("/[controller]/{id}")] for example)

    foreach (var selector in controllerAction.Selectors
                                             .Where(x => x.AttributeRouteModel == null))
    
    0 讨论(0)
  • 2020-12-09 09:50

    I'm using Asp.NetCore 2.0.0 and Razor Pages (no explicit controller necessary), so all that's needed is:

    1. Enable Lowercase Urls:

      services.AddRouting(options => options.LowercaseUrls = true);

    2. Create a file named Dashboard-Settings.cshtml and the resulting route becomes /dashboard-settings

    0 讨论(0)
  • 2020-12-09 09:54

    Copied from ASP.NET Core 3.0 (unchanged from 2.2) documentation:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.Conventions.Add(new RouteTokenTransformerConvention(
                                         new SlugifyParameterTransformer()));
        });
    }
    
    public class SlugifyParameterTransformer : IOutboundParameterTransformer
    {
        public string TransformOutbound(object value)
        {
            if (value == null) { return null; }
    
            // Slugify value
            return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
        }
    }
    
    0 讨论(0)
  • 2020-12-09 09:57

    A little late to the party here but.. Can do this by implementing IControllerModelConvention.

     public class DashedRoutingConvention : IControllerModelConvention
     {
            public void Apply(ControllerModel controller)
            {
                var hasRouteAttributes = controller.Selectors.Any(selector =>
                                                   selector.AttributeRouteModel != null);
                if (hasRouteAttributes)
                {
                    // This controller manually defined some routes, so treat this 
                    // as an override and not apply the convention here.
                    return;
                }
    
                foreach (var controllerAction in controller.Actions)
                {
                    foreach (var selector in controllerAction.Selectors.Where(x => x.AttributeRouteModel == null))
                    {
                        var template = new StringBuilder();
    
                        if (controllerAction.Controller.ControllerName != "Home")
                        {
                            template.Append(PascalToKebabCase(controller.ControllerName));
                        }
    
                        if (controllerAction.ActionName != "Index")
                        {
                            template.Append("/" + PascalToKebabCase(controllerAction.ActionName));
                        }
    
                        selector.AttributeRouteModel = new AttributeRouteModel()
                        {
                            Template = template.ToString()
                        };
                    }
                }
            }
    
            public static string PascalToKebabCase(string value)
            {
                if (string.IsNullOrEmpty(value))
                    return value;
    
                return Regex.Replace(
                    value,
                    "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z])",
                    "-$1",
                    RegexOptions.Compiled)
                    .Trim()
                    .ToLower();
            }
    }
    

    Then registering it in Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc(options => options.Conventions.Add(new DashedRoutingConvention()));
    }
    

    Can find more info and example here https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing

    0 讨论(0)
  • 2020-12-09 10:04

    Update in ASP.NET Core Version >= 2.2

    To do so, first create the SlugifyParameterTransformer class should be as follows:

    public class SlugifyParameterTransformer : IOutboundParameterTransformer
    {
        public string TransformOutbound(object value)
        {
            // Slugify value
            return value == null ? null : Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
        }
    }
    

    For ASP.NET Core 2.2 MVC:

    In the ConfigureServices method of the Startup class:

    services.AddRouting(option =>
    {
        option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
    });
    

    And route configuration should be as follows:

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

    For ASP.NET Core 2.2 Web API:

    In the ConfigureServices method of the Startup class:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options => 
        {
            options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }
    

    For ASP.NET Core >=3.0 MVC:

    In the ConfigureServices method of the Startup class:

    services.AddRouting(option =>
    {
        option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
    });
    

    and route configuration should be as follows:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapAreaControllerRoute(
            name: "AdminAreaRoute",
            areaName: "Admin",
            pattern: "admin/{controller:slugify=Dashboard}/{action:slugify=Index}/{id:slugify?}");
    
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller:slugify}/{action:slugify}/{id:slugify?}",
            defaults: new { controller = "Home", action = "Index" });
    });
    

    For ASP.NET Core >=3.0 Web API:

    In the ConfigureServices method of the Startup class:

    services.AddControllers(options => 
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
    });
    

    For ASP.NET Core >=3.0 Razor Pages:

    In the ConfigureServices method of the Startup class:

    services.AddRazorPages(options => 
    {
        options.Conventions.Add(new PageRouteTransformerConvention(new SlugifyParameterTransformer()));
    });
    

    This is will make /Employee/EmployeeDetails/1 route to /employee/employee-details/1

    0 讨论(0)
提交回复
热议问题