Unity IOC - 如何注册基于自定义属性的类型?

Unity IOC - How to register Types based on Custom Attribute?

我有一个大型 ASP.Net 网络应用程序,它始终使用 Unity IOC。有许多 classes 需要创建为单例。

这是我的 UnityConfig.cs 启动项目中代码的第一部分:

// Create new Unity Container
var container = new UnityContainer();

// Register All Types by Convention by default
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.Transient);

到此为止,我已经在Unity IOC容器中具体注册了各个单例类型,有一个lifetime manager,如下:

container.RegisterType<IMySingleton1, MySingleton1>(new ContainerControlledLifetimeManager());
container.RegisterType<IMySingleton2, MySingleton2>(new ContainerControlledLifetimeManager());

但是,我想放弃以这种方式将每种类型专门注册为单例,通过使用自定义 SingletonAttribute 标记加载的程序集中的哪些类型需要是单例,然后,如果可能的话, 集体注册。

我为此目的创建了一个自定义属性:

[AttributeUsage(AttributeTargets.Class)]
public class SingletonAttribute : Attribute {}

并相应地标记 class 定义:

[Singleton]
public class MySingleton : IMySingleton
{
 ...
}

我已经设法 select 所有具有此自定义属性的类型:

static IEnumerable<Type> GetTypesWithSingletonAttribute(Assembly assembly)
{
    foreach (Type type in assembly.GetTypes())
    {
        if (type.GetCustomAttributes(typeof(SingletonAttribute), true).Length > 0)
        {
            yield return type;
        }
    }
}

我在 UnityConfig.cs 中有以下代码:

// Identify Singleton Types
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

List<Type> singletonTypes = new List<Type>();
foreach (var assembly in assemblies)
{
    singletonTypes.AddRange(GetTypesWithSingletonAttribute(assembly));
}

所以,我现在有一个包含所有必需类型的枚举,但我看不到如何按类型将它们注册为单例,同时仍使它们能够按约定解析(即,Unity 知道 IMySingleton 应该是解析为 MySingleton 的实例)。

任何人都可以解释一下吗?

您只需要将返回的类型限制为使用 Singleton 属性注释的类型:

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies()
        .Where(t => t.GetCustomAttributes<SingletonAttribute>(true).Any()),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.ContainerControlled);

您可以注册所有内容,然后使用 ContainerControlledLifetimeManager:

覆盖任何单例的注册
// Register All Types by Convention by default
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.Transient);

// Overwrite All Types marked as Singleton
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies()
        .Where(t => t.GetCustomAttributes<SingletonAttribute>(true).Any()),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.ContainerControlled,
    null,
    true); // Overwrite existing mappings without throwing