Unity Container 中基于 Marker 接口注册接口到不同的 Lifetime

Posted

技术标签:

【中文标题】Unity Container 中基于 Marker 接口注册接口到不同的 Lifetime【英文标题】:Register Interface in Unity Container based on Marker interface into different Lifetime 【发布时间】:2017-07-13 00:20:01 【问题描述】:

我的解决方案中有多个项目:

Core
Repository
Service
WebAPi

我的 Unity 注册在 WebAPi 项目上。

我想要实现的是我过去在温莎城堡做过的事情,现在我想通过 Unity 做到这一点:使用约定注册接口https://github.com/castleproject/Windsor/blob/master/docs/registering-components-by-conventions.md

我有两个标记接口。

public interface ISingletonDependency
public interface ITransientDependency

对于我的存储库或服务中的类,我这样做:

public interface IPersonRepository:ISingletonDependency
...
...



public class PersonRepository: IPersonRepository
...
...
...

在我的服务类中:

public interface IPersonService:ISingletonDependency
...
...    


public class PersonService: IPersonService
...
...
...

我为我所有的课程都以类似的方式为 DI 这样做,并且在注册期间我曾经这样做:

container.Register(
    Classes.NamedAssembly("SolutionName.Repository")
        .BasedOn<ISingletonDependency>()
        .WithService.FromInterface().LifestyleSingleton()
);


container.Register(
    Classes.NamedAssembly("SolutionName.Service")
        .BasedOn<ISingletonDependency>()
        .WithService.FromInterface().LifestyleSingleton()
);


container.Register(
    Classes.NamedAssembly("SolutionName.Repository")
        .BasedOn<ITransientDependency>()
        .WithService.FromInterface().LifestyleTansient()
);


container.Register(
    Classes.NamedAssembly("SolutionName.Service")
        .BasedOn<ITransientDependency>()
        .WithService.FromInterface().LifestyleTansient()
);

这样我不需要为每个人都这样做,我在 Unity 中看到了方法,但它确实基于命名约定 而且你不能单独指定单身或短暂的生活方式。

https://blogs.msdn.microsoft.com/agile/2013/03/12/unity-configuration-registration-by-convention/

有没有一种方法可以根据标记界面完成您在温莎城堡中可以做的事情,就像我上面给出的示例一样?

【问题讨论】:

i have done in Castle windsor in past, now i want to do that via Unity... - 你为什么要从一个完全支持的 DI 容器转移到一个 dead 容器? Unity 是no longer supported,即使它在功能上也远远落后。 Microsoft gave up support for it,但新所有者也不关心支持它 - 一年半没有提交。 @NightOwl888 的评论 +100 :) 【参考方案1】:

给定:

public interface ISingletonDependency  
public interface ITransientDependency  

public interface IPersonRepository : ISingletonDependency  
public class PersonRepository : IPersonRepository  

public interface IPersonService : ITransientDependency  
public class PersonService : IPersonService  

然后您可以使用以下方法注册类型:

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromAssembliesInBasePath().Where(
        // Could also match on namespace etc. here
        t => t.Assembly.GetName().Name.StartsWith("SolutionName")),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.FromMarkerInterface);

// Singleton
Debug.Assert(ReferenceEquals(container.Resolve<IPersonRepository>(), container.Resolve<IPersonRepository>()));

// Transient
Debug.Assert(!ReferenceEquals(container.Resolve<IPersonService>(), container.Resolve<IPersonService>()));

WithLifetime.FromMarkerInterface 是一个自定义约定,它使用标记界面来选择正确的LifetimeManager

public static class WithLifetime

    public static LifetimeManager FromMarkerInterface(Type type)
    
        if (typeof(ISingletonDependency).IsAssignableFrom(type))
        
            return new ContainerControlledLifetimeManager();
        

        return new TransientLifetimeManager();
    

在这种情况下,除非是 ISingletonDependency,否则一切都是暂时的,但您可以使规则更加明确(例如,如果找不到有效的标记接口,则抛出)。

如果您可以缩小 AllClasses.FromAssembliesInBasePath().Where 中的 where 子句,那么您可能会使用一个衬里:

container.RegisterTypes(
AllClasses.FromAssembliesInBasePath().Where(
    t => t.Namespace.StartsWith("SolutionName.Repository") || 
         t.Namespace.StartsWith("SolutionName.Service")),
    WithMappings.FromMatchingInterface,
    WithName.Default,
    WithLifetime.FromMarkerInterface);

【讨论】:

以上是关于Unity Container 中基于 Marker 接口注册接口到不同的 Lifetime的主要内容,如果未能解决你的问题,请参考以下文章

Unity IoC Container创建对象过程

Unity DI Container RegisterType 方法中断从 v5.8.x 到 v5.9.x 的更改

当SAP云平台account的service Marke place里找不到Machine Learning服务该怎么办

Spring IOC 系列:基于Java Code 配置Spring Container

Unity 依赖注入

Unity中基于网格/平铺移动+碰撞?