Kestrel 和 ASP.NET 核心 MVC 使用自定义基本路径
Kestrel and ASP.NET Core MVC use custom base path
如何将应用挂载到不同的基本路径?
例如,我的控制器路由是/api/keywords,但是当运行网络服务器时,我希望基本路径是/development,所以我的控制器路由是/development/api/keywords .我宁愿不必修改我的控制器。在旧的 Web API 版本中,您可以在不同的路径中安装 OWIN 应用程序,所以我希望做类似的事情。
看看这个:
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 和内容根。
您可以查看原大文章here
首先创建一个继承自IApplicationModelConvention
接口的class
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);
}
}
}
}
}
然后创建一个 class 只是为了更容易和更清洁的使用。
public static class MvcOptionsExtensions
{
public static void UseEnvironmentPrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
{
opts.Conventions.Insert(0, new EnvironmentRouteConvention(routeAttribute));
}
}
现在开始使用它,首先很常见,将您的环境保存在启动 class
的 属性 中
private IHostingEnvironment _env;
public Startup(IHostingEnvironment env)
{
_env = env;
}
然后你需要做的就是调用你的静态扩展 class
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.UseEnvironmentPrefix(new RouteAttribute(_env.EnvironmentName));
});
}
但是还有最后一件事需要关心。无论您有什么客户端使用您的 API,您肯定不想更改您发送的所有 URL HTTP 请求。所以诀窍是创建一个中间件,它将修改您请求的 Path
以包含您的环境名称。 ()
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
class 变成了
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.
的路径
有一个名为 UsePathBase 的新方法可以轻松完成此操作。
https://github.com/aspnet/HttpAbstractions/blob/bfa183747f6fb528087554c3d6ec58ef05f1c10a/src/Microsoft.AspNetCore.Http.Abstractions/Extensions/UsePathBaseExtensions.cs
如何将应用挂载到不同的基本路径?
例如,我的控制器路由是/api/keywords,但是当运行网络服务器时,我希望基本路径是/development,所以我的控制器路由是/development/api/keywords .我宁愿不必修改我的控制器。在旧的 Web API 版本中,您可以在不同的路径中安装 OWIN 应用程序,所以我希望做类似的事情。
看看这个:
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 和内容根。
您可以查看原大文章here
首先创建一个继承自IApplicationModelConvention
接口的class
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);
}
}
}
}
}
然后创建一个 class 只是为了更容易和更清洁的使用。
public static class MvcOptionsExtensions
{
public static void UseEnvironmentPrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
{
opts.Conventions.Insert(0, new EnvironmentRouteConvention(routeAttribute));
}
}
现在开始使用它,首先很常见,将您的环境保存在启动 class
的 属性 中private IHostingEnvironment _env;
public Startup(IHostingEnvironment env)
{
_env = env;
}
然后你需要做的就是调用你的静态扩展 class
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.UseEnvironmentPrefix(new RouteAttribute(_env.EnvironmentName));
});
}
但是还有最后一件事需要关心。无论您有什么客户端使用您的 API,您肯定不想更改您发送的所有 URL HTTP 请求。所以诀窍是创建一个中间件,它将修改您请求的 Path
以包含您的环境名称。 (
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
class 变成了
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.
有一个名为 UsePathBase 的新方法可以轻松完成此操作。 https://github.com/aspnet/HttpAbstractions/blob/bfa183747f6fb528087554c3d6ec58ef05f1c10a/src/Microsoft.AspNetCore.Http.Abstractions/Extensions/UsePathBaseExtensions.cs