Autofac - 委托工厂 + 类型拦截器在一起

Autofac - Delegate Factories + Type Interceptors together

我正在尝试让 AutoFac Delegate Factories & Type Interceptors 相互配合,但我似乎无法获得我想要的行为。

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

在下面的示例中,我希望调用 IQuoteService.GetQuote(...) 被 CallLogger 拦截器拦截。

我已经尝试了两个 Enable___();启用拦截的扩展方法,但其中 none 似乎正确拦截了调用。

我怀疑问题出在 Autofac 注册代理的方式和委托人的签名,但老实说我有点卡住了......我对 Autofac 的了解并不像我对 Castle Windsor 的了解, 但这个项目正在使用 Autofac.

回答如下

代码已更新为工作示例:

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();
        }
    }
}
// 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>();

在我看来,您缺少 IPortfolioDynamicProxyIInterceptor 类型之间的关联。

这可以通过注册来解决:

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

或通过 InterceptAttribute

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