Jeremy
Jeremy

Reputation: 105

Instantiate multiple DbContext manually without dependency injection

I want to create an ASP.Net Core web service which will select rows from one SQL Server database and insert them into X SQL server database(s). All databases have the same structure (same model).

I don't want to inject DbContext because I don't know how many context I will have to use and it will be difficult to maintain.

Is it possible to manually create a DbContext in a controller or a manager like :

MyContextClass dbContext = new MyContextClass("myConnectionString");

Thank you

Upvotes: 4

Views: 5680

Answers (1)

wertzui
wertzui

Reputation: 5740

Yes, it is possible to just create a new DbContext. However when using DI, you should write and inject something like a DbContextFactory class that you can use to create a new context and that itself gets the DbContextOptions from your configuration.

public class ContextFactory<TContext>
    where TContext : DbContext
{
    private readonly Func<TContext> _createContext;

    public ContextFactory(Func<TContext> createContext)
    {
        _createContext = createContext ?? throw new ArgumentNullException(nameof(createContext));
    }

    TContext CreateForRead()
    {
        var context = Create();

        context.ChangeTracker.AutoDetectChangesEnabled = false;
        context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

        return context;
    }

    TContext CreateForWrite() => Create();

    private TContext Create()
    {
        var context = _createContext();
        if (context == null)
            throw new NullReferenceException($"{nameof(_createContext)} must not return null.");

        return context;
    }
}

For easier use, create an extension class:

public static class ServiceCollectionDataExtensions
{
    public static void AddDatabase<TDbContext>(this IServiceCollection services, string connectionString)
        where TDbContext : DbContext
    {
        if (services == null)
            throw new ArgumentNullException(nameof(services));

        if (string.IsNullOrEmpty(connectionString))
            throw new ArgumentNullException(nameof(connectionString));

        services.AddDbContext<TDbContext>(c => c.UseSqlServer(connectionString), ServiceLifetime.Transient);
        services.AddScoped(provider => new ContextFactory<TDbContext>(() => ActivatorUtilities.CreateInstance<TDbContext>(provider, provider.GetRequiredService<DbContextOptions<TDbContext>>())));
    }
}

And then inside your public void ConfigureServices(IServiceCollection services) add your connection string from your configuration:

services.AddDatabase<MyDbContext>(Configuration.GetConnectionString("MyDatabase"));

Upvotes: 2

Related Questions