Accessing DBContext without injecting it all the way down

.net-core c# dependency-injection entity-framework-core

Question

I'm having some trouble with the whole dependency injection with/through reflection.

The scenario is as following;

  • User authenticates via AzureAD through our identity server
  • If user is not in local database, save the user together with some other information

I keep restructuring my logic and I still can't make the puzzle work.

Currently this is my chain:

OWIN Startup:

I'm specifying a method to run after the OnTokenValidated event has triggered: ProfileEvents.ValidatedToken

services.AddAuthentication()
                .AddOpenIdConnect("oidc", o =>
                {
                    o.ClientId = $"{configuration["Globals:AzureApplication:AppId"]}";
                    o.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                    o.Authority = $"https://login.microsoftonline.com/{configuration["Globals:AzureApplication:TenantId"]}";
                    o.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
                    o.Events = new OpenIdConnectEvents()
                    {
                        OnTokenValidated = ProfileEvents.ValidatedToken
                    };
                });

DatabaseContext is added like this:

    public void ConfigureServices(IServiceCollection services)
    {
    .... // other stuff

    services.Configure<Config.ConnectionStrings>(configuration.GetSection("ConnectionStrings"));

    services.AddDbContext<ModelContext>(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
    }

The my ValidatedToken method looks like this:

 internal static class ProfileEvents
    {
        internal static Task ValidatedToken(TokenValidatedContext context)
        {
            var dbContext = new ProfileDAL();
            dbContext.SaveToDb(context.Principal);
            return Task.FromResult(0);
        }
    }

And finally my ProfileDAL looks like this:

public class ProfileDAL
    {
       internal async Task SaveToDb(ClaimsPrincipal principal)
        {
            var nameClaim = principal.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn");
            var emailClaim = principal.FindFirstValue("email");
            // TODO: Save user..
        }
     }

Now which way I turn I either have to use and pass IOptions through the chain so that ModelContext can override "OnConfiguring" to actually get the connection string or I have to pass the context.

Is there really no way to access either the connection string outside of the DI?

For me I feel like something like this would solve all of my current issues:

  public partial class ModelContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer( ** Magic way to access connection string in appsettings ** );
        }
     }
1
4
10/4/2017 2:20:14 PM

Popular Answer

When you speak of 'passing down the chain`, that shouldn't be necessary. If we're using a dependency injection container then we don't have to pass a dependency to one class, have that pass a dependency to another class, and so on. In fact, that's part of what we're avoiding by using the container.

We don't have to do that because each class is receiving its dependencies as abstractions (usually interfaces.) That means that one class can't pass something to its dependencies because it doesn't even know what that dependency needs.

Rather than passing something along from one class to another as if in a chain, each individual class is resolved with just the dependency it needs. None of the classes in the chain are responsible for supplying constructor arguments to their dependencies.

That becomes more difficult when we use static classes like ProfileEvents. You can't inject ProfileDAL into it because it's static. Then, because ProfileDAL isn't getting "newed" - new ProfileDAL() - there's no way to inject its dependencies.

That in turn means that you won't use constructor injection with ProfileDAL, and you'll look for other ways to create and pass in its dependencies. But use of the DI container should prevent that. All the way down the dependency graph everything is following the same pattern, where each class gets its dependencies in its constructor without knowing or caring what dependencies those classes have.

0
10/5/2017 6:22:36 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow