I needed a custom file provider, and to access a request's HttpContext
, I found a solution using IHttpContextAccessor
:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/res", StringComparison.OrdinalIgnoreCase), appBuilder =>
{
appBuilder.UseStaticFiles(new StaticFileOptions
{
FileProvider = new HostResFileProvider(appBuilder.ApplicationServices.GetRequiredService<IHttpContextAccessor>(), builder.Environment),
RequestPath = "/res"
});
});
While that worked just fine, looking at that code snippet I just started to wonder, instead of setting up IHttpContextAccessor
wouldn't it be possible to pass the ctx
variable instead, something like this?
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/res", StringComparison.OrdinalIgnoreCase), appBuilder =>
{
appBuilder.UseStaticFiles(new StaticFileOptions
{
FileProvider = new HostResFileProvider(ctx, builder.Environment),
RequestPath = "/res"
});
});
Now, this won't work, though is there a way making it work?
HttpContext
is scoped to HTTP request, that is why you must always use IHttpCOntextAccessor
in services, in order to reliably access HttpContext
related to current HTTP request being handled.
What you wanted to do is just passing single fixed context reference, that would be used for all static files requests. Which is simply not valid (and why, please read below explanations).
If you would put a breakpoint at your condition and inside the second lambda with appBuilder
, you would see that this lambda is called once on the application build. At this time there's not even a HttpContext
you could use. This is registered as part of a pipeline.
So, when the pipeline is built, it only checks the condition on each HTTP request and conditionally invokes this part of pipeline.
However the pipeline won't be rebuilt every HTTP request.
If you would look at the source code of UseWhen
, last argument is Action<IApplicationBuilder> configuration
and is used in one place (the other one is just null
check):
var branchBuilder = app.New();
configuration(branchBuilder);
which then is used in middleware definition with app.Use
.
So, the delegate is used at application startup. Not during HTTP request. Without HTTP request it is impossible to get HTTP context, thus your definition would be invalid if you'd try to bind HTTP context on app startup (even if you would figure out how).