Reputation: 414
I'm using Asp.Net Core RC1, and I've to access to an HttpContext
instance from instances generated by a model generator (from interceptors of Castle.Core
, for be exact). Model generator has to be a single instance through the entire application.
I need to create an instance of ModelGenerator
into startup file, because it is used into static lambdas needed to configure some serializers. Serializers are statically registered, so I have to write into startup:
var modelGenerator = new ModelGenerator();
Serializers.Configure(modelGenerator); // static use of model generator instance
I also add modelGenerator as singleton instance for other uses with DI.
services.AddInstance<IModelGenerator>(modelGenerator);
What I would have done with DI is to take a IHttpContextAccessor
interface from ModelGenerator's constructor, but into this context I can't because I don't have an instance on startup. I need something like a ServiceLocator to call from ModelGenerator, or some other patter that I ignore.
How can reach an updated HttpContext instance, with information of current request, from interceptors generated by ModelGenerator?
Upvotes: 2
Views: 4053
Reputation: 56849
It appears that there is no way to get an instance of HttpContext
in application startup. This makes sense - in previous versions of MVC this wasn't possible in IIS integrated mode or OWIN.
So what you have are 2 issues:
IHttpContextAccessor
into your serializer?HttpContext
is not accessed until it is available?The first issue is pretty straightforward. You just need to use constructor injection on IHttpContextAccessor
.
public interface ISerializer
{
void Test();
}
public class ModelGenerator : ISerializer
{
private readonly IHttpContextAccessor httpContextAccessor;
public ModelGenerator(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Test()
{
var context = this.httpContextAccessor.HttpContext;
// Use the context
}
}
And to register...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Other code...
// Add the model generator
services.AddTransient<ISerializer, ModelGenerator>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var serializers = app.ApplicationServices.GetServices<ISerializer>();
foreach (var serializer in serializers)
{
Serializers.Configure(serializer);
}
// Other code...
}
The second issue can be resolved by moving whatever initialization calls that you require HttpContext
in into a global filter.
public class SerializerFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext context)
{
// TODO: Put some kind of if condition (possibly a
// global static variable) here to ensure this
// only runs when needed.
Serializers.Test();
}
}
And to register the filter globally:
public void ConfigureServices(IServiceCollection services)
{
// Other code...
// Add the global filter for the serializer
services.AddMvc(options =>
{
options.Filters.Add(new SerializerFilter());
});
// Other code...
}
If your Serializers.Configure()
method requires HttpContext
to work, then you will need to move that call into the global filter.
Upvotes: 3