web-dev-qa-db-ja.com

ASP.Net Core 2.0:要求なしでUrlHelperを作成

私は、バックグラウンドワーカーがコールバックURLを作成するためのUrlHelperの作成に取り組んでいます。つまり、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<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
}
25
Stylpe

ASP.NET Core 2.2は本日リリース で、この問題を解決するように聞こえる LinkGenerator クラスを追加しました( tests 有望に見える)。私はそれを試してみたいと思っていますが、現時点でこれが必要なプロジェクトに積極的に取り組んでいないので、少し待たなければなりません。しかし、私はこれを新しい答えとしてマークするのに十分楽観的です。

3
Stylpe

ソースを閲覧すると、それほどハッキングされたソリューションはないようです。

UseMvc()メソッドでは、構築されるIRouterオブジェクトは RouterMiddlewareに渡される であり、これは プライベートフィールドに格納する であり、リクエストにのみ公開します。したがって、リフレクションが唯一の他のオプションとなり、これは明らかに実行されません。

ただし、IUrlHelper.Content()を使用して静的パスのみを生成する必要がある場合、 デフォルトの実装では使用されない であるため、ルーターは不要です。この場合、次のようにヘルパーを作成できます。

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