ASP.Net Core 2.0:无需请求即可创建UrlHelper

我正在为后台工作者创建一个UrlHelper来创建回调url,这意味着它不是正常请求的一部分,我可以通过DI请求它。

在ASP.Net 5中,我可以创建一个HttpRequest,并为它提供与构建我的应用程序相同的HttpConfiguration,但在ASP.Net Core 2.0中,UrlHelper依赖于完整的ActionContext,这有点难以制作。

我有一个工作原型,但它正在使用一个讨厌的黑客来从应用程序启动过程中走私路由数据。 有一个更好的方法吗?

public class Capture { public IRouter Router { get; set; } } public static class Ext { // Step 1: Inject smuggler when building web host public static IWebHostBuilder SniffRouteData(this IWebHostBuilder builder) { return builder.ConfigureServices(svc => svc.AddSingleton()); } // Step 2: Swipe the route data in application startup public static IApplicationBuilder UseMvcAndSniffRoutes(this IApplicationBuilder app) { var capture = app.ApplicationServices.GetRequiredService(); IRouteBuilder capturedRoutes = null; app.UseMvc(routeBuilder => capturedRoutes = routeBuilder); capture.Router = capturedRoutes?.Build(); return app; } // Step 3: Build the UrlHelper using the captured routes and webhost public static IUrlHelper GetStaticUrlHelper(this IWebHost host, string baseUri) => GetStaticUrlHelper(host, new Uri(baseUri)); public static IUrlHelper GetStaticUrlHelper(this IWebHost host, Uri baseUri) { HttpContext httpContext = new DefaultHttpContext() { RequestServices = host.Services, Request = { Scheme = baseUri.Scheme, Host = HostString.FromUriComponent(baseUri), PathBase = PathString.FromUriComponent(baseUri), }, }; var captured = host.Services.GetRequiredService(); var actionContext = new ActionContext { HttpContext = httpContext, RouteData = new RouteData { Routers = { captured.Router }}, ActionDescriptor = new ActionDescriptor(), }; return new UrlHelper(actionContext); } } // Based on dotnet new webapi public class Program { public static void Main(string[] args) { BuildWebHost(args);//.Run(); } public static IWebHost BuildWebHost(string[] args) { var captured = new Capture(); var webhost = WebHost.CreateDefaultBuilder(args) .SniffRouteData() .UseStartup() .Build(); var urlHelper = webhost.GetStaticUrlHelper("https://my.internal.service:48923/somepath"); Console.WriteLine("YO! " + urlHelper.Link(nameof(ValuesController), null)); return webhost; } } public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, Capture capture) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvcAndSniffRoutes(); } } [Route("api/[controller]", Name = nameof(ValuesController))] public class ValuesController : Controller { // GET api/values [HttpGet] public IEnumerable Get() { return new string[] { "value1", "value2" }; } // etc } 

浏览源代码似乎没有那么简单的解决方案。

在UseMvc()方法中,正在构建的IRouter对象被传递给RouterMiddleware ,后者将其存储在私有字段中 ,并仅将其公开给请求。 所以reflection将是你唯一的另一种选择,显然是在运行之外。

但是,如果您需要使用IUrlHelper.Content()仅生成静态路径,则不需要路由器,因为默认实现不会使用它 。 在这种情况下,您可以像这样创建帮助器:

 var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var urlHelper = new UrlHelper(actionContext);