Routing Razor Pages to /example.com/en/ format

你。 提交于 2020-06-27 04:27:07

问题


I have three languages on my website. I'm trying to get my razor pages to route to culture/localization like so:

https://localhost:44396/en/
https://localhost:44396/ru/

I have hundreds of lines of code commented out at this point using methods I've been googling for the past two days and nothing seems to do the job. The website is mostly static so right now beyond the culture there is nothing else that needs routing.


回答1:


Here's a way you can do it that doesn't require you to put a middleware attribute on all of your pages. This works globally.

In the ConfigureServices method of Startup.cs, add the following:

services.AddMvc().AddRazorPagesOptions(options => {
     options.Conventions.AddFolderRouteModelConvention("/", model => {
         foreach (var selector in model.Selectors) {
             selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{lang=en}", selector.AttributeRouteModel.Template);
         }
     });
 });

services.Configure<RequestLocalizationOptions>(options => {
    var defaultCulture = new CultureInfo("en");
    var supportedCultures = new CultureInfo[] {
        defaultCulture,
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(defaultCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider() {
        RouteDataStringKey = "lang",
        UIRouteDataStringKey = "lang",
        Options = options
    });
});

This sets up the global route, your supported cultures, and sets the primary culture provider to come from the route. (This still leaves the other providers intact, so failing the Route values, it can still set the culture based on the Query String, Cookies, or Language Header.)

Now, in your Configure method (still in Startup.cs), add the following:

var routeBuilder = new RouteBuilder(app) {
    DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
};
routeBuilder.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
var router = routeBuilder.Build();

app.Use(async (context, next) => {
    var routeContext = new RouteContext(context);
    await router.RouteAsync(routeContext);

    context.Features[typeof(IRoutingFeature)] = new RoutingFeature() {
        RouteData = routeContext.RouteData
    };

    await next();
});

var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
app.UseMvc();

There's some trickery here. Firstly, we have to call app.UseRequestLocalization before we call app.UseMvc, or else our program will run before we've changed the current culture. But the problem is, app.UseMvc() is the one that sets up RouteData. So, until you call it, the routing values are all blank. Ergo, when the RouteDataRequestCultureProvider goes to try and observe what {lang} is, it'll come back empty, and thus always default you to en. Catch 22.

So, we just go manually populate the RouteData ourselves in our own custom middleware. That way, the RouteDataRequestCultureProvider can see it, and all will work well.

(I admit this is not the most efficient, as you're just duplicating the routing work that app.UseMvc() will itself also do, but I'll take that unnoticeable delay to ensure all my pages are localized.)




回答2:


I will tell you what I do which works. The only difference is that I use the 5 characters language code but I guess it is not something difficult to change.

Make sure that you have the following nuget library installed

Microsoft.AspNetCore.Localization.Routing

In the ConfigureServices method of the Startup.cs we type the following code under the servcies.AddMvc();

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        options.Conventions.AuthorizeFolder("/Account/Manage");
        options.Conventions.AuthorizePage("/Account/Logout");
        options.Conventions.AddFolderRouteModelConvention("/", model =>
        {
            foreach (var selector in model.Selectors)
            {
                var attributeRouteModel = selector.AttributeRouteModel;
                attributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{lang=el-GR}", attributeRouteModel.Template);
            }
        });
    });

IList<CultureInfo> supportedCultures = new List<CultureInfo>
{
    new CultureInfo("en-US"),
    new CultureInfo("fr-FR"),
    new CultureInfo("el-GR"),
};

var MyOptions = new RequestLocalizationOptions()
{
    DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US"),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures
};
MyOptions.RequestCultureProviders = new[]
{
     new RouteDataRequestCultureProvider() { RouteDataStringKey = "lang", Options = MyOptions }        // requires nuget package Microsoft.AspNetCore.Localization.Routing
};

services.AddSingleton(MyOptions);

We add the following class

using Microsoft.AspNetCore.Builder;
public class LocalizationPipeline
{
    public void Configure(IApplicationBuilder app, RequestLocalizationOptions options)
    {
        app.UseRequestLocalization(options);
    }
}

Now you have to add the following line over your PageModel class:

[MiddlewareFilter(typeof(LocalizationPipeline))]
public class ContactModel : PageModel
{
    public void OnGet()
    {

    }
}

I hope it helps.



来源:https://stackoverflow.com/questions/50581293/routing-razor-pages-to-example-com-en-format

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!