Автоматически создавать строчные штриховые маршруты в ASP.NET Core
ASP.NET Core по умолчанию использует CamelCase-маршруты, такие как http://localhost:5000/DashboardSettings/Index. Но я хочу использовать строчные маршруты, которые ограничены тире: http://localhost:5000/dashboard-settings/index Они более распространены и последовательны, поэтому мое приложение расширяет сайт работает Wordpress, который также имеет строчные URL-адреса с тире.
Я узнал, что я могу изменить URL-адреса в нижнем регистре с помощью параметров маршрутизации:
services.ConfigureRouting(setupAction => {
setupAction.LowercaseUrls = true;
});
Это работает, но дает мне URL-адреса без разделителя, такие как http://localhost:5000/DashboardSettings/Index, которые плохо читаемы. Я мог бы определить пользовательские маршруты, используя атрибут route, например
[Route("dashboard-settings")]
class DashboardSettings:Controller {
public IActionResult Index() {
// ...
}
}
Но это вызывает дополнительную работу и подвержено ошибкам. Я бы предпочел автоматическое решение, которое ищет символы в верхнем регистре, вставьте перед ним тире и сделайте прописную букву < char в нижнем регистре. Для старого ASP.NET это не было большой проблемой, но на ядре ASP.NET я не вижу направления, как справиться с этим.
Каким образом это можно сделать здесь? Мне нужен какой-то интерфейс, где я могу генерировать URL-адреса (например, для помощников тегов) и заменять там CamelCase на тире-разделители. Тогда мне нужен другой вид интерфейса для маршрутизации, так что URL-адреса тире-разделителя преобразуются обратно в CamelCase для правильного сопоставления с моими именами контроллеров/действий.
Ответы
Ответ 1
Немного опоздал на вечеринку здесь, но.. Можно сделать это путем реализации 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();
}
}
Затем зарегистрируй его в Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(options => options.Conventions.Add(new DashedRoutingConvention()));
}
Более подробную информацию и пример можно найти здесь https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing.
Ответ 2
Я использую Asp.NetCore 2.0.0 и Razor Pages (нет явного контроллера), поэтому все, что вам нужно:
-
Включить строчные адреса:
services.AddRouting(options => options.LowercaseUrls = true);
-
Создайте файл с именем Dashboard-Settings.cshtml
, и полученный маршрут станет /dashboard-settings
Ответ 3
Обновление в ASP.NET Core 2.2
В методе ConfigureServices
класса Startup
:
services.AddRouting(option =>
{
option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
option.LowercaseUrls = true;
});
И класс SlugifyParameterTransformer
должен быть следующим:
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();
}
}
И конфигурация маршрута должна быть следующей:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller:slugify}/{action:slugify}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
Это сделает /Employee/EmployeeDetails/1
маршрут к /employee/employee-details/1
Ответ 4
Спасибо за информацию, однако лучше отфильтровать селектор, чтобы пропустить те, у которых есть шаблон пользовательского маршрута: [HttpGet("/[controller]/{id}")]
например)
foreach (var selector in controllerAction.Selectors
.Where(x => x.AttributeRouteModel == null))
Ответ 5
Скопировано из ASP.NET 2.2 Основной документации:
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();
}
}