Home > database >  Inject the HttpContext into a class and call the class outside the controller in .net core
Inject the HttpContext into a class and call the class outside the controller in .net core

Time:10-08

I need to save some info like Language and Timezone for each user, so I save them in cookies and access them through the whole website. Before was easier to access the httpContext outside the controller but in .Net Core, I see the need to use injection.

I have read a lot of articles and the process is to:

  1. Create an Interface for the class
  2. Create the actual class that will access the HttpContext
  3. At the Startup.cs set the injection and register the dependency
  4. Call the class from the Controller's constructor

See details here at Microsoft: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-5.0

Now, the problem is, this only moves up the problem to upper levels, you can only instantiate your class from the controller, but if you need to call the class from another place, like inside another class, then you need to call the constructor like

The class with injection:

public class MyClass : IMyClass
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public MyClass(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    ...
}

The new class using the injected one above:

public class MyClass2
{
   public MyClass2() {
      MyClass myclass = new MyClass(httpContextAccessor)
   }
}

But at this point you don't have the httpContextAccessor object because is not being called from the controller and passing the httpContextAccessor to this new class is just... not feasible.

So, how to do this correctly? how to inject the HttpContext into a class and how to call that class without depending on the controller?

CodePudding user response:

But at this point you don't have the httpContextAccessor

I'm not quite get the point here. IHttpContextAccessor was registered as singleton service lifetime, which mean we can get it from anywhere in our application.

Let's say this case, MyClass2 need an object of MyClass, so, where can do it like

public class MyClass2
{
   public MyClass2(IHttpContextAccessor httpContextAccessor) 
   {
      MyClass myclass = new MyClass(httpContextAccessor)
   }
}

// Some service make use of MyClass2, MyClass2 not register on DI
public class DemonstrateService
{
   private readonly MyClass2 myClass2;

   public DemonstrateService(IHttpContextAccessor httpContextAccessor)
   {
      myClass2 = new MyClass2(httpContextAccessor);
   }
}

// Some service make use of MyClass2, MyClass2 got registered on DI
public class DemonstrateService
{
   private readonly MyClass2 _myClass2;

   public DemonstrateService(MyClass2 myClass2)
   {
      _myClass2 = myClass2;
   }
}

// Register in DI
services.AddScoped<DemonstrateService>();
services.AddScoped<MyClass2>();
...

// Using it anywhere, it's not restricted to Controller

As a side note, we can easily see this kind of nested dependencies was not so well-organize. But we implement the code our way. There was plenty clean code .Net core repository on github out there, which we could take some fundamental of.

CodePudding user response:

Seems that by adding a constructor in the Model class to inject the HttpContext it is not possible, since LINQ also calls the constructor when executing queries. I found out that I can just use a STATIC class outside the Models to keep all settings I need, like "UserTimezone". So, instead of trying to read the Cookie from the static class, I set a static string property where I save the value, and seems that value is kept during the whole web page request cycle.

Basically, I did this, and works for me:

  1. Create an ActionFilter and call it on each controller
  2. Set the injection for this Filter in the Startup.cs
  3. The HttpContext is then injected into the Filter from the Controller
  4. In the Filter I add a function to read the values from the Cookie and save them to the static class (I.e. MyGlobalStatic.UserTimezone)
  5. Then I use the static class inside all my models that require these values (i.e. I need the UserTimeZone to convert DateTime fields from database Universal time to user's local time).
  • Related