Can I safely use the non-generic DbContextOptions in ASP.NET Core and EF Core?

asp.net-core asp.net-identity c# entity-framework-core

Question

In ASP.NET Core, an EF Core context is created by the builtin DI container. In the official documentation, a context is created with a generic DbContextOptions<TContext>:

public class MyContext : IdentityDbContext<User> {
  public MyContext(DbContextOptions<MyContext> options, ILogger<MyContext) logger) : base(options) { }
}

However, there are examples of the non-generic as well:

public class MyContext : IdentityDbContext<User> {
  public MyContext(DbContextOptions options, ILogger<MyContext) logger) : base(options) { }
}

The difference between them according to the source code is:

Type parameters: TContext: The type of the context these options apply to.

I'd like to use the non-generic type, because in my design I have an abstract context, and that doesn't play well with the DI container.

So, if I use the non-generic type, what does that really mean? That my context won't be properly configured?

1
2
1/7/2017 11:42:41 AM

Accepted Answer

I'd like to use the non-generic type, because in my design I have an abstract context, and that doesn't play well with the DI container.

That plays just fine with the DI container. It only looks at the most-derived type, the type it's trying to instantiate. The fact that there's a base class somewhere in between is not relevant.

Note that while you cannot use DbContextOptions<AbstractDbContext>, you do not need to. You can either make the base class take DbContextOptions, or make the base class generic and take DbContextOptions<ConcreteDbContext>:

abstract class AbstractDbContext : DbContext
{
    protected AbstractDbContext(DbContextOptions options) : base(options)
    {
    }
}

class ConcreteDbContext : AbstractDbContext
{
    public ConcreteDbContext(DbContextOptions<ConcreteDbContext> options) : base(options)
    {
    }
}

or

abstract class AbstractDbContext<TContext> : DbContext
    where TContext : AbstractDbContext<TContext>
{
    protected AbstractDbContext(DbContextOptions<TContext> options) : base(options)
    {
    }
}

class ConcreteDbContext : AbstractDbContext<ConcreteDbContext>
{
    public ConcreteDbContext(DbContextOptions<ConcreteDbContext> options) : base(options)
    {
    }
}

So, if I use the non-generic type, what does that really mean? That my context won't be properly configured?

A constructor taking a non-generic DbContextOptions usually works as well. Normally, you'd be right, the service provider wouldn't be able to figure this out. However, EF Core specifically informs the service container, when you call serviceCollection.AddDbContext<ConcreteDbContext>(...), that when a DbContextOptions instance is requested, a DbContextOptions<ConcreteDbContext> instance should be provided.

Note that this only works if you have a single context type. If you have multiple, the service provider doesn't have enough information to figure out which one you need.

4
1/6/2017 10:07:20 PM

Popular Answer

Here is the signature of the base IdentityDbContext class (generic and non generic) constructor:

public IdentityDbContext(DbContextOptions options)

Which to me means it can work with non generic DbContextOptions without a problem.

In fact the only difference between the generic and non generic versions of the DbContextOptions class is that the generic version implements the abstract non generic version.

Still, passing DbContextOptions<YourDbContext> to YourDbContext constructor is safer because it ensures the caller will pass the correct implementation of the abstract class (basically the ContextType property).



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