agc93
8/2/2017 - 6:28 AM

Runtime route prefixing

Runtime route prefixing

services.AddSingleton<PrefixRouteConvention>();
services.Configure<MvcOptions>(opts => opts.Conventions.Add(services.BuildServiceProvider().GetService<PrefixRouteConvention>())); 
public class PrefixRouteConvention : IActionModelConvention
    {
        private readonly string _prefix;
        private readonly ILoggerFactory _factory;

        public DownlinkRouteConvention(IConfiguration config, ILoggerFactory factory) {
            _prefix = config.GetValue("RoutePrefix", string.Empty);
            _factory = factory;
        }
        public void Apply(ActionModel action)
        {
            if (action.Controller.ControllerType == typeof(Controllers.ApiController)) { // restrict to this controller
                foreach(var selector in action.Selectors) {
                    selector.ActionConstraints.Add(
                        new RouteActionConstraint(
                            _prefix,
                            _factory.CreateLogger(nameof(RouteActionConstraint))));
                }
            }
        }
    }
public class RouteActionConstraint : IActionConstraint, IActionConstraintMetadata
    {
        private readonly ILogger _logger;

        public string Prefix { get; private set; }
        internal RouteActionConstraint(string prefix, ILogger logger) {
            Prefix = prefix;
            _logger = logger;
        }
        public int Order => 0;

        public bool Accept(ActionConstraintContext context)
        {
            _logger.LogDebug("Matching route using prefix: {0}", Prefix ?? string.Empty);
            return string.IsNullOrWhiteSpace(Prefix)
                ? true
                : context.RouteContext.RouteData.Values.First().Value?.ToString() == Prefix; 
                // this is specifically for prefix, and would need to be improved for other routing scenarious
        }
    }
[Route("{prefix?}")]
public class ApiController : Controller {}