Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing in options to IDbContextFactory.CreateDbContext #34156

Open
petermorlion opened this issue Jul 4, 2024 · 1 comment
Open

Allow passing in options to IDbContextFactory.CreateDbContext #34156

petermorlion opened this issue Jul 4, 2024 · 1 comment

Comments

@petermorlion
Copy link

We want to pass the connection to our DbContext using the IDbContextFactory.CreateDbContext method. You can't pass any DbContextOptions to the CreateDbContext method.

The longer story is that we're creating dotnet templates, in a hexagonal architecture (ports & adapters). So we don't know the exact type of the DbContext and we want to have an Entity Framework adapter and an NServiceBus adapter. We want the NServiceBus endpoint configuration in the NServiceBus adapter project, not in the Program.cs (although Program.cs will call the adapter and tell it to set itself up).

As stated in their docs, "the business data has to reuse the same connection context as NServiceBus persistence."

We believe this could work with (something like) the following code:

// This code is inside our NServiceBus adapter project
endpointConfiguration.RegisterComponents(c =>
{
    c.AddScoped(b => {
        var session = b.GetRequiredService<ISqlStorageSession>();
        
        // TDbContext would be provided by Program.cs, because our template doesn't know the concrete type:
        var contextFactory = b.GetRequiredService<IDbContextFactory<TDbContext>>(); 
        
        // This is the code recommended by NServiceBus:
        // var context = new ReceiverDataContext(new DbContextOptionsBuilder<ReceiverDataContext>()
        //     .UseSqlServer(session.Connection)
        //     .Options);

        // This is the code we would like to be able to use:
        var options = new OptionsBuilder<TDbContext>().UseSqlService(session.Connection).Options;
        var context = contextFactory.CreateDbContext(b, options);

        //Use the same underlying ADO.NET transaction
        context.Database.UseTransaction(session.Transaction);

        //Ensure context is flushed before the transaction is committed
        session.OnSaveChanges((s, token) => context.SaveChangesAsync(token));

        return context;
    });
});

Maybe I'm underestimating the problem or not seeing the reasons for not doing so, but I believe all we would need is to add the following code to DbContextFactory (and the interface as well of course):

public virtual TContext CreateDbContext(IServiceProvider serviceProvider, DbContextOptions<TContext> options)
    => _factory(serviceProvider, options);

I'm not sure if the serviceProvider is necessary or if it should use the one in the private field.

I can provide a PR if you're open to this change.

@ajcvickers
Copy link
Member

@petermorlion Is there a reason you can't implement your own factory that has the behavior you want? (I'm not saying we can't add things to IDbContextFactory, but I want clarification if you think this is necessary. Generally, EF is agnostic to how types are registered in the application's service provider.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants