Search code examples
c#.net-coreautofac

Autofac two pgsql database connections


We are using InstancePerLifetimeScope for Database . But in some case we need a new db connection. Our autofac registration is

builder.RegisterType<Npgsql.NpgsqlConnection> ()
     As<IDbConnection> ()
     .WithParameter ("connectionString", constr)
     .InstancePerLifetimeScope ();

 // for NewDb Connection     
 builder.RegisterType<Npgsql.NpgsqlConnection> ()
      .As<IDpNewDb> ()
      .WithParameter ("connectionString", constr)
      .InstancePerRequest ();   

Code for IDpNewDb is

public interface IDpNewDb : IDbConnection { }

We are getting a error while running this code

An exception of type 'System.ArgumentException' occurred in Autofac.dll but was not handled in user code: 'The type 'Npgsql.NpgsqlConnection' is not assignable to service 'xxxx.Core.Data.IDpNewDb'.'

Any idea ?

Edit : Below the code for a cut-down version of the app

My Startup Class

public class Startup {
    public Startup (IConfiguration configuration) {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    public void ConfigureServices (IServiceCollection services) {
        services.AddMvc ().SetCompatibilityVersion (CompatibilityVersion.Version_2_2);
        ConfigureAutofac (services);
    }
    internal static AutofacServiceProvider ConfigureAutofac (IServiceCollection services) {

        var containerBuilder = new ContainerBuilder ();

        containerBuilder.RegisterModule<DefaultModule> ();
        containerBuilder.Populate (services);
        var container = containerBuilder.Build ();
        var srv = new AutofacServiceProvider (container);
        return srv;
    }
    public void Configure (IApplicationBuilder app, IHostingEnvironment env) {
        if (env.IsDevelopment ()) {
            app.UseDeveloperExceptionPage ();
        } else {
            app.UseHsts ();
        }

        app.UseHttpsRedirection ();
        app.UseMvc ();
    }
}

Autofac Module

 internal class DefaultModule : Autofac.Module {
        public void init (ContainerBuilder builder) {
            Load (builder);
        }

        protected override void Load (ContainerBuilder builder) {
            builder.RegisterType<Npgsql.NpgsqlConnection> ()
                .As<IDbConnection> ()
                .WithParameter ("connectionString", "Server=localhost;Database=DBName;User Id=postgres;password=*******;Application Name=myapp;")
                .InstancePerLifetimeScope ();

            builder.RegisterType<Npgsql.NpgsqlConnection> ()
                .As<IDbNewDb> ()
                .WithParameter ("connectionString", "Server=localhost;Database=DBName;User Id=postgres;password=******;Application Name=myapp;")
                .InstancePerRequest ();
        }

    }

interfaces.cs

namespace autofac_issue {
        public interface IDbNewDb : IDbConnection { };
}

Finally, Controller

namespace autofac_issue.Controllers {
    [Route ("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase {
        // GET api/values
        public ValuesController (IDbNewDb dbnew, IDbConnection db) {

        }
    }
}

Solution

  • The following line won't work

     builder.RegisterType<Npgsql.NpgsqlConnection> ()
            .As<IDpNewDb> ()
    

    NpgsqlConnection does not implement IDpNewDb. You will have a similar error even using pure C#.

    If you want a new instance of IDbConnection you can use Owned combined with Func<> which will act like a mini scope and you will have a new instance whenever you want.

    
    public class X {
        public X(Func<Owned<IDbConnection>> dbConnectionFactory){
            this._dbConnectionFactory = dbConnectionFactory;
        }
    
        private readonly Func<Owned<IDbConnection>> _dbConnectionFactory; 
    
        public void Do(){
            // will create a new instance each time you call the factory 
            using(Owned<IDbConnection> ownedDbConnection = this._dbConnectionFactory()){
                IDbConnection dbConnection = ownedDbConnection.Value;
            }
        }
    }
    
    

    See Combining Owned with Func from the Autofac documentation for more information.