Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoFac - Instantiating an unregistered service with known services

Instantiating an unregistered service with known services (injecting them via ctr).

I want to avoid container pollution.

like image 447
Paul Knopf Avatar asked Feb 18 '11 15:02

Paul Knopf


2 Answers

Here is another way to resolve unregistered concrete types from container. Note that all autofac constructor finding and selecting logic, all registration event handlers remain in force.

First, you define this method:

    public static object ResolveUnregistered(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
    {
        var scope = context.Resolve<ILifetimeScope>();
        using (var innerScope = scope.BeginLifetimeScope(b => b.RegisterType(serviceType)))
        {
            IComponentRegistration reg;
            innerScope.ComponentRegistry.TryGetRegistration(new TypedService(serviceType), out reg);

            return context.ResolveComponent(reg, parameters);
        }
    }

The idea is that you get component registration from derived context and resolve it in the current context. Then you can create some handy overloads:

    public static object ResolveUnregistered(this IComponentContext context, Type serviceType)
    {
        return ResolveUnregistered(context, serviceType, Enumerable.Empty<Parameter>());
    }

    public static object ResolveUnregistered(this IComponentContext context, Type serviceType, params Parameter[] parameters)
    {
        return ResolveUnregistered(context, serviceType, (IEnumerable<Parameter>)parameters);
    }

    public static TService ResolveUnregistered<TService>(this IComponentContext context)
    {
        return (TService)ResolveUnregistered(context, typeof(TService), Enumerable.Empty<Parameter>());
    }

    public static TService ResolveUnregistered<TService>(this IComponentContext context, params Parameter[] parameters)
    {
        return (TService)ResolveUnregistered(context, typeof(TService), (IEnumerable<Parameter>)parameters);
    }
like image 85
Ilya Avatar answered Nov 06 '22 21:11

Ilya


I found a solution that required some custom code. Somethings are specific to my app, but I think you can get the picture.

Resolve(parameter.ParameterType) would be a call to your container.

public object ResolveUnregistered(Type type)
{
    var constructors = type.GetConstructors();
    foreach (var constructor in constructors)
    {
        try
        {
            var parameters = constructor.GetParameters();
            var parameterInstances = new List<object>();
            foreach (var parameter in parameters)
            {
                var service = Resolve(parameter.ParameterType);
                if (service == null) throw new NopException("Unkown dependency");
                parameterInstances.Add(service);
            }
            return Activator.CreateInstance(type, parameterInstances.ToArray());
        }
        catch (NopException)
        {

        }
    }
    throw new NopException("No contructor was found that had all the dependencies satisfied.");
}
like image 45
Paul Knopf Avatar answered Nov 06 '22 19:11

Paul Knopf