Autofac 全局接口拦截器与 Autofac.Extras.DynamicProxy2

2024-01-04

我将接口拦截器与 Autofac DynamicProxy2 结合使用,并且可以为每个寄存器启用接口拦截器:

   var registration = builder.RegisterType<AType>().As<AInterface>();
   registration.EnableInterfaceInterceptors().InterceptedBy<AInterceptor>()

我想将某些特征应用于所有注册类型。就像是:

   var registrations = builder.GetAllRegistrations(); // ops, this does not exist...
   foreach (var registration in registrations) {
       registration.EnableInterfaceInterceptors().InterceptedBy<AInterceptor>()
   }

我找不到获得所有注册的方法。我知道我们可以这样做:

   builder.RegisterCallback(cr =>
   {
       foreach (var registration in cr.Registrations)
       {
            // registration is IComponentRegistration
       }
   });

但这里的注册是IComponentRegistration我需要一个IRegistrationBuilder来应用EnableInterfaceInterceptors().


显然,放弃这一点并不简单EnableInterfaceInterceptors在我们执行注册表时调用。

由于我的目标是实现一个对通过 Autofac 解析的所有接口通用的拦截器,所以我最终推出了自己的解决方案,灵感来自于DynamicProxyAutofac 的实现。

这个想法是重写 AutofacActivating事件并手动创建 DynamicProxy。这里的大部分工作是确保我们可以安全地代理正在解析的类型。

public static class AutofacExtensions
{
    // DynamicProxy2 generator for creating proxies
    private static readonly ProxyGenerator generator = new ProxyGenerator();

    /// <summary>
    /// Intercept ALL registered interfaces with provided interceptors.
    /// Override Autofac activation with a Interface Proxy.
    /// Does not intercept classes, only interface bindings.
    /// </summary>
    /// <param name="builder">Contained builder to apply interceptions to.</param>
    /// <param name="interceptors">List of interceptors to apply.</param>
    public static void InterceptInterfacesBy(this ContainerBuilder builder, params IInterceptor[] interceptors)
    {
        builder.RegisterCallback((componentRegistry) =>
        {
            foreach (var registration in componentRegistry.Registrations)
            {
                InterceptRegistration(registration, interceptors);
            }
        });
    }

    /// <summary>
    /// Intercept a specific component registrations.
    /// </summary>
    /// <param name="registration">Component registration</param>
    /// <param name="interceptors">List of interceptors to apply.</param>
    private static void InterceptRegistration(IComponentRegistration registration, params IInterceptor[] interceptors)
    {
        // proxy does not get allong well with Activated event and registrations with Activated events cannot be proxied.
        // They are casted to LimitedType in the IRegistrationBuilder OnActivated method. This is the offending Autofac code:
        // 
        // public IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> OnActivated(Action<IActivatedEventArgs<TLimit>> handler)
        // {
        //    if (handler == null) throw new ArgumentNullException("handler");
        //    RegistrationData.ActivatedHandlers.Add(
        //        (s, e) => handler(new ActivatedEventArgs<TLimit>(e.Context, e.Component, e.Parameters, (TLimit)e.Instance)));
        //    return this;
        // }
        Delegate[] handlers = GetActivatedEventHandlers(registration);
        if (handlers.Any(h => handlers[0].Method.DeclaringType.Namespace.StartsWith("Autofac")))
        {
            return;
        }

        registration.Activating += (sender, e) =>
        {
            Type type = e.Instance.GetType();

            if (e.Component.Services.OfType<IServiceWithType>().Any(swt => !swt.ServiceType.IsInterface || !swt.ServiceType.IsVisible) || 
                // prevent proxying the proxy 
                type.Namespace == "Castle.Proxies")
            {
                return;
            }

            var proxiedInterfaces = type.GetInterfaces().Where(i => i.IsVisible).ToArray();

            if (!proxiedInterfaces.Any())
            {
                return;
            }

            // intercept with all interceptors
            var theInterface = proxiedInterfaces.First();
            var interfaces = proxiedInterfaces.Skip(1).ToArray();

            e.Instance = generator.CreateInterfaceProxyWithTarget(theInterface, interfaces, e.Instance, interceptors);
        };
    }

    /// <summary>
    /// Get Activated event handlers for a registrations
    /// </summary>
    /// <param name="registration">Registration to retrieve events from</param>
    /// <returns>Array of delegates in the event handler</returns>
    private static Delegate[] GetActivatedEventHandlers(IComponentRegistration registration)
    {
        FieldInfo eventHandlerField = registration.GetType().GetField("Activated", BindingFlags.NonPublic | BindingFlags.Instance);
        var registrations = eventHandlerField.GetValue(registration);
        System.Diagnostics.Debug.WriteLine(registrations);
        return registrations.GetType().GetMethod("GetInvocationList").Invoke(registrations, null) as Delegate[];
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Autofac 全局接口拦截器与 Autofac.Extras.DynamicProxy2 的相关文章

  • 如何指定CMAKE外部项目的编译器?

    我使用ExternalProject Add 包含一个外部项目 我想要的是能够做到 cmake DCMAKE CXX COMPILER
  • C 中的分段错误

    我需要用 0 填充二维数组 但编译后的程序会出现此错误 怎么了 int main int vert 1001 1001 int hor 1001 1001 int dudiag 1416 1416 int uddiag 1416 1416
  • NUnit 测试运行顺序

    默认情况下 nunit 测试按字母顺序运行 有谁知道有什么方法可以设置执行顺序吗 是否存在这样的属性 我只是想指出 虽然大多数受访者认为这些是单元测试 但问题并没有具体说明它们是 nUnit 是一个很棒的工具 可用于各种测试情况 我可以看到
  • 使用 boost::iterator_facade<>

    我有一个链表结构 struct SomeLinkedList const char bar int lots of interesting stuff in here DWORD foo SomeLinkedList pNext 它是现有
  • 按位非运算符

    为什么要按位运算 0 打印 1 在二进制中 不是0应该是1 为什么 你实际上很接近 在二进制中 不是0应该是1 是的 当我们谈论一位时 这是绝对正确的 然而 一个int其值为0的实际上是32位全零 将所有 32 个 0 反转为 32 个 1
  • .NET 中 IEqualityComparer 中 GetHashCode 的作用是什么?

    我试图了解 IEqualityComparer 接口的 GetHashCode 方法的作用 下面的例子取自MSDN using System using System Collections Generic class Example st
  • 了解 MVC-5 身份

    我创建了一个新的ASP NET MVC 5申请与Individual User Accounts然后更新了所有的Nuget packages在解决方案中 现在我尝试遵循一些教程中显示的一些指南 但遇到了一些问题 第一个是一个名为Applic
  • 为什么测试在 TeamCity 中运行比直接在 NUnit 中运行需要更长的时间?

    我进行了一些 C 性能测试 基本上运行两种不同的方法 并检查一种方法的运行速度是否比另一种方法快得多 当我在 NUnit 本地运行它们时 其中一个测试的运行速度是另一个测试的十倍 因此我有一个 NUnit 测试 它使用Stopwatch检查
  • 锁定文件的一个块

    我有一个大小为 192k 的文件 我想锁定文件的中间部分 例如 我想用 c 锁定文件的 64k 128k 知道如何锁定文件的那部分吗 你需要使用锁定文件Ex http msdn microsoft com en us library win
  • 如何在 C# 中通过 JavaScript 回调运行 QUnit 测试并获取测试结果?

    在我的几个项目中 我使用 MVC 模式将代码 关注点 分为 3 层 模型层和控制层都在 C 上运行 因此我使用 MSTest 或 NUnit 等测试框架来验证这些层的功能需求 对于视图层 我使用 QUnit 来测试 JavaScript 文
  • 一个对大文件有效的轻量级 XML 解析器?

    我需要解析潜在的巨大 XML 文件 所以我猜这排除了 DOM 解析器 是否有任何优秀的 C 轻量级 SAX 解析器 在占用空间上可与 TinyXML 相媲美 XML的结构非常简单 不需要诸如命名空间和DTD之类的高级东西 只是元素 属性和
  • C++ std:.auto_ptr 或 std::unique_ptr (支持多个编译器,甚至是旧的 C++03 编译器)?

    我正在尝试更新一些 C 代码 我想转向更现代的代码 c 11 但我仍然需要使用一些较旧的编译器 兼容 c 03 来编译代码 因为支持的平台限制 我知道在 C 11 编译器中 std auto ptr 已被弃用 但由于较旧的编译器支持 我不能
  • MPI_Gatherv:根数组中收到的垃圾值

    我正在尝试实施MPI Gatherv函数于C 根据我的程序 包括 root 在内的每个进程都应该创建一个大小等于 进程的等级 1 这将在所有单元格中保持进程的等级 然后这个本地数组被收集到根的 rcv array 中 不知何故 我得到了垃圾
  • 如何最好地为 Visual Studio 2017 构建的 CMake C++ 项目设置输出目录?

    我使用 Visual Studio 2017 使用 vcxproj 文件构建 C 桌面项目 我喜欢默认行为 其中输出目录是项目下面的子目录 例如 myproj sln myproj vcxproj x64 myproj release my
  • 将函数作为函数参数传递

    Unity C 似乎无法识别Func lt gt 作为函数委托的符号 那么 如何将函数作为函数参数传递呢 我有一个想法Invoke functionName 0 可能有帮助 但我不确定它是否实际上立即调用该函数 或者等待帧结束 还有别的办法
  • 检测用户是否正在滚动 dataGridView 滚动条

    我正在更新一个dataGridView与一个新的数据表使用 dataGridView1 DataSource table 但是 我不想在用户滚动 dataGridView 时执行此操作 如何检查滚动条是否正在滚动或已完成滚动 即拖动而不是单
  • Azure Function App Azure 服务总线触发器触发两次

    我使用带有服务总线触发器的 Azure Function Apps 来读取服务总线并对服务总线消息的内容执行操作 服务总线接收 JSON 序列化对象 然后将 JSON 消息反序列化回 Function App 中的对象 然而 由于某种原因
  • MonoGame 中的 ContentLoadException

    我一直在尝试使用 Xamarin Studio 在 MonoGame 中加载纹理 我的代码设置如下 region Using Statements using System using Microsoft Xna Framework usi
  • 如何通过Task.ContinueWith创建传递?

    我想在原始任务结束时添加一个任务 但想保留原始结果和类型 附加任务仅用于记录目的 例如写入控制台等 例如 Task Run gt DateTime Now Hour gt 12 Hey throw new Exception Continu
  • “保留供任何使用”是什么意思?

    注意 这是一个c questions tagged c问题 虽然我补充说c questions tagged c 2b 2b如果某些 C 专家可以提供 C 使用与 C 不同的措辞的基本原理或历史原因 在 C 标准库规范中 我们有这个规范文本

随机推荐