efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Improve CheckContextConstructors method in EntityFrameworkServiceCollectionExtensions

Open michaeltg17 opened this issue 10 months ago • 1 comments

When adding a DbContext using AddDbContext with some options, you want those options to be applied in that context. There is a checker method in the AddDbContext extension method that checks that the DbContext does not only have one parameterless constructor. However, it can have a constructor with some other arguments and still not have the DbContextOptions (or DbContextOptions<T>) parameter. This causes the options to be ignored by the context without noticing and the expected exception is not thrown.

    private static void CheckContextConstructors<TContext>()
        where TContext : DbContext
    {
        var declaredConstructors = typeof(TContext).GetTypeInfo().DeclaredConstructors.ToList();
        if (declaredConstructors.Count == 1
            && declaredConstructors[0].GetParameters().Length == 0)
        {
            throw new ArgumentException(CoreStrings.DbContextMissingConstructor(typeof(TContext).ShortDisplayName()));
        }
    }

Exception message:

'AddDbContext' was called with configuration, but the context type '{contextType}' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then '{contextType}' should declare a constructor that accepts a DbContextOptions<{contextType}> and must pass it to the base constructor for DbContext.

Improve the CheckContextConstructors method so it really checks that the DbContext has a DbContextOptions as a parameter.

michaeltg17 avatar Apr 18 '24 18:04 michaeltg17

@michaeltg17 This is by-design. EF Core cannot know whether or not the parameter or parameters that are passed to the constructor will resolve a DbContextOptions or not. Just because the parameter itself is not a DbContextOptions does not mean it does not depend itself on something else with a DbContextOptions.

So the idea here is to warn for the common case where the user has forgotten, or does not know, that a constructor containing the options is needed. It is not intended to cover more advanced cases, and I don't think it is possible without knowing the D.I. system or its logic, to tell from the signature that a DbContextOptions is definitely not being injected.

ajcvickers avatar Apr 21 '24 22:04 ajcvickers