Auto-generating interface implementation (proxy without class)

I would like to achieve:

[Factory]
public interface IFooFactory
{
    Foo Create();
}

unityContainer.RegisterType<IFooFactory>(
    new Interceptor<InterfaceInterceptor>(), 
    new InterceptionBehavior<FactoryInterceptionBehavior>());

      

If there is IFooFactory

no implementation , because it is provided FactoryInterceptionBehavior

.

When I try to resolve IFooFactory

, however, I get a ResolutionFailedException

message saying:

InvalidOperationException - The current type of IFooFactory is an interface and cannot be constructed. Are you missing type mapping?

I also thought about creating a proxy myself (using Intercept.ThroughProxy<>

or a dynamic lock proxy ...), but I still need to do the type registration with the container. I don't know how to delegate / undo creation of this type (like Ninject Bind<IFoo>().ToMethod(() => return new Foo())

).

+3


source to share


1 answer


So after some research and testing and error, I found that Unity.Interception does not support proxy interfaces where there is no real class implementing the interface and where calls end up eventually (dynamic lock proxies call them "proxy without a goal ").

So, I'm using Castle.Core dynamic proxy combined with unity out of the box InjectionFactory

(which can be used to delegate Func

factory permission ).

Factory injection looks like this:

var proxyFuncFactory = new InjectionFactory(CreateProxy);

private static object CreateProxy(IUnityContainer container, Type interfaceType, string name)
{
    var proxyGenerator = container.Resolve<Castle.DynamicProxy.ProxyGenerator>();

    return proxyGenerator.CreateInterfaceProxyWithoutTarget(interfaceType, container.Resolve<AutoGeneratedFactoryInterceptor>());
}

      

and can be used in a binding like this:

IUnityContainer.RegisterType<ISomeFactory>(proxyFuncFactory);

      

AutoGeneratedFactoryInterceptor

looks like that:

internal class AutoGeneratedFactoryInterceptor : IInterceptor
{
    private readonly IUnityContainer _unityContainer;

    public AutoGeneratedFactoryInterceptor(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public void Intercept(IInvocation invocation)
    {
        IEnumerable<ResolverOverride> resolverOverrides = DetermineResolverOverrides(invocation);

        Type typeToResolve = DetermineTypeToResolve(invocation.Method);

        invocation.ReturnValue = _unityContainer.Resolve(typeToResolve, resolverOverrides.ToArray());
    }

    private static Type DetermineTypeToResolve(MethodInfo method)
    {
        ResolveToAttribute resolveToAttribute = method.Attribute<ResolveToAttribute>();
        if (resolveToAttribute == null)
        {
            return method.ReturnType;
        }

        if (resolveToAttribute.ResolveTo.IsGenericTypeDefinition)
        {
            return resolveToAttribute.ResolveTo.MakeGenericType(method.GetGenericArguments());
        }

        return resolveToAttribute.ResolveTo;
    }

    private static IEnumerable<ResolverOverride> DetermineResolverOverrides(IInvocation invocation)
    {
        return invocation.Method.Parameters()
            .Select((parameterInfo, parameterIndex) => 
                new ParameterOverride(parameterInfo.Name, invocation.Arguments[parameterIndex]));
    }

      

It matches the factory -method-argument for constructor arguments by name (Unity out of the box ParameterOverride

). Note that especially the support for shared parameters is not ideal. It supports the following uses:

public interface IFooFactory
{
    Foo Create();
}

      



and

unityContainer.RegisterType(typeof(IFoo<>), typeof(Foo<>));

public interface IFooFactory
{
    IFoo<T> Create<T>();
}

      

and

public interface IFooFactory
{
    Foo Create(string parameter1, object parameter2);
}

      

and

public interface IFooFactory
{
    [ResolveTo(typeof(Foo))]
    IFoo Create();
}

      

and

public interface IFooFactory
{
    [ResolveTo(typeof(Foo<>))]
    IFoo Create<T>();
}

      

Also note that any allowed (created) instance constructor arguments that are not covered ParameterOverride

are ctor-inject "as usual".

+1


source







All Articles