-2

I'm building a Web API with ASP.NET Core 2.1. I have controllers that user can access through HTTP requests. Controllers then call service classes. I'm trying to inject my DbContext to my custom service class but whenever I do that I get response 500 from server. In my startup class i have

services.AddDbContext<CatalogueContext>(options => options.UseSqlServer(_config.GetConnectionString("DefaultConnection")));

If I put like this in controller class everything works

private readonly ITrackServices _service;
private readonly CatalogueContext _dbContext;

public TrackController(ITrackServices service, CatalogueContext dbContext)
{
  _service = service;
  _dbContext = dbContext;
}

But I don't want to inject dbContext to controller. If I delete that injection from controller and try same thing in my service class like this

private readonly CatalogueContext _dbContext;

public TrackService(CatalogueContext dbContext)
{
  _dbContext = dbContext;
}

it doesn't work. So when ever I try to access endpoint that uses TrackService I get 500 from server.

TrackService is registered as a singleton:

services.AddSingleton<ITrackServices, TrackService>();

I don't know what I'm doing wrong. Should I implement some interface on TrackService to enable dependency injection or what?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
kivikall
  • 786
  • 2
  • 13
  • 29
  • 3
    Have you registered the service? e.g. `services.AddScoped()` – juunas May 22 '19 at 13:19
  • *Why* don't you want to inject the context? If you register the DbContext injection will work in both the controller and service. – Panagiotis Kanavos May 22 '19 at 13:19
  • @juunas: Thanks. I was using services.AddSingleton(); I changed to what you said and it seems to work now. – kivikall May 22 '19 at 13:22
  • What error are you getting? Post the *full* exception text returned by `Exception.ToString()`. That includes any inner exceptions and the call stack that led to the exception. This will show what the actual problem is. An unregistered depencency? Or an ObjectDisposedException that's probably caused because `ITrackServices` is a singleton when the DbContext is scoped? – Panagiotis Kanavos May 22 '19 at 13:23
  • Short answer: don't ever use DbContext from a singleton. – DavidG May 22 '19 at 13:27
  • @DavidG not directly at least – Panagiotis Kanavos May 22 '19 at 13:28
  • @PanagiotisKanavos How would you do it indirectly? – DavidG May 22 '19 at 13:28
  • @DavidG it's documented, in the *wrong* place as always : [Background tasks with hosted services in ASP.NET Core : Consuming a scoped service in a background task](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2#consuming-a-scoped-service-in-a-background-task). Finding doc links is becoming a real pain. – Panagiotis Kanavos May 22 '19 at 13:31
  • @DavidG that's a `discretion required` technique though. Why use a *singleton* scope for a service if the cost isn't justified? – Panagiotis Kanavos May 22 '19 at 13:34
  • @PanagiotisKanavos Oh, creating your own scope, gotcha, just didn't know what you meant by 'indirectly'. Yeah, I've had to do this in a couple of places recently, just not because it was from a singleton. – DavidG May 22 '19 at 13:35

1 Answers1

1

You need to register the service too:

services.AddScoped<ITrackService, TrackService>();

Whether you use transient, scoped, or singleton depends on what lifetime the dependencies of the service have. It shouldn't depend on services with a smaller lifetime.

juunas
  • 54,244
  • 13
  • 113
  • 149
  • The OP mentions in the comments that the service is already registered as a singleton – Panagiotis Kanavos May 22 '19 at 13:25
  • And they also said they changed it what I said and it works now. Could be a service lifetime validation error. You shouldn't use scoped services from singletons. – juunas May 22 '19 at 13:26
  • there's no problem with using scoped services from singletons. The correct way to do so is described in the docs and the duplicate questions – Panagiotis Kanavos May 22 '19 at 13:27
  • Okey thanks. I need to read more about this. Meanwhile I'll mark this as an answer because it fixed my issue anyhow :) – kivikall May 22 '19 at 13:28
  • Using a scoped service from a singleton through constructor injection means you are using a disposed service after the request is done and the scope is disposed. Of course you can create your own scopes or get it via the service collection within a method. – juunas May 22 '19 at 13:35