Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Microsoft.AspNet.Http.HttpContext instance in Class Constructor using DI

I am building a throwaway application in MVC 6 and experimenting with different architectures for dependencies.

The problem I am facing is how to create a custom 'MyAppContext' object specific to the Application. This would require some information from the HttpContext and some information from the database, and will be a request-scoped repository for application specific attributes. I want to pass the instance of the HttpContext into the constructor of the 'MyAppContext'.

I have successfully created a 'DataService' object with an IDataService interface using DI and this works Ok. The difference with the 'MyAppContext' class is that it has two parameters in the constructor - the 'DataService' and the Microsoft.AspNet.Http.HttpContext. Here is the MyAppContext class:

public class MyAppContext : IMyAppContext
{
    public MyAppContext(IDataService dataService, HttpContext httpContext)
    {
       //do stuff here with the httpContext
    }
}

In the startup code, I register the DataService instance and the MyAppContext instance:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        //adds a singleton instance of the DataService using DI
        services.AddSingleton<IDataService, DataService>();
        services.AddScoped<IMyAppContext, MyAppContext>();    

    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseErrorPage();
        app.UseRequestServices();
        app.UseMvc(routes => /* routes stuff */);
    }

I am expecting the HttpContext parameter in the constructor to get resolved by DI. When running the code, this is the exception I get returned:

InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNet.Http.HttpContext' while attempting to activate 'MyAppContext'

I figure this is because there is no specific instance of HttpContext that this error is occurring, but I don't know how to register the HttpContext instance in DI. I added the line 'app.UseRequestServices();' but this hasn't made any difference. I also tried a variant of:

services.AddScoped<HttpContext, HttpContext>();

But this fails because the second HttpContext is supposed to be an instance - I know it's not correct but haven't been able to work out what is.

So, in summary - how can I pass in the HttpContext object into the constructor of MyAppContext?

like image 674
Bruce Chapman Avatar asked May 05 '15 14:05

Bruce Chapman


People also ask

How do I get HttpContext in .NET Core?

ASP.NET Core apps access HttpContext through the IHttpContextAccessor interface and its default implementation HttpContextAccessor. It's only necessary to use IHttpContextAccessor when you need access to the HttpContext inside a service.

How do I find HttpContext current?

HTTP context accessor. Finally, you can use the IHttpContextAccessor helper service to get the HTTP context in any class that is managed by the ASP.NET Core dependency injection system. This is useful when you have a common service that is used by your controllers.

How is HttpContext created?

When an HTTP request arrives at the server, the server processes the request and builds an HttpContext object. This object represents the request which your application code can use to create the response.


2 Answers

Inject IHttpContextAccessor in the constructor

like image 184
Victor Hurdugaci Avatar answered Oct 06 '22 07:10

Victor Hurdugaci


By injecting an HttpContext into your component you are violating the SOLID principles. To be more specifically, you are violating:

  • The Dependency Inversion Principle (DIP) because you depend on a framework type (the HttpContext).
  • The Interface Segregation Principle (ISP) because the HttpContext has many methods, while the consumer never uses them all.

Both violations make it much harder to test your code. Although you can instead inject the IHttpContextAccessor as @victor suggests, this is still a violation of both the DIP and ISP, because this is an abstraction that is provided by the framework and you still depend on HttpContext. According to the DIP it is the client who should define the abstraction. This causes your code to be needlessly coupled to the framework.

Instead you should strive to specify narrow role interfaces; interfaces that do one specific thing for you that is specific to the needs of your application. Injecting a big dictionary with string values (as what HttpContext is, is never very specific). From your question it's unclear what kind of data you need from our MyAppContext, but I expect something like information of the currently logged in user. For this you can define a specific IUserContext abstraction, for instance:

public interface IUserContext {
    IPrincipal CurrentUser { get; }
}

An adapter that connects the application to the ASP.NET framework can be easily created for this abstraction:

sealed class AspNetUserContextAdapter : IUserContext  {
    private readonly IHttpContextAccessor accessor;
    public AspNetUserContextAdapter(IHttpContextAccessor accessor) {
        this.accessor = accessor;
    }
    public IPrincipal CurrentUser => accessor.HttpContext.User;
}

This adapter does depend on IHttpContextAccessor, but this is okay, since the adapter is an infrastructural component located in the Composition Root. There are serveral ways to register this class, for instance:

services.AddSingleton<IUserContext, AspNetUserContext>();
like image 37
Steven Avatar answered Oct 06 '22 09:10

Steven