如何在 Autofac 程序集扫描和注册期间有选择地更改生命周期范围?

How do I selectively change lifetime scope during Autofac assembly scanning and registration?

我有一个 class,它使用 AutoFac 从二进制文件夹中的程序集构建容器。这实质上是遍历 dll 并使用接口注册 classes:

    private static void RegisterAssembly(ContainerBuilder builder, string assemblyNamePattern)
    {
        // Get the path to the currently executing assembly. We will load dll's from here only.
        var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (String.IsNullOrWhiteSpace(path))
            return;

        // Get a list of all the assemblies in this folder
        var assembliesToRegister = (Directory.EnumerateFiles(path, assemblyNamePattern, SearchOption.TopDirectoryOnly)
                .Select(Assembly.LoadFrom)
                .ToArray());

        // Register the dll's
        builder.RegisterAssemblyTypes(assembliesToRegister).AsImplementedInterfaces();
    }

工作正常,我可以创建我需要的 classes 的实例。我遇到的问题是这些 class 中有几个是单例(例如 Redis 缓存),因此需要这样注册。在代码中,它们是使用 Lazy<>:

定义的
    private static readonly Lazy<CacheManager> _instance = new Lazy<CacheManager>(() => new CacheManager());
    public static ICacheManager Instance
    {
        get { return _instance.Value; }
    }

我想知道是否有某种方法可以告诉 AutoFac 某些 classes 需要注册为单例。我猜我可以在构建容器后检查容器并将特定定义更改为单例,但如果我能让 Autofac 在注册时自动执行它会更可靠。

作为一种廉价的解决方案,当扫描 DLL 时,您可以排除一个或多个接口:

        // Register the dll's, except the singleton ones.
        builder.RegisterAssemblyTypes(assembliesToRegister)
                .AsImplementedInterfaces()
                .Except<IOne>()
                .Except<ITwo>();

这允许自动注册除单例之外的所有内容。接下来注册单例:

AddSingletonInstance<IOne>(builder, assembliesToRegister, "OneType");
AddSingletonInstance<ITwo>(builder, assembliesToRegister, "TwoType");

这依赖于扫描之前创建的汇编列表的通用方法:

    private static void AddSingletonInstance<T>(ContainerBuilder builder, Assembly[] assembliesToRegister, string typeName)
    {
        var singletonType = (from asm in assembliesToRegister
                        from tt in asm.DefinedTypes
                        where tt.Name == typeName
                        select tt).FirstOrDefault();

        if (singletonType != null)
            builder.RegisterType(singletonType).As<T>().SingleInstance().ExternallyOwned();
    }

虽然不理想,但很管用。