DryIoc open generic interception with castle core

558 Views Asked by At

I want to register open generic interception, so I modified explample from https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/Interception.md

[TestFixture]
public class UnitTest3
{
    public interface IFoo<T>
    {
        void Greet();
    }

    public class Foo<T> : IFoo<T>
    {
        public void Greet() { }
    }

    [Test]
    public void Example()
    {
        var container = new Container();
        container.Register(typeof(IFoo<>), typeof(Foo<>));
        container.Register<FooLoggingInterceptor>(Reuse.Singleton);
        container.Intercept<FooLoggingInterceptor>(typeof(IFoo<>));

        var foo = container.Resolve<IFoo<int>>();
        foo.Greet();

        // examine that logging indeed was hooked up
        var logger = container.Resolve<FooLoggingInterceptor>();
        Assert.AreEqual("Invoking method: Greet", logger.LogLines[0]);
    }
}

public class FooLoggingInterceptor : IInterceptor
{
    public List<string> LogLines = new List<string>();
    private void Log(string line) => LogLines.Add(line);

    public void Intercept(IInvocation invocation)
    {
        Log($"Invoking method: {invocation.GetConcreteMethod().Name}");
        invocation.Proceed();
    }
}

public static class DryIocInterception
{
    private static readonly DefaultProxyBuilder _proxyBuilder = new DefaultProxyBuilder();

    public static void Intercept<TInterceptor>(this IRegistrator registrator, Type serviceType, object serviceKey = null)
        where TInterceptor : class, IInterceptor
    {
        Type proxyType;
        if (serviceType.IsInterface())
            proxyType = _proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(
                serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default); //Exception!!!
        else if (serviceType.IsClass())
            proxyType = _proxyBuilder.CreateClassProxyTypeWithTarget(
                serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default);
        else
            throw new ArgumentException(
                $"Intercepted service type {serviceType} is not a supported, cause it is nor a class nor an interface");

        registrator.Register(serviceType, proxyType,
            made: Made.Of(pt => pt.PublicConstructors().FindFirst(ctor => ctor.GetParameters().Length != 0),
                Parameters.Of.Type<IInterceptor[]>(typeof(TInterceptor[]))),
            setup: Setup.DecoratorOf(useDecorateeReuse: true, decorateeServiceKey: serviceKey));
    }
}

But this throws exception:

Can not create proxy for type TestDryIoc.UnitTest3+IFoo`1 because type TestDryIoc.UnitTest3+IFoo`1 is an open generic type.

Aparently Castle.Core doesn't support open generics. My other idea was to supply delegate, which will create the proxy class on resolve, when concrete generic param is known, but looks like DryIoc doesn't support open generic delegates...

1

There are 1 best solutions below

4
dadhi On BEST ANSWER

Yeah, it is possible. So you need to find the closed type to pass it to the proxy? Wrap the code into the method and use the Made.Of which has access to the Request.ServiceType.