2017-09-07 12 views
14

バックグラウンドワーカーのコールバックURLを作成するためのUrlHelperを作成しています。つまり、通常のリクエストの一部ではないため、DI経由でリクエストできます。ASP.Net Core 2.0:リクエストなしでUrlHelperを作成する

私はちょうど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<Capture>()); 
    } 

    // Step 2: Swipe the route data in application startup 
    public static IApplicationBuilder UseMvcAndSniffRoutes(this IApplicationBuilder app) 
    { 
     var capture = app.ApplicationServices.GetRequiredService<Capture>(); 
     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<Capture>(); 
     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<Startup>() 
      .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<string> Get() 
    { 
     return new string[] { "value1", "value2" }; 
    } 

    // etc 
} 
+0

をこれはひどいアイデアかもしれませんが、あなたがバックグラウンドスレッドからそれを引き続き使用することができますので、あなただけの*リクエストの間に作成された*のUrlHelperを保存することはできませんか?だから、最初のリクエストが行われた後*あなたはそのスレッドを開始しますか? – poke

+0

これをチェックする機会がありましたか? https://stackoverflow.com/questions/37322076/injection-of-iurlhelper-in-asp-net-core-1-0-rc2 –

+0

@poke、それはおそらく動作するだろうが、明らかな欠点があるので、それを最後の手段として使用してください。 – Stylpe

答えて

1

ソースを参照すると、それほどハッキリしないようです。

UseMvc()メソッドで構築されるIRouterオブジェクトはpassed to the RouterMiddlewareであり、stores it in a private fieldであり、要求にのみ公開されます。だから反射はあなたの唯一の他の選択肢になるでしょう。

ただし、IUrlHelper.Content()を使用して静的パスのみを生成する必要がある場合は、ルータをdefault implementation won't use itとして指定する必要はありません。この場合、あなたはこのようなヘルパーを作成することができます

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

これは私が得たのと同じ結論ですが、私の質問では回避策につながります。 Content()についての素晴らしい点がありますが、名前付きコントローラアクションにリンクしたいと考えています。これを裏付けてくれてありがとう:)私の次のステップはおそらくこれを簡単にするためにGithubの問題を策定しようとすることでしょう。 – Stylpe

関連する問題