ASP.NET Core 7.0 Razor Pages -创建动态路由

k4ymrczo  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(110)

我的项目背景故事

我正在尝试添加多种语言到我的网站。为此,我在URL的路径中使用区域设置来区分各种语言。默认网站(英语)位于http://localhost:5000/,而德语页面位于http://localhost:5000/de-de/。我已经可以设置存储在会话中的区域设置。
用户可以通过表单在网站上更改其区域设置。如果用户已将其语言设置为德语,并且尝试访问http://localhost:5000/,则会重定向到位于http://localhost:5000/de-de的德语页面。这对于将用户重定向到正确的路径非常有效。没什么不对的。
例如,如果用户将其区域设置为德语,并且他们尝试进入页面,则此方法也有效:http://localhost:5000/Pictures会将它们重定向到http://localhost:5000/de-de/Pictures。没有任何问题。
目前,我还没有为特定的区域设置创建任何页面。我所做的基本上只是将其设置为重定向到起始页作为回退。由于/de-de/实际上并不存在于网站中,因此它只会使用以下命令加载起始页:Program.cs文件中的app.UseStatusCodePagesWithReExecute("/");
我的问题
由于我只是将用户重定向到一个回退页面的时刻(由于事实上,没有de-de文件夹在我的Pages文件夹),它只加载了英文开始页的内容。因此,如果我访问http://localhost:5000/de-de/Pictures,我实际上看到的是http://localhost:5000/的内容。这可不好。
假设我的Pages文件夹中有两个页面。它们分别称为Index.cshtmlPictures.cshtml。我可以使用默认区域设置(英语)在以下URL访问它们:http://localhost:5000/http://localhost:5000/Pictures

**但是,我如何设置它,使它将加载相应的页面,排除在URL中的地区?**换句话说,如果用户将其区域设置为德语并访问http://localhost:5000/de-de/Pictures,如何使其从http://localhost:5000/Pictures加载HTML?

我还需要它为我以后创建的任何页面工作,例如。/Videos/About等等。它必须是动态的。
不要担心它是英语内容。我可以稍后再解决。我只想实现的是,无需在Pages\de-de处创建子目录,它应该自动加载页面的内容,而无需在URL中设置区域设置。
在未来,我想添加20+语言的网站。我不想有20多个文件夹,每个都包含相同的HTML文件。例如,文件夹和文件结构如下所示:

Pages
    Index.cshtml
    Pictures.cshtml
    /de-de/
        Index.cshtml
        Pictures.cshtml
    /es-es/
        Index.cshtml
        Pictures.cshtml
    /fr-fr/
        Index.cshtml
        Pictures.cshtml

字符串
上面的文件夹结构示例很难维护。我只想在Pages目录中有两个文件(Index.cshtmlPictures.cshtml)。并路由所有其他区域设置以加载这些文件。因此,如果我对Pictures.cshtml文件进行更改,它将更新所有区域设置。
我的中间件
我已经设置了一个名为LocaleMiddleware的中间件,它检查名为"locale"的会话变量,并相应地重定向用户。我不确定是否有什么可以在中间件内部完成。中间件所做的就是将用户重定向到正确的URL。
我需要解决的问题是,让URL从路径中加载页面内容(HTML),而不需要在其中设置区域。

public class LocaleMiddleware
{
    private readonly RequestDelegate _next;

    public LocaleMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Exclude redirects for "/api" and "/auth" paths
        if (context.Request.Path.StartsWithSegments("/api") || context.Request.Path.StartsWithSegments("/auth"))
        {
            await _next(context);
        }
        else
        {
            // Regex pattern for URL ([xx-yy])
            string pattern = @"\/([a-z]{2})-([a-z]{2})";

            // Get locale from session
            string? locale = context.Session.GetString("locale");

            // If no locale, or if locale is default "en-us"
            // Remove any potential locales from URL and redirect them to "root" path
            // E.g. /de-de/Pictures will be reset to /Pictures
            if (String.IsNullOrEmpty(locale) || locale == "en-us")
            {
                if (Regex.IsMatch(context.Request.Path, pattern))
                {
                    // Redirect to page without locale in URL
                    string newPath = Regex.Replace(context.Request.Path, pattern, "");
                    if (String.IsNullOrEmpty(newPath)) newPath = "/";
                    context.Response.Redirect($"{newPath}");
                    return;
                }
            }

            // If locale is set and is not default "en-us" and locale is not currently in the URL
            // Then it should redirect them to the correct locale URL path
            // E.g. if the user has set locale to "de-de" and loads /Pictures it will redirect to /de-de/Pictures
            if (!String.IsNullOrEmpty(locale) && locale != "en-us" && !context.Request.Path.ToString().Contains(locale))
            {
                // Redirect to locale path
                string oldPath = Regex.Replace(context.Request.Path, pattern, "");
                context.Response.Redirect($"/{locale}{oldPath}");
                return;
            }

            await _next(context);
        }
    }
}

public static class RequestLocaleMiddlewareExtensions
{
    public static IApplicationBuilder UseLocaleMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<LocaleMiddleware>();
    }
}

Tl/dr:

基本上,如果用户将其区域设置为de-de,我希望URL为http://localhost:5000/de-de/Pictures,但从http://localhost:5000/Pictures加载HTML内容。以及所有未来的路径,例如/Videos/Contact的数据。
换句话说,逻辑是:

1. Check if the URL path matches Regex pattern for locales [xx-yy]
2. If it does, setup a router to load HTML from the path EXCLUDING the locale


我在哪里以及如何做到这一点?在哪些文件中设置路由?它需要是动态的。

jtjikinw

jtjikinw1#

在asp.net核心中有对本地化的内置支持,您可以检查document相关
根据医生和迈克·布林德的文章
这里有一个最小的例子:

public class CultureTemplatePageRouteModelConvention : IPageRouteModelConvention
    {
        public void Apply(PageRouteModel model)
        {
            var selectorCount = model.Selectors.Count;

            for (var i = 0; i < selectorCount; i++)
            {
                var selector = model.Selectors[i];

                model.Selectors.Add(new SelectorModel
                {
                    AttributeRouteModel = new AttributeRouteModel
                    {
                        //modify -1 to 1 here
                        Order = 1,
                        Template = AttributeRouteModel.CombineTemplates("{culture?}", selector.AttributeRouteModel.Template),
                    }
                });
            }
        }
    }

字符串
在Program.cs中:

builder.Services.AddRazorPages(options=> {
    options.Conventions.Add(new CultureTemplatePageRouteModelConvention()); 
});

builder.Services.AddLocalization();
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[] { "en-us", "zh-cn" };
    options.SetDefaultCulture(supportedCultures[0])
        .AddSupportedCultures(supportedCultures)
        .AddSupportedUICultures(supportedCultures);
    options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
});


....

app.UseRouting();
app.UseRequestLocalization();


页面型号:

public class MyPageModel : PageModel
    {
        private readonly IStringLocalizer<MyPageModel> _localizer;

        public MyPageModel(IStringLocalizer<MyPageModel> localizer) 
        {
            _localizer = localizer;
        }
        
        [FromRoute]
        public string? culture { get; set; }

        public string? Hi { get; set; }
        public void OnGet()
        {
            Hi = _localizer["Hi"];
            if(!String.IsNullOrEmpty(culture))
            {
                Response.Cookies.Append(
             CookieRequestCultureProvider.DefaultCookieName,
             CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
             new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });
            }
            
   
        }
    }


页面:
@Model.Hi;
资源文件:x1c 0d1x的数据
我的项目:



测试结果:



修改资源文件:


相关问题