Get version when using IPageRouteModelConvention

时光毁灭记忆、已成空白 提交于 2019-12-10 17:13:55

问题


I sometime ago asked how to add some kind of localized url's, were IPageRouteModelConvention came into play in a, for me, perfect way.

With that I'm able to have routes in different languages/names.


If I use www.domain.com/nyheter (swedish) or www.domain.com/sistenytt (norwegian) I still only find, in RouteData, that the News route were used (RouteData.Values["page"]).

How do I get which version?

I know I can check/parse the context.Request.Path but am wondering if there is a built-in property that will give me it instead.


In startup

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

appsettings.Routes is read from appsettings.json

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

The 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
                        }
                    });
                }
            }
        }
    }

回答1:


To retrieve a RouteData value, you can specify a token within the template for a route. For example, the route {version} would add a RouteData value of version that would be taken from the URL's first segment. In your example, you don't specify a token for version and so there will be no RouteData value for it, as you've described.

The solution for your specific problem is two-part:

  1. Instead of using specific values when creating new SelectorModels, use a token as described above.
  2. With this in place, you will now be able to access a version value from RouteData, but the new problem is that any value can be provided, whether or not it was specified in your configuration.

To solve the second problem, you can turn to IActionConstraint. Here's an implementation:

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 takes a list of allowed values (e.g. nyheter, sistenytt) and checks whether or not the version RouteData value matches. If it doesn't match, the "action" (it's really a page at this point) won't be a match and will end up with a 404.

With that implementation in place, you can update your implementation of LocalizedPageRouteModelConvention's Apply to look like this:

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)
        }
    });
}

This implementation adds a single new SelectorModel that's set up with a Version RouteData value and is constrained to only allow the values specified in configuration.



来源:https://stackoverflow.com/questions/56090637/get-version-when-using-ipageroutemodelconvention

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