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

Autofac ServiceLocator #15

Closed
mkobaly opened this issue Oct 22, 2011 · 5 comments
Closed

Autofac ServiceLocator #15

mkobaly opened this issue Oct 22, 2011 · 5 comments

Comments

@mkobaly
Copy link

mkobaly commented Oct 22, 2011

Sorry for doing this but I am new to SimpleCqrs & GitHub. I am trying to incorporate Autofac as one of the Service Locators but the below code seems to blow up when resolving say the LocalCommandBus using the SimpleCqrsDemo. Any ideas?

public class AutofacServiceLocator : IServiceLocator
{
public IContainer Container { get; private set; }

    public AutofacServiceLocator()
    { 
        var builder = new ContainerBuilder();

        Container = builder.Build();
    }

    public AutofacServiceLocator(IContainer container)
    {
        if (container == null)
            throw new ArgumentNullException("container", "The specified Autofac container cannot be null.");
        Container = container;
    }

    #region IServiceLocator Members

    public T Resolve<T>() where T : class
    {
        return Container.Resolve<T>();
    }

    public T Resolve<T>(string key) where T : class
    {
        return Container.ResolveNamed<T>(key);
    }

    public object Resolve(Type type)
    {
        return Container.Resolve(type);
    }

    public IList<T> ResolveServices<T>() where T : class
    {
        return Container.Resolve<IEnumerable<T>>().ToList();
    }

    public void Register<TInterface>(Type implType) where TInterface : class
    {
        var builder = new ContainerBuilder();
        builder.RegisterType(implType).As<TInterface>();
        builder.Update(Container);
    }

    public void Register<TInterface, TImplementation>() where TImplementation : class, TInterface
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<TImplementation>().As<TInterface>();
        builder.Update(Container);
    }

    public void Register<TInterface, TImplementation>(string key) where TImplementation : class, TInterface
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<TImplementation>().As<TInterface>().Named<TInterface>(key);
        builder.Update(Container);
    }

    public void Register(string key, Type type)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType(type).Named(key, type);
        builder.Update(Container);
    }

    public void Register(Type serviceType, Type implType)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType(implType).As(serviceType);
        builder.Update(Container);
    }

    public void Register<TInterface>(TInterface instance) where TInterface : class
    {
        var builder = new ContainerBuilder();
        builder.RegisterInstance(instance).As<TInterface>();
        builder.Update(Container);
    }

    public void Release(object instance)
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }

    public TService Inject<TService>(TService instance) where TService : class
    {
        return Container.InjectProperties(instance);
    }

    public void TearDown<TService>(TService instance) where TService : class
    {
        throw new NotImplementedException();
    }

    public void Register<TInterface>(Func<TInterface> factoryMethod) where TInterface : class
    {
        var builder = new ContainerBuilder();
        builder.Register(x => factoryMethod()).As<TInterface>();
        builder.Update(Container);
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        if (Container != null) 
        { 
            Container.Dispose(); 
            Container = null;
        }  
    }

    #endregion
}
@darrencauthon
Copy link
Collaborator

I haven't run your code, but just looking at it reminded me of an issue I had implementing a service locator for Autofac last year. Back then, you could not add registrations to a container after it was built. "Immutable containers" suddenly became a big problem for that crowd. So when you build the container in the constructor, you might be shutting off your ability to load anything.

@mkobaly
Copy link
Author

mkobaly commented Oct 22, 2011

For a test I changed my registrations to something similar below. Basically if the container is not instantiated keep using the builder. Since I don't know anything about Unity / Structuremap I don't understand how they actually can resolve LocalCommandBus. I step through the code for all service locators and I don't see where LocalCommnadBus is registered. For the unity/structuremap ServiceLocators when I step through the code it is resolving the LocalCommandBus AND THEN REGISTERING it as ICommandBus. I would almost agree with the error I am getting from Autofac that the LocalCommandBus is NOT registered.

If I add a line to register the LocalCommandBus manually it works fine.

public void Register<TInterface, TImplementation>() where TImplementation : class, TInterface
    {
        if (_container == null)
        {
            _builder.RegisterType<TImplementation>().As<TInterface>();
        }
        else
        {
            _container.ComponentRegistry.Register(RegistrationBuilder.ForType<TImplementation>().As<TInterface>().CreateRegistration());
        }
    }

@darrencauthon
Copy link
Collaborator

In case this helps, here is what I believe is happening:

1.) When Start() is called on the SimpleCQRS runtime, the essential components (like ICommandBus) are registered in your IoC container: https://github.com/tyronegroves/SimpleCQRS/blob/master/src/SimpleCqrs/SimpleCqrsRuntime.cs#L37

2.) The way the runtime gets those components is calling methods on the runtime, like GetCommandBus: https://github.com/tyronegroves/SimpleCQRS/blob/master/src/SimpleCqrs/SimpleCqrsRuntime.cs#L86

So, given this setup, the runtime will attempt to resolve an instance of LocalCommandBus (since it's the default), then it will register that instance as a singleton for ICommandBus.

I thought Autofac had the same capability of resolving concrete types that aren't registered, does it?

@tyronegroves
Copy link
Owner

I think I can fix your problem pretty easily I will try it out at lunch and let you know how it went.

@tyronegroves
Copy link
Owner

I changed the way the LocalCommandBus is created so it should work for you now. Can you try it out and let me know if it works? Thanks for taking intreset in the project.

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

No branches or pull requests

3 participants