首页 > 解决方案 > 使用 IPageRouteModelConvention 时获取版本

问题描述

前段时间我问如何添加某种本地化的 urlIPageRouteModelConvention对我来说,这是一种完美的方式。

有了它,我就可以拥有不同语言/名称的路线。


如果我使用www.domain.com/nyheter(swedish) 或www.domain.com/sistenytt(norwegian),我仍然只能在 中发现使用RouteData了该News路线 ( RouteData.Values["page"])。

我如何获得哪个版本?

我知道我可以检查/解析,context.Request.Path但我想知道是否有一个内置属性可以代替它。


startup

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddRazorPagesOptions(options =>
    {
        options.Conventions.Add(new LocalizedPageRouteModelConvention(new LocalizationService(appsettings.Routes)));
    });

appsettings.Routesappsettings.json

"Routes": [
  {
    "Page": "/Pages/News.cshtml",
    "Versions": [ "nyheter", "sistenytt" ]
  },
  and so on....
]

班上

public class LocalizedPageRouteModelConvention : IPageRouteModelConvention
    {
        private ILocalizationService _localizationService;

        public LocalizedPageRouteModelConvention(ILocalizationService localizationService)
        {
            _localizationService = localizationService;
        }

        public void Apply(PageRouteModel model)
        {
            var route = _localizationService.LocalRoutes().FirstOrDefault(p => p.Page == model.RelativePath);
            if (route != null)
            {
                foreach (var option in route.Versions)
                {
                    model.Selectors.Add(new SelectorModel()
                    {
                        AttributeRouteModel = new AttributeRouteModel
                        {
                            Template = option
                        }
                    });
                }
            }
        }
    }

标签: c#asp.net-corerazor-pagesasp.net-core-2.2

解决方案


要检索一个RouteData值,您可以在模板中为路由指定一个标记。例如,路由{version}会添加一个取自 URL 的第一段的RouteData值。version在您的示例中,您没有指定令牌version,因此正如您所描述的那样,它没有任何RouteData价值。

针对您的特定问题的解决方案分为两部分:

  1. 在创建新SelectorModels 时不要使用特定的值,而是使用如上所述的标记。
  2. 有了这个,您现在可以从 访问一个versionRouteData,但新问题是可以提供任何值,无论它是否在您的配置中指定。

要解决第二个问题,您可以转向IActionConstraint. 这是一个实现:

public class VersionConstraint : IActionConstraint
{
    private readonly IEnumerable<string> allowedValues;

    public VersionConstraint(IEnumerable<string> allowedValues)
    {
        this.allowedValues = allowedValues;
    }

    public int Order => 0;

    public bool Accept(ActionConstraintContext ctx)
    {
        if (!ctx.RouteContext.RouteData.Values.TryGetValue("version", out var routeVersion))
            return false;

        return allowedValues.Contains((string)routeVersion);
    }
}

VersionConstraint获取允许值的列表(例如nyheter, sistenytt)并检查值是否version RouteData匹配。如果不匹配,“动作”(此时它实际上是一个页面)将不匹配,并以 404 结束。

有了该实现,您可以将LocalizedPageRouteModelConvention's的实现更新Apply为如下所示:

var route = _localizationService.LocalRoutes().FirstOrDefault(p => p.Page == model.RelativePath);
if (route != null)
{
    model.Selectors.Add(new SelectorModel
    {
        AttributeRouteModel = new AttributeRouteModel
        {
            Template = "{version}"
        },
        ActionConstraints =
        {
            new VersionConstraint(route.Versions)
        }
    });
}

这个实现添加了一个新SelectorModel的,它设置了一个Version RouteData值,并且被限制为只允许配置中指定的值。


推荐阅读