11

I use TempData in some of my Views/Actions but I'd like to extract that into some class. The problem is if I try to create my class in Controller's constructor, the TempDate there is null. Better yet, I'd like to have my class to be injectable into Controller. So I need to get access to TempData when my class is created.

So how can this TempData be constructed in a separate class?

This is ASP.NET Core 2.0 web app.

poke
  • 369,085
  • 72
  • 557
  • 602
AlexB
  • 4,167
  • 4
  • 45
  • 117

1 Answers1

18

You can access temp data anywhere by simply injecting ITempDataDictionaryFactory where you need it. You can then call its GetTempData which returns an ITempDataDictionary which you can use to access (read or write) the temp data for the current HTTP context:

public class ExampleService
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;

    public ExampleService(IHttpContextAccessor httpContextAccessor, ITempDataDictionaryFactory tempDataDictionaryFactory)
    {
        _httpContextAccessor = httpContextAccessor;
        _tempDataDictionaryFactory = tempDataDictionaryFactory;
    }

    public void DoSomething()
    {
        var httpContext = _httpContextAccessor.HttpContext;
        var tempData = _tempDataDictionaryFactory.GetTempData(httpContext);

        // use tempData as usual
        tempData["Foo"] = "Bar";
    }
}

Btw. the reason why TempData is null in your controller’s constructor is because the controller context is only injected after the controller has already been created (using property injection). So when the controller’s constructor runs, there simply isn’t any information about the current request yet.

If you do inject your service though, and that service works like the ExampleService above, then it will work even from within the constructor, since it will simply request the necessary information from the DI container itself (the factory and the HTTP context).

poke
  • 369,085
  • 72
  • 557
  • 602
  • Or you could even do this by injecting only IHttpContextAccessor: ``` public SetMessageOnBrowse(IHttpContextAccessor contextAccessor) { if (contextAccessor == null) throw new ArgumentNullException(nameof(contextAccessor)); var httpContext = contextAccessor.HttpContext; var factory = httpContext.RequestServices.GetService( typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory; _tempData = factory.GetTempData(httpContext); } ``` – AlexB Sep 11 '17 at 23:03
  • 1
    Retrieving services through `context.RequestServices.GetService()` is not dependency injection though but is the [service locator pattern](https://en.wikipedia.org/wiki/Service_locator_pattern). There is really no good reason to use this when you are getting services injected anyway. Please [avoid using service locator](https://stackoverflow.com/q/4985455/216074) at all costs in ASP.NET Core; there are really only a handful of situation when that’s the only solution (and usually it’s limited to very internal framework stuff). – poke Sep 11 '17 at 23:07
  • @poke For those who see the answer and wonder where the HttpContextAccessor comes from, you need to add it in the Startup.cs file in the ConfigureServices method: services.AddHttpContextAccessor();. Then you put it in your controller constructor to inject it into the controller or into your service in its constructor. As far as DI vs service locator patterns and "edge" cases. I find using completely stateless client and microservice is a good place to use this as it keeps up with TempData and out of the program logic. – Larry Aultman Oct 31 '20 at 21:28