Search code examples
c#asp.net-coreentity-framework-coreasp.net-core-mvc

Inject ApplicationDBContext to non-controller file


I'm trying to inject the ApplicationDBContext into a service or a non-controller file and getting a stuck a bit with DI.

Program.cs extract:

builder.Services.AddRazorPages().AddRazorRuntimeCompilation();

builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseMySQL(
        builder.Configuration.GetConnectionString("DefaultConnection")
    ));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromSeconds(10);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

builder.Services.AddScoped<IAppSettingsService, AppSettingsService>();

var app = builder.Build();

Service / non-controller file:

using NVFlexo.Data;

namespace NVFlexo.Services;

public interface IAppSettingsService
{
    public string GetSetting(string key);
}

public class AppSettingsService: IAppSettingsService
{
    private readonly ApplicationDbContext _db;

    public AppSettingsService(ApplicationDbContext db)
    {
        _db = db;
    }
    
    public string GetSetting(string key)
    {
        var results = _db.AppSettings.Where(s => s.SettingKey == key).First();
        if (results == null)
        {
            return null;    
        }
        return results.Value;
    }
}

I'm trying to access a method of the AppSettingsService class as shown here from another file:

AppSettingsService appSettingsService = new AppSettingsService();
appSettingsService.GetSetting("GST");

I'm getting this error:

Constructor 'AppSettingsService' has 1 parameter(s) but is invoked with 0 argument(s)

Which makes sense. But is there anyway to have the db connection loaded automatically without injecting it?

I guess I'm coming from a PHP/Laravel background where db connection is handled automatically and seems like db context needs to be added explicitly in .NET Core?

Appreciate if someone can point me in the right direction please.

Thank you for your time.

-- Edit I'm trying to use this from a controller method as below.

public IActionResult GetItem(string? key)
{
   // AppSettingsService appSettingsService = new AppSettingsService();
      AppSettingsService appSettingsService = new AppSettingsService(_db);  //This works
    appSettingsService.GetSetting(key);

    return this.StatusCode(StatusCodes.Status200OK, "Retrieved");
}

Solution

  • You need to use dependency injection to obtain IAppSettingsService. You can't just use new to create a new one, because that doesn't use the container to obtain the dependencies - you have to pass them manually.

    Usually you'll inject it like this (into controllers, other services, etc.):

    public class MyController
    {
        private readonly IAppSettingsService _appSettingsService;
    
        public MyController(IAppSettingsService appSettingsService)
        {
            _appSettingsService = appSettingsService;
        }
    
        public IActionResult GetItem(string? key)
        {
            _appSettingsService.GetSetting(key);
            return this.StatusCode(StatusCodes.Status200OK, "Retrieved");
        }
    }
    

    In ASP.NET Core controllers, you can also use [FromServices] to inject services just into the controller action method:

    public IActionResult GetItem(string? key, [FromServices] IAppSettingsService appSettingsService)
    {
        appSettingsService.GetSetting(key);
        return this.StatusCode(StatusCodes.Status200OK, "Retrieved");
    } 
    

    Note that we're injecting IAppSettingsService here, and not AppSettingsService. This is because you've registered the service as IAppSettingsService, and the DI container doesn't know what AppSettingsService is.