Multiple databases, containers and packages

Feb 27, 2014 at 3:47 AM
I was just playing around with simple injector and was wondering is it's possible to use multiple containers and package in one application. I'm getting an error when I use a second instance of simple injector container. I will explain with an example. I use two separate databases code-first.

Database 1:
    public class ERPContext : DbContext
    {
        #region Catalog

        public DbSet<Category> Categories { get; set; }

        public DbSet<CrossSellProduct> CrossSellProducts { get; set; }
        
        public DbSet<Manufacturer> Manufacturers { get; set; }

        public DbSet<ManufacturerSize> ManufacturerSizes { get; set; }

        public DbSet<ManufacturerSizeOption> ManufacturerSizeOptions { get; set; }

        public DbSet<ManufacturerTierPrice> ManufacturerTierPrices { get; set; }
               
        public DbSet<Product> Products { get; set; }
     
        #endregion Catalog
  
        public ERPContext()
            : base("intershoe-erp")
        {
            //Configuration.LazyLoadingEnabled = false;
          
        }

       protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // verwijder naamconventie
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
         
        }
    }
Database 2:
 public class SyncContext : DbContext
    {
        public DbSet<Sync> Syncs { get; set; }
        
        public SyncContext()
            : base("intershoe-sync")
        {}
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // verwijder naamconventie
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        }
     
    }
I've created two packages to register my repositories and services so i can call them easily from every app i create. Those packages i've created in the service layer. Here is the structure of my solution:

ErpDatabase (context)
SyncDatabase (context)
ErpModel (model classes)
SyncModel (model classes)
ErpServices (holds the services and package)
SyncServices (holds the services and package)
ConsoleApp (app that calls the packages)

Package 1:
 public class ErpServicesPackage : IPackage
    {
        public void RegisterServices(Container container)
        {
           // context
            container.Register<DbContext, ERPContext>();
            
            // repositories
            container.RegisterSharpRepository();

            // services
            container.Register<IProductService, ProductService>();
            container.Register<IManufacturerService, ManufacturerService>();
            container.Register<ICategoryService, CategoryService>();
            
            // verify
            container.Verify();

            // set resolver
            RepositoryDependencyResolver.SetDependencyResolver(new SimpleInjectorDependencyResolver(container));
        }
    }
Package 2:
 public  class SyncServicesPackage : IPackage
    {
          public void RegisterServices(Container container)
          {

              // context
              container.Register<DbContext, SyncContext>();

              // services
              container.Register<ISyncService, SyncService>();
        
              // repositories
              container.RegisterSharpRepository();

              // verify
              container.Verify();

              // set resolver
              RepositoryDependencyResolver.SetDependencyResolver(new SimpleInjectorDependencyResolver(container));
          }
    }
When i call just one package in my console app it works find, but when i register the second i'm getting an error. Does someone know what i'm doing wrong and how to fix this?

Console App:
        private static readonly Container _erpServicesContainer = new Container();
        private static readonly Container _syncServicesContainer = new Container();

        private static void Main(string[] args)
        {
            var erpServicesPackage= new ErpServicesPackage();
            var syncServicesPackage = new SyncServicesPackage();

            erpServicesPackage.RegisterServices(_erpServicesContainer);
            syncServicesPackage.RegisterServices(_syncServicesContainer);

            var productService = _erpServicesContainer.GetInstance<IProductService>();
            var manufacturerService = _erpServicesContainer.GetInstance<IManufacturerService>();
            var syncService = _syncServicesContainer.GetInstance<ISyncService>();

            var test = new ErpProduct();

            productService.InsertProduct(test);

        }
Error:
The entity type Product is not part of the model for the current context.

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=The entity type Product is not part of the model for the current context.
  Source=EntityFramework
  StackTrace:
       bij System.Data.Entity.Internal.InternalContext.UpdateEntitySetMappingsForType(Type entityType)
       bij System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
       bij System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
       bij System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
       bij System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
       bij System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
       bij System.Data.Entity.DbSet`1.Add(TEntity entity)
       bij SharpRepository.EfRepository.EfRepositoryBase`2.AddItem(T entity)
       bij SharpRepository.Repository.RepositoryBase`2.ProcessAdd(T entity, Boolean batchMode)
       bij SharpRepository.Repository.RepositoryBase`2.Add(T entity)
       bij ERP.Services.ERPServices.Catalog.ProductService.InsertProduct(Product product) in c:\Users\wesley\Documents\## Bitbucket\ERP\intershoe\ERP\Services\ERPServices\Catalog\ProductService.cs:regel 62
       bij UpgradeConsoleApplication.Program.CopyProductsToErp(Boolean isTest) in c:\Users\wesley\Documents\## Bitbucket\ERP\intershoe\ERP\Console\UpgradeConsoleApplication\Program.cs:regel 1897
       bij UpgradeConsoleApplication.Program.Main(String[] args) in c:\Users\wesley\Documents\## Bitbucket\ERP\intershoe\ERP\Console\UpgradeConsoleApplication\Program.cs:regel 86
       bij System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       bij System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bij Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bij System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bij System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bij System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bij System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bij System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
This is the service i'm calling. I'm using SharpRepository:
 public  class ProductService : IProductService
    {

        #region Fields

        private readonly IRepository<Product> _productRepository; 

        #endregion

        #region Ctor

        public ProductService(IRepository<Product> productRepository)
        {
            _productRepository = productRepository;
        }

        #endregion

        #region CRUD

        public IList<Product> GetAllProducts()
        {
            return _productRepository.GetAll().ToList();
        }

        public Product GetProductById(int id)
        {
            return _productRepository.Get(id);
        }

        public void InsertProduct(Product product)
        {
            _productRepository.Add(product);
        }

        public void UpdateProduct(Product product)
        {
            _productRepository.Update(product);
        }

        public void DeleteProduct(Product product)
        {
            _productRepository.Delete(product);
        }

        #endregion

        #region Methods

        public Product GetProductByName(string name)
        {
            return _productRepository.Find(x => x.Name.Equals(name));
        }
        
        public Product GetProductBySku(string sku)
        {
            return _productRepository.Find(x => x.Sku.Equals(sku));
        }

        #endregion

    }
Developer
Feb 27, 2014 at 7:52 AM
I am not familiar with SharpRepository but:

I wonder whether you are configuring/using two independent containers? I ask because in both packages you register the same service DbContext and in both you call container.Verify();. Registering the same service twice (e.g. overwriting an earlier registration) should only be possible when container.Options.AllowOverridingRegistrations == true. And container.Verify() will disallow further registrations therefore it should better not be placed in a RegisterServices() method - so I guess you are using two containers because otherwise you should see other exceptions earlier.

If you are using two containers RepositoryDependencyResolver.SetDependencyResolver() will probably not work because it registeres a dependency resolver appdomain-wide in a static variable (last writer-wins).

Do you have a reference of the SharpRepository authors that explains how they intended to enable sharing different DbContexts?
Marked as answer by dot_NET_Junkie on 4/15/2014 at 1:46 AM