Asp.net core 2.2 перехватывает и изменяет значения данных маршрута - локализация URL - PullRequest
1 голос
/ 24 июня 2019

Можно ли в ядре 2.2 asp.net перехватывать для каждого запроса данные маршрута и (возможно) изменять значения, такие как целевые значения controller / action?

Мне нужно использовать схему локализованных URL-адресов с двухбуквенной спецификацией культуры и локализованными именами контроллеров / действий, например:

/en/contact-us
/it/contatti
/de/kontakte

я не хочу использовать атрибутную маршрутизацию для украшения контроллеров и действий;вместо этого я хочу захватить данные маршрута и, основываясь на culture и controller/action, получить целевой контроллер и действие, возможно, со словарной ассоциацией.Я уже сделал такую ​​вещь в asp.net (не основной) MVC.

До сих пор я могу захватить маршрутизацию с помощью этого кода:

        app.Use(async (context, next) =>
        {
            var routeData = context.GetRouteData();


            routeData.Values["controller"] = ....;
            routeData.Values["action"] = .....;

            await next();
        });

, но данные маршрута заполненытолько для URL, точно сопоставленных с существующим контроллером / действием, иначе - ноль;похоже, это связано с методом AttributeRouting.CreateAttributeMegaRoute ядра asp.net, который отображает только существующие контроллеры / действия.

1 Ответ

1 голос
/ 26 июня 2019

Вот обходной путь, который работает для меня:

<b>// if the route matches this pattern, let's say:</b>
app.UseMvc(routeBuilder => {
    routeBuilder.MapRoute("route1",template: "/{controller=Home}/{action=Index}");
});

<b>// else if the route matches `{culture=en-US}/{controller=Home}/{action=Index}`</b>
app.UseRouter(routeBuilder =>{
    var template = "{culture=en-US}/{controller=Home}/{action=Index}";
    routeBuilder.MapMiddlewareRoute(template, appBuilder =>{
        appBuilder.Use(async(context, next)=>{
            var routeData = context.GetRouteData();
            var controller = routeData.Values["controller"] as string;
            var action= routeData.Values["action"] as string;
            var culture= routeData.Values["culture"] as string;
            // get the real backing path according to current route data
            context.Request.Path = getNormalizedPath(routeData);  
            await next();
        });
        appBuilder.UseRequestLocalization();
        appBuilder.UseMvc(rb=>{
            rb.MapRoute(name:"cultureRoute",template:template);
        });
    });
    <strike>// if you have other MVC routes, add them below:</strike>
    <strike>// routeBuilder.MapRoute(name:"mvcRoutes",template: "{area:exists}/{controller=Home}/{action=Index}");</strike>
});

<b>// else if doesn't match the above pattern, let's say:</b>
app.UseMvc(routeBuilder => {
    routeBuilder.MapRoute("route3",template: "/test/mvc/{controller=Home}/{action=Index}");
});
private string getNormalizedPath(RouteData routeData)
{
    var culture= routeData.Values["culture"] as string;
    var controller = routeData.Values["controller"] as string;
    var action= routeData.Values["action"] as string;

    controller = ... real controller according to current culture & controller string
    action = ... real action according to current culture & controller string
    return $"/{culture}/{controller}/{action}";
}

Вам нужно настроить getNormalizedPath(routeData), чтобы получить реальный путь, который будет перенаправлен на резервный контроллер / действие.

Чтобы автоматически настроить функцию запроса локализации в соответствии с текущим путем маршрута, вам необходимо вставить RouteDataRequestCultureProvider:

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]{
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("de"),
        new CultureInfo("it"),
    };
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
    options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
});

Как обнаружил @ ʞᴉɯ в комментариях, первый UseMvc() не работает хорошо для 2.2. Нам нужно изменить MVC-совместимость на CompatibilityVersion.Version_2_1:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...