Search code examples
c#castle-windsor

Use Castle.Windsor with SSW Data Onion for Entity Framework 6


I'm working on integrating a legacy database with Asp.Net Zero. I created the model classes using EntityFramework Reverse POCO Generator in a separate Models class library project. I also reversed engineered the DbContext into a separate Data class library project. I would like to use the Data Onion framework for my repositories and unit of work. When I use the recommended IOC container Autofaq my Test Winform application works correctly.

However, the Web Project utilizes Castle.Windsor. I'm uncertain on how to do the wire-up.

I'm creating a new container called ClientDesktopContainer:

internal class ClientDesktopContainer : WindsorContainer
{
    public ClientDesktopContainer()
    {
        RegisterComponents();
    }

    private void RegisterComponents()
    {
        var connectionstring = ConfigurationManager.ConnectionStrings["MyDbContext"].ConnectionString;

        // Data Onion
        Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
            .DependsOn(new DbContextConfig(connectionstring, typeof(MyDbContext), new MigrateToLatestVersion(new Seeder())));
        Component.For<IDbContextScope>().ImplementedBy<DbContextScope>();
        Component.For<IDbContextScopeFactory>().ImplementedBy<DbContextScopeFactory>();
        Component.For<IAmbientDbContextLocator>().ImplementedBy<AmbientDbContextLocator>();
        Component.For<IDbContextReadOnlyScope>().ImplementedBy<DbContextReadOnlyScope>();

        // Data Onion Unit of Work
        Component.For<IRepositoryLocator>().ImplementedBy<RepositoryLocator>();
        // Component.For<IRepositoryResolver>().ImplementedBy<CastleWindsorRepositoryResolver>();
        Component.For<IUnitOfWorkFactory>().ImplementedBy<UnitOfWorkFactory>();
        Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>();
        Component.For<IReadOnlyUnitOfWork>().ImplementedBy<IReadOnlyUnitOfWork>();

        // Custom
        Component.For<IRepository<Enrollment>>()
                 .ImplementedBy<BaseRepository<Enrollment, MyDbContext>>();
}

My application invocation code is Program:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        IoC.Initialize(new ClientDesktopContainer());

        var dbContextScopeFactor = IoC.Resolve<IDbContextScopeFactory>();
        using (var dbReadOnly = dbContextScopeFactor.CreateReadOnly())
        {
            var context = dbReadOnly.DbContexts.Get<MyDbContext>();

            var individuals = context.Enrollments.ToList();
            foreach (var individual in individuals)
            {
                // do stuff
            }
        }

        Application.Run(new ViewMain());
    }
}

I created a static IOC:

public static class IoC
{
    private static IWindsorContainer _container;

    public static void Initialize(IWindsorContainer container)
    {
        _container = container;
    }

    public static T Resolve<T>()
    {
        try
        {
            return _container.Resolve<T>();
        }
        catch
        {
            throw;
        }
    }
}

The Data Onion documentation mentions registering a custom Resolver for IRepositoryResolver.

I created a CastleWindsorRepositoryResolver:

public class CastleWindsorRepositoryResolver : IRepositoryResolver
{
    public IRepository<TEntity> Resolve<TEntity>() where TEntity : class
    {
        // TODO: Resolve wire-up goes here
        throw new System.NotImplementedException();
    }
}

I'm receiving a ComponentNotFoundExpection: Exception

Updated to fix constructor parameter for DbContextFactory (to RegisterComponents method):

   var dbContextConfig = new DbContextConfig[]
        {
            new DbContextConfig(
                connectionString,
            typeof(MyDbContext),
            new MigrateToLatestVersion(new Seeder())
            ) 
        };

        // Data Onion
        Register(Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
            .DependsOn(Dependency.OnValue<DbContextConfig[]>(dbContextConfig)));

Solution

  • Add call to Register in:

    internal class ClientDesktopContainer : WindsorContainer
    {
        public ClientDesktopContainer()
        {
            RegisterComponents();
        }
    
        private void RegisterComponents()
        {
            var connectionstring = ConfigurationManager.ConnectionStrings["MyDbContext"].ConnectionString;
    
             /* HERE CALL TO REGISTER: */
             this.Register(
    
            // Data Onion
            Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
                .DependsOn(new DbContextConfig(connectionstring, typeof(MyDbContext), new MigrateToLatestVersion(new Seeder()))),
            Component.For<IDbContextScope>().ImplementedBy<DbContextScope>(),
            Component.For<IDbContextScopeFactory>().ImplementedBy<DbContextScopeFactory>(),
            Component.For<IAmbientDbContextLocator>().ImplementedBy<AmbientDbContextLocator>(),
            Component.For<IDbContextReadOnlyScope>().ImplementedBy<DbContextReadOnlyScope>(),
    
            // Data Onion Unit of Work
            Component.For<IRepositoryLocator>().ImplementedBy<RepositoryLocator>(),
            // Component.For<IRepositoryResolver>().ImplementedBy<CastleWindsorRepositoryResolver>(),
            Component.For<IUnitOfWorkFactory>().ImplementedBy<UnitOfWorkFactory>(),
            Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>(),
            Component.For<IReadOnlyUnitOfWork>().ImplementedBy<IReadOnlyUnitOfWork>(),
    
            // Custom
            Component.For<IRepository<Enrollment>>()
                     .ImplementedBy<BaseRepository<Enrollment, MyDbContext>>() );
    }
    

    Without Register you are just creating registration object without actually putting types in container. Another thing that may help, by default Castle will register components as singletons add LifestyleTranscient or PerWebRequest to your UnitOfWork registrations.