Can I access a database during startup in ASP.NET Core?

24,111

Solution 1

Yes, you can access the database! Code that runs in the Configure method can access any services that are added in the ConfigureServices method, including things like database contexts.

For example, if you have a simple Entity Framework context:

using Microsoft.EntityFrameworkCore;
using SimpleTokenProvider.Test.Models;

namespace SimpleTokenProvider.Test
{
    public class SimpleContext : DbContext
    {
        public SimpleContext(DbContextOptions<SimpleContext> options)
            : base(options)
        {
        }

        public DbSet<User> Users { get; set; }
    }
}

And you add it in ConfigureServices:

services.AddDbContext<SimpleContext>(opt => opt.UseInMemoryDatabase());

Then, you can access it when you are setting up the middleware:

var context = app.ApplicationServices.GetService<SimpleContext>();

app.UseSimpleTokenProvider(new TokenProviderOptions
{
    Path = "/api/token",
    Audience = "ExampleAudience",
    Issuer = "ExampleIssuer",
    SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
    IdentityResolver = (username, password) => GetIdentity(context, username, password)
});

And rewrite the GetIdentity method a little:

private Task<ClaimsIdentity> GetIdentity(SimpleContext context, string username, string password)
{
    // Access the database using the context
    // Here you'd need to do things like hash the password
    // and do a lookup to see if the user + password hash exists
}

I'm the author of the original sample. Sorry it wasn't clear initially! I tried to write the IdentityResolver delegate in a way that makes it easy to provide your own functionality -- like integrating with your own database (as above), or hooking it up to ASP.NET Core Identity. Of course, you're free to throw away my code and do something better, too. :)

Solution 2

On .NET CORE 2.1, just pass the context as an argument to the Configure method:

public void Configure(IApplicationBuilder app, YourDbContext context, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
        //do whatever you want with the context here...
}

Adding services to the service container makes them available within the app and in the Configure method. The services are resolved via dependency injection or from ApplicationServices.

Solution 3

The accepted answer does not work for scoped services (scoped services are created per request, if you are using Entity Framework and adding the context with AddDbContext then this is the case).

You can use scoped services in startup as follows (source):

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    using (var serviceScope = app.ApplicationServices.CreateScope())
    {
        var services = serviceScope.ServiceProvider;
        var myDbContext = services.GetService<MyDbContext>();
    }
}

or pass it in the argument of the Configure method as shown in the answer of juanora

Share:
24,111

Related videos on Youtube

Top Rat
Author by

Top Rat

Updated on September 18, 2020

Comments

  • Top Rat
    Top Rat over 3 years

    I have recently been working on a .NET Core web API. I have just attempted authentication using JWT, by following the guide on https://stormpath.com/blog/token-authentication-asp-net-core.

    All was going well until I had to replace the hard-coded username and passwords in the GetIdentity method with a DB query and realized I do not know how to access the DB from within this file!

    The method I am referring to is shown in the link below on line 70. https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs

    My questions are as follows.

    1. Can I access the database here? If so how?
    2. Should this be where the GetIdentity method is, or is there a better way?
  • xcud
    xcud over 7 years
    If you're just adding JWT to aspnet identity, you may pass the signinmanager instead of the dbcontext: var userManager = app.ApplicationServices .GetService(typeof(UserManager<ApplicationUser>))
  • Mohamed Badr
    Mohamed Badr over 6 years
    @xcud That's exactly what I'm trying to do but get an error " Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager`", what am I missing here?
  • CopyJosh
    CopyJosh about 6 years
    Should update the sample or add this concept in comments, this was driving me crazy for hours! Thank you for your answer!
  • Florian Moser
    Florian Moser over 5 years
    This does not work for scoped services. If you've used AddDbContext with Entity Framework then your DB service is scoped. Check out my answer for a solution.
  • Marvin
    Marvin over 5 years
    I think this is the recommended way to consume scoped services in singletons and services, reference sample code: consuming-a-scoped-service-in-a-background-task
  • Legends
    Legends over 4 years
    This is the actual and simplest answer, provided you have registered your DbContext with DI upfront or implicitly with AddDbContext. Working at least from .net core 2.1as stated in this answer (Didn't check it, works with 3.0 prev)
  • jegtugado
    jegtugado over 4 years
    May I ask if you registered a service as scoped, can you still access it within the Configure method or only transients and singletons work here?
  • juanora
    juanora over 4 years
    @jegtugado is supposed to work. Btw AddDbContext adds as scoped
  • Tom McDonough
    Tom McDonough over 4 years
    @xcud you need to add Identity to the services, for example services.AddIdentity<User, Role>() will add User and Role so you are able to use throughout your application