.NET6 Razor Pages实现URL含自定义文化路由的方法
在.NET6 Razor Pages中实现URL带文化标识的本地化方案
要实现URL中显示文化标识(如www.website.com/en/services),需要从路由配置、文化提取、链接生成三个核心部分调整,以下是具体步骤:
1. 修改路由配置,支持文化前缀
更新MapRazorPages的路由模板,为所有页面添加可选的文化前缀参数,并添加约束确保只有支持的文化码能通过:
app.MapRazorPages() .AddRazorPagesOptions(options => { // 为所有页面路由添加文化前缀约束 options.Conventions.AddAreaPageRoute("", "/{culture:regex(^en$|^fr$|^nl$)}/", ""); options.Conventions.AddPageRoute("/{culture:regex(^en$|^fr$|^nl$)}/", ""); });
2. 自定义URL文化提取提供器
默认的请求本地化不会从URL提取文化,需要自定义RequestCultureProvider,优先从URL的culture参数中获取文化值:
2.1 实现自定义文化提供器
在项目中添加如下类:
public class UrlRequestCultureProvider : RequestCultureProvider { public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext) { if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); var culture = httpContext.Request.RouteValues["culture"]?.ToString(); if (!string.IsNullOrEmpty(culture) && SupportedCultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase))) { return Task.FromResult(new ProviderCultureResult(culture, culture)); } // URL中无有效文化时,返回null,将使用后续提供器(如Cookie) return Task.FromResult<ProviderCultureResult>(null); } public IList<CultureInfo> SupportedCultures { get; set; } }
2.2 注册自定义提供器
在Program.cs的本地化配置中,将自定义提供器添加到最前面,确保优先从URL提取文化:
builder.Services.Configure<RequestLocalizationOptions>(opt => { var supportedCultures = new List<CultureInfo> { new CultureInfo("en"), new CultureInfo("fr"), new CultureInfo("nl") }; opt.DefaultRequestCulture = new RequestCulture("en"); opt.SupportedCultures = supportedCultures; opt.SupportedUICultures = supportedCultures; // 移除默认提供器,添加自定义URL提供器 opt.RequestCultureProviders.Clear(); opt.RequestCultureProviders.Add(new UrlRequestCultureProvider { SupportedCultures = supportedCultures, Options = opt }); // 保留Cookie提供器作为 fallback opt.RequestCultureProviders.Add(new CookieRequestCultureProvider()); });
3. 生成带文化标识的URL链接
在Razor页面中,生成链接时需要传入当前文化参数,确保URL包含文化前缀:
3.1 直接在页面中生成链接
<a href="@Url.Page("/Services", new { culture = CultureInfo.CurrentCulture.Name })">服务页面</a>
3.2 扩展方法简化调用(可选)
创建一个URL扩展方法,自动携带当前文化:
public static class UrlHelperExtensions { public static string PageWithCulture(this IUrlHelper urlHelper, string pageName, object routeValues = null) { var currentCulture = CultureInfo.CurrentCulture.Name; var routeDict = new RouteValueDictionary(routeValues); routeDict["culture"] = currentCulture; return urlHelper.Page(pageName, routeDict); } }
在页面中使用:
<a href="@Url.PageWithCulture("/Services")">服务页面</a>
4. 处理无文化前缀的URL重定向(可选)
如果需要将不带文化的URL(如www.website.com/services)重定向到默认文化的URL,可添加一个中间件:
app.Use(async (context, next) => { var culture = context.Request.RouteValues["culture"]?.ToString(); if (string.IsNullOrEmpty(culture)) { var defaultCulture = "en"; var newPath = $"/{defaultCulture}{context.Request.Path}{context.Request.QueryString}"; context.Response.Redirect(newPath); return; } await next(); });
注意:此中间件需要放在UseRouting之后,UseAuthorization之前。
修改后的完整Program.cs代码
using System.Globalization; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.Razor; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); builder.Services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization(); builder.Services.Configure<RequestLocalizationOptions>(opt => { var supportedCultures = new List<CultureInfo> { new CultureInfo("en"), new CultureInfo("fr"), new CultureInfo("nl") }; opt.DefaultRequestCulture = new RequestCulture("en"); opt.SupportedCultures = supportedCultures; opt.SupportedUICultures = supportedCultures; opt.RequestCultureProviders.Clear(); opt.RequestCultureProviders.Add(new UrlRequestCultureProvider { SupportedCultures = supportedCultures, Options = opt }); opt.RequestCultureProviders.Add(new CookieRequestCultureProvider()); }); builder.Services.AddHttpContextAccessor(); builder.Services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 无文化前缀重定向中间件 app.Use(async (context, next) => { var culture = context.Request.RouteValues["culture"]?.ToString(); if (string.IsNullOrEmpty(culture)) { var defaultCulture = "en"; var newPath = $"/{defaultCulture}{context.Request.Path}{context.Request.QueryString}"; context.Response.Redirect(newPath); return; } await next(); }); app.UseAuthorization(); app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value); app.MapRazorPages() .AddRazorPagesOptions(options => { options.Conventions.AddAreaPageRoute("", "/{culture:regex(^en$|^fr$|^nl$)}/", ""); options.Conventions.AddPageRoute("/{culture:regex(^en$|^fr$|^nl$)}/", ""); }); app.Run(); public class UrlRequestCultureProvider : RequestCultureProvider { public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext) { if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); var culture = httpContext.Request.RouteValues["culture"]?.ToString(); if (!string.IsNullOrEmpty(culture) && SupportedCultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase))) { return Task.FromResult(new ProviderCultureResult(culture, culture)); } return Task.FromResult<ProviderCultureResult>(null); } public IList<CultureInfo> SupportedCultures { get; set; } }
内容的提问来源于stack exchange,提问作者Kilerz159753
相关产品推荐
相关产品推荐

