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

本文关键字:自定义属性 类型 注册 IOC 何注册 Unity | 更新日期: 2023-09-27 18:37:22

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

这是我的 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 容器中使用生存期管理器注册了每个单一实例类型,如下所示:

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

但是,我想避免以这种方式将每个类型专门注册为单一实例,而是通过使用自定义 SingletonAttribute 标记它们来确定加载程序集中的哪些类型需要是单一实例,然后,如果可能,将它们集体注册。

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

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

并相应地标记了类定义:

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

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

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 的实例)。

谁能透露任何光芒?

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

你只需要将返回的类型约束为使用 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