Kestrel and ASP.NET Core MVC use custom base path

时间:2016-10-20 20:13:25

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

How can you mount your app on a different base path?

For example, my controller's route is /api/keywords, but when running the web server I want the basepath to be /development, so my controller route would be /development/api/keywords. I would rather not have to modify my controllers. In old Web API versions you could mount an OWIN app in a different path so I'm looking to do something similar.

3 个答案:

答案 0 :(得分:6)

答案 1 :(得分:0)

您可以查看原创精彩文章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);
    }
}

并且ConfigureServices班级中的Startup方法变为

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

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

答案 2 :(得分:-1)

看看这个:

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和内容根。