Autofac - Delegate Factories + Type Interceptors together

462 views Asked by At

I am trying to get AutoFac Delegate Factories & Type Interceptors to play nicely with each other, but I cannot seem to get the behaviour I want.

(http://docs.autofac.org/en/latest/advanced/delegate-factories.html) (http://docs.autofac.org/en/latest/advanced/interceptors.html)

In the example below, I want calls to the IQuoteService.GetQuote(...) to be intercepted by the CallLogger interceptor.

I've tried both of the Enable___(); extension methods for enabling interception, but none of them seem to correctly intercept the call.

I suspect the problem is the way that Autofac is registering the proxy and the signature of the delegate, but to be honest I am a little stuck... I don't know Autofac as well as I know Castle Windsor, but this project is using Autofac.

ANSWERED BELOW

Code updated to working example:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autofac;
using Autofac.Extras.DynamicProxy2;
using Castle.DynamicProxy;

namespace AutofacTest
{
    public class Shareholding
    {
        public delegate Shareholding Factory(string symbol, uint holding);

        private readonly IQuoteService _quoteService;

        public Shareholding(string symbol, uint holding, IQuoteService quoteService)
        {
            _quoteService = quoteService;
            Symbol = symbol;
            Holding = holding;
        }

        public string Symbol { get; private set; }

        public uint Holding { get; set; }

        public decimal Value
        {
            get { return _quoteService.GetQuote(Symbol) * Holding; }
        }
    }

    public class Portfolio
    {
        private readonly IList<Shareholding> _holdings = new List<Shareholding>();
        private readonly Shareholding.Factory _shareholdingFactory;

        public Portfolio(Shareholding.Factory shareholdingFactory)
        {
            _shareholdingFactory = shareholdingFactory;
        }

        public decimal Value
        {
            get { return _holdings.Sum(h => h.Value); }
        }

        public void Add(string symbol, uint holding)
        {
            _holdings.Add(_shareholdingFactory(symbol, holding));
        }
    }

    public interface IQuoteService
    {
        decimal GetQuote(string symbol);
    }

    public class QuoteService : IQuoteService
    {
        public decimal GetQuote(string symbol)
        {
            return 10m;
        }
    }

    public class CallLogger : IInterceptor
    {
        private readonly TextWriter _output;

        public CallLogger(TextWriter output)
        {
            _output = output;
        }

        public void Intercept(IInvocation invocation)
        {
            _output.Write("Calling method {0} with parameters {1}... ",
                invocation.Method.Name,
                string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

            invocation.Proceed();

            _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Shareholding>();
            builder.RegisterType<Portfolio>();
            builder.Register(c => new CallLogger(Console.Out));

            builder.RegisterType<QuoteService>()
                   .As<IQuoteService>()
                   .EnableInterfaceInterceptors()
                   .InterceptedBy(typeof(CallLogger));

            var container = builder.Build();

            var portfolio = container.Resolve<Portfolio>();
            portfolio.Add("ABC", 1234);
            portfolio.Add("DEF", 4567);

            Console.WriteLine(portfolio.Value);
            Console.ReadKey();
        }
    }
}
2

There are 2 answers

1
CodingYoshi On BEST ANSWER
// Magic?

builder.RegisterType<Portfolio>()
       .As<IPortfolio>()
       .EnableInterfaceInterceptors()
       .InterceptedBy(typeof(CallLogger));;
builder.Register(c => new CallLogger(Console.Out));
var container = builder.Build();
var isResolved = container.Resolve<IPortfolio>();
0
qujck On

It looks to me like you are missing an association between the DynamicProxy for IPortfolio and the IInterceptor type.

This can be remedied via registration:

builder.RegisterType<Portfolio>()
    .As<IPortfolio>()
    .EnableInterfaceInterceptors()
    .InterceptedBy(typeof(CallLogger));

or via the InterceptAttribute

[Intercept(typeof(CallLogger))]
public interface IPortfolio
{
    decimal Value { get; }
    void Add(string symbol, uint holding);
}