【问题标题】:Kestrel and ASP.NET Core MVC use custom base pathKestrel 和 ASP.NET Core MVC 使用自定义基本路径
【发布时间】:2016-10-20 20:13:25
【问题描述】:

如何将应用挂载到不同的基本路径上?

例如,我的控制器的路由是 /api/keywords,但是在运行 Web 服务器时,我希望基本路径是 /development,所以我的控制器路由是 /development/api/keywords。我宁愿不必修改我的控制器。在旧的 Web API 版本中,您可以在不同的路径中安装 OWIN 应用程序,所以我正在寻找类似的东西。

【问题讨论】:

    标签: asp.net-web-api asp.net-core asp.net-core-mvc kestrel-http-server


    【解决方案1】:

    【讨论】:

    【解决方案2】:

    您可以查看原创精彩文章here

    首先创建一个继承自IApplicationModelConvention接口的类

    public class EnvironmentRouteConvention : IApplicationModelConvention
    {
        private readonly AttributeRouteModel _centralPrefix;
    
        public EnvironmentRouteConvention(IRouteTemplateProvider routeTemplateProvider)
        {
            _centralPrefix = new AttributeRouteModel(routeTemplateProvider);
        }
    
        public void Apply(ApplicationModel application)
        {
             foreach (var controller in application.Controllers)
            {
                var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList();
                if (matchedSelectors.Any())
                {
                    foreach (var selectorModel in matchedSelectors)
                    {
                        //This will apply only to your API controllers. You may change that depending of your needs
                        if (selectorModel.AttributeRouteModel.Template.StartsWith("api"))
                        {
                            selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, selectorModel.AttributeRouteModel);
                        }
                    }
                }
            }
        }
    

    然后创建一个类只是为了更容易和更清洁的使用。

    public static class MvcOptionsExtensions
    {
        public static void UseEnvironmentPrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
        {
            opts.Conventions.Insert(0, new EnvironmentRouteConvention(routeAttribute));
        }
    }
    

    现在要使用它,首先非常常用,将您的环境保存在 Startup 类的属性中

    private IHostingEnvironment _env;
    
    public Startup(IHostingEnvironment env)
    {
        _env = env;
    }
    

    然后你需要做的就是调用你的静态扩展类

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.UseEnvironmentPrefix(new RouteAttribute(_env.EnvironmentName));
        });
    }
    

    但还有最后一件事需要关心。无论您有什么客户端使用您的 API,您当然不想更改您发送的 HTTP 请求的所有 URL。所以诀窍是创建一个中间件,它将修改您请求的Path 以包含您的环境名称。 (source)

    public class EnvironmentUrlRewritingMiddleware
    {
        private readonly RequestDelegate _next;
    
        public EnvironmentUrlRewritingMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task Invoke(HttpContext context, IHostingEnvironment env)
        {
            var path = context.Request.Path.ToUriComponent();
            //Again this depends of your need, whether to activate this to your API controllers only or not
            if (!path.StartsWith("/" + env.EnvironmentName) && path.StartsWith("/api"))
            {
                var newPath = context.Request.Path.ToString().Insert(0, "/" + env.EnvironmentName);
                context.Request.Path = newPath;
            }
            await _next.Invoke(context);
        }
    }
    

    您的Startup 类中的ConfigureServices 方法变为

    public void ConfigureServices(IServiceCollection services)
    {
        app.UseMiddleware<EnvironmentUrlRewritingMiddleware>();
        services.AddMvc(options =>
        {
            options.UseEnvironmentPrefix(new RouteAttribute(_env.EnvironmentName));
        });
    }
    

    唯一的缺点是它不会更改您的 URL,因此如果您使用浏览器访问 API,您将看不到包含您的环境的 URL。 response.Redirect 始终发送 GET 请求,即使原始请求是 POST 也是如此。我还没有找到反映 URL 路径的最终解决方案。

    【讨论】:

      【解决方案3】:

      看看这个:

      public class Program
      {
         public static void Main(string[] args)
         {
              var contentRoot = Directory.GetCurrentDirectory();
      
              var config = new ConfigurationBuilder()
                 .SetBasePath(contentRoot)
                 .Build();
      
              var hostBuilder = new WebHostBuilder()
      
                //Server
                 .UseKestrel()
      
                 //Content root - in this example it will be our current directory
                 .UseContentRoot(contentRoot)
      
                 //Web root - by the default it's wwwroot but here is the place where you can change it
                 .UseWebRoot("wwwroot")
      
                 //Startup
                 .UseStartup<Startup>();
      
      
              var host = hostBuilder.Build();
      
              host.Run();
          } 
      }
      

      有两种扩展方法 - UseWebRoot() 和 UseContentRoot() - 可用于配置 Web 和内容根。

      【讨论】:

      • 这是关于文件路径,而不是 HTTP 请求路径。与OP的问题无关
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      相关资源
      最近更新 更多