使用 IPageRouteModelConvention 时获取版本
Get version when using IPageRouteModelConvention
我前段时间问过 ,IPageRouteModelConvention
是否以对我来说完美的方式发挥作用。
这样我就可以在不同的 languages/names.
中设置路由
如果我使用 www.domain.com/nyheter
(瑞典语)或 www.domain.com/sistenytt
(挪威语),我仍然只发现在 RouteData
中使用了 News
路由(RouteData.Values["page"]
).
我如何获得哪个版本?
我知道我可以 check/parse context.Request.Path
但我想知道是否有一个内置的 属性 会给我它。
在startup
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddRazorPagesOptions(options =>
{
options.Conventions.Add(new LocalizedPageRouteModelConvention(new LocalizationService(appsettings.Routes)));
});
appsettings.Routes
是从 appsettings.json
读取的
"Routes": [
{
"Page": "/Pages/News.cshtml",
"Versions": [ "nyheter", "sistenytt" ]
},
and so on....
]
class
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
}
});
}
}
}
}
要检索 RouteData
值,您可以在路由模板中指定一个标记。例如,路线 {version}
将添加取自 URL 的第一段的 version
的 RouteData
值。在您的示例中,您没有为 version
指定标记,因此正如您所描述的,它不会有 RouteData
值。
针对您的特定问题的解决方案是 two-part:
- 在创建新的
SelectorModel
时不要使用特定值,而是使用如上所述的标记。
- 有了这个,您现在可以从
RouteData
访问 version
值,但新的问题是 any 值可以提供,无论是否在您的配置中指定。
要解决第二个问题,可以转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
值是否匹配。如果不匹配,"action"(此时它实际上是一个页面)将不匹配并以 404 结束。
有了该实施,您可以将 LocalizedPageRouteModelConvention
的 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
,该 SelectorModel
设置了 Version
RouteData
值,并且被限制为仅允许配置中指定的值。
我前段时间问过 IPageRouteModelConvention
是否以对我来说完美的方式发挥作用。
这样我就可以在不同的 languages/names.
中设置路由如果我使用 www.domain.com/nyheter
(瑞典语)或 www.domain.com/sistenytt
(挪威语),我仍然只发现在 RouteData
中使用了 News
路由(RouteData.Values["page"]
).
我如何获得哪个版本?
我知道我可以 check/parse context.Request.Path
但我想知道是否有一个内置的 属性 会给我它。
在startup
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddRazorPagesOptions(options =>
{
options.Conventions.Add(new LocalizedPageRouteModelConvention(new LocalizationService(appsettings.Routes)));
});
appsettings.Routes
是从 appsettings.json
"Routes": [
{
"Page": "/Pages/News.cshtml",
"Versions": [ "nyheter", "sistenytt" ]
},
and so on....
]
class
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
}
});
}
}
}
}
要检索 RouteData
值,您可以在路由模板中指定一个标记。例如,路线 {version}
将添加取自 URL 的第一段的 version
的 RouteData
值。在您的示例中,您没有为 version
指定标记,因此正如您所描述的,它不会有 RouteData
值。
针对您的特定问题的解决方案是 two-part:
- 在创建新的
SelectorModel
时不要使用特定值,而是使用如上所述的标记。 - 有了这个,您现在可以从
RouteData
访问version
值,但新的问题是 any 值可以提供,无论是否在您的配置中指定。
要解决第二个问题,可以转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
值是否匹配。如果不匹配,"action"(此时它实际上是一个页面)将不匹配并以 404 结束。
有了该实施,您可以将 LocalizedPageRouteModelConvention
的 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
,该 SelectorModel
设置了 Version
RouteData
值,并且被限制为仅允许配置中指定的值。