zoukankan      html  css  js  c++  java
  • .NET手记-Autofac进阶(注册的概念 Registering Concepts)

    通过创建ContainerBuilder并配置暴露的service(接口或者类型)来使用Autofac注册我们的组件。

    组件(Components) 可以通过反射, 对象实例,或者lambda表达式来创建. ContainerBuilder有一系列的Register()方法来实现组件的注册。

    ContainerBuilder中每个组件都能通过As()方法来暴露他们一个或多个service.

     

    // Create the builder with which components/services are registered.
    var builder = new ContainerBuilder();
    
    // Register types that expose interfaces...
    builder.RegisterType<ConsoleLogger>().As<ILogger>();
    
    // Register instances of objects you create...
    var output = new StringWriter();
    builder.RegisterInstance(output).As<TextWriter>();
    
    // Register expressions that execute to create objects...
    builder.Register(c => new ConfigReader("mysection")).As<IConfigReader>();
    
    // Build the container to finalize registrations
    // and prepare for object resolution.
    var container = builder.Build();
    
    // Now you can resolve services using Autofac. For example,
    // this line will execute the lambda expression registered
    // to the IConfigReader service.
    using(var scope = container.BeginLifetimeScope())
    {
      var reader = container.Resolve<IConfigReader>();
    }

    反射组件 Reflection Components

    通过类型注册

    通过反射生成组件最典型的方法是通过类型注册:

    var builder = new ContainerBuilder();
    builder.RegisterType<ConsoleLogger>();
    builder.RegisterType(typeof(ConfigReader));

    当使用基于反射的组件时,Autofac会自动使用容器中最可能获取到的参数来构造实例你的类

    例如,你的类有3个构造函数

    public class MyComponent
    {
        public MyComponent() { /* ... */ }
        public MyComponent(ILogger logger) { /* ... */ }
        public MyComponent(ILogger logger, IConfigReader reader) { /* ... */ }
    }

    现在使用如下方法注册你的组件:

    var builder = new ContainerBuilder();
    builder.RegisterType<MyComponent>();
    builder.RegisterType<ConsoleLogger>().As<ILogger>();
    var container = builder.Build();
    
    using(var scope = container.BeginLifetimeScope())
    {
      var component = container.Resolve<MyComponent>();
    }

    当你解析你的组件时,Autofac发现你已经注册了ILogger,但是没有注册IConfigReader。在这个例子中,第二个构造函数会被执行,因为容器中具有最符合的参数。

    注意:任何你注册的Type必须都是实类型,这意味着你不能直接注册抽象类或者接口。应为在解析组件时,对象可能会被new实例化,而接口或者抽象类是无法直接实例化的。

    指定构造函数 Specifying a Constructor

    你可以通过方法UsingConstructor手动指定使用哪个构造函数,其参数为指定构造函数的参数类型。

    var output = new StringWriter();
    builder.RegisterInstance(output).As<TextWriter>();

    注意你提供的参数必须能在容器中获取,不然会出现错误。

    实例组件 Instance Components

    在很多情况下,你可能想要预先生成对象实例并将它注册到容器中。你可以通过使用RegisterInstance方法来实现:

    var output = new StringWriter();
    builder.RegisterInstance(output).As<TextWriter>();

    当你这么做的时候,一些事情需要被考虑到。Autofac会自动处理对象的释放,但是你很可能想自己控制对象的生命周期,而不是让Autofac调用对象Dispose方法。在这种情况下,你需要使用ExternallyOwned方法:

    var output = new StringWriter();
    builder.RegisterInstance(output)
           .As<TextWriter>()
           .ExternallyOwned();

    当我们集成Autofac到现有项目中时,可能会存在容器中一些组件用到的对象的单例写法。RegisterInstance()也用来处理这种情况,你可以通过容器来注册它们,而不是直接使用它们:

    builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();

    这确保了单例最后会被排除,并使用容器托管的对象来替代他。

    表达式组件 Lambda Expression Components

    反射是创建组件相当好的默认选择,尽管当组件创建逻辑超出简单构造函数调用后,事情可能会变混乱。

    Autofac支持通过委托或者Lambda表达式来创建组件:

    builder.Register(c => new A(c.Resolve<B>()));

    提供的参数c是一个组件上下文对象(IComponentContext),在上下文中创建组件。你可以通过它从容器中解析出其他的值来辅助创建你的组件。使用它而不是使用闭包去访问容器是很重要的,为了层叠容器能够被正确支持。

    使用此上下文参数能够满足额外的依赖项。在这个例子中,类型A构造函数要求的B类型参数可能还会依赖其他类型参数。表达式创建的组件暴露的默认服务是通过表达式返回类型来推断的。

    下面会给出一些例子:

    复杂参数

    builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));

    属性注入

    builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));

    通过参数值选择实现方式

    builder.Register<CreditCard>(
      (c, p) =>
        {
          var accountId = p.Named<string>("accountId");
          if (accountId.StartsWith("9"))
          {
            return new GoldCard(accountId);
          }
          else
          {
            return new StandardCard(accountId);
          }
        });

    在这个例子中,CreditCard被两个类实现,分别是GoldenCard和StandardCard,哪种类型被实例取决于输入的卡号。

    参数通过可选构造参数p来传入,注册方式可能像这样:

    var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));

    范型组件 

    Autofac支持范型,通过使用RegisterGeneric()方法:

    builder.RegisterGeneric(typeof(NHibernateRepository<>))
           .As(typeof(IRepository<>))
           .InstancePerLifetimeScope();

    当一个匹配的Service类型被请求时,容器会自动映射它到一个相近的实现类型:

    // Autofac将会返回NHibernateRepository<Task>类型
    var tasks = container.Resolve<IRepository<Task>>();

    指定类型服务的注册将会覆盖掉范型版本。

    服务 vs 组件 Services vs. Components

    当注册组件时,我们需要告诉Autofac组件暴露了哪种服务。大多数情况下,会暴露组件自身的类型。

    // This exposes the service "CallLogger"
    builder.RegisterType<CallLogger>();

    组件仅能被其暴露的服务来解析出实例,这就意味着如下:

    // This will work because the component
    // exposes the type by default:
    scope.Resolve<CallLogger>();
    
    // 这个将会失败
    // tell the registration to also expose
    // the ILogger interface on CallLogger:
    scope.Resolve<ILogger>();

    你也可以使用任何数量的服务来暴露你的组件:

    builder.RegisterType<CallLogger>()
           .As<ILogger>()
           .As<ICallInterceptor>();

    你可以通过你暴露的服务来解析出组件实例,但这同时意味着默认服务(组件自身类型)将被覆盖:

    // These will both work because we exposed
    // the appropriate services in the registration:
    scope.Resolve<ILogger>();
    scope.Resolve<ICallInterceptor>();
    
    // 失败
    // 默认服务被覆盖
    scope.Resolve<CallLogger>();

    如果你想为组件暴露一系列服务,同时自身类型仍然可用,你需要使用AsSelf方法:

    builder.RegisterType<CallLogger>()
           .AsSelf()
           .As<ILogger>()
           .As<ICallInterceptor>();

    现在所有服务均可以解析:

    // These will all work because we exposed
    // the appropriate services in the registration:
    scope.Resolve<ILogger>();
    scope.Resolve<ICallInterceptor>();
    scope.Resolve<CallLogger>();

    默认注册 Default Registrations

    如果有多个提供相同service的组件被注册,Autofac默认使用最后注册的组件。

    builder.Register<ConsoleLogger>().As<ILogger>();
    builder.Register<FileLogger>().As<ILogger>();

    在这个例子中,FileLogger将会成为ILogger的默认组件提供者,因为它是最后注册的。

    为了改写这种行为,使用PreserveExistingDefaults()来修改:

    builder.Register<ConsoleLogger>().As<ILogger>();
    builder.Register<FileLogger>().As<ILogger>().PreserveExistingDefaults();

    在这种情况下,ConsoleLogger将会成为默认组件提供者。

    配置文件注册 Configuration of Registrations

    你可以使用定义的XML或者代码模块(Module)来实现孕事批量注册或者更改。也可以使用Autofac modules进行一些动态注册生成或者条件注册逻辑。具体请看:http://autofac.readthedocs.org/en/latest/configuration/index.html

    动态注册 Dynamically-Provided Registrations

    Autofac modules是最简单的方式来引入动态注册逻辑或简单交叉特性。例如,你可以使用module动态地附加一个Log4net实例到解析出的一个service上。请看:http://autofac.readthedocs.org/en/latest/examples/log4net.html

  • 相关阅读:
    MATLAB矩阵操作【z】
    matlab绘图方法[z]
    Drawhere 有趣的网页涂鸦工具【z】
    DemoHelper,针对电脑演示的小工具
    Matlab Matrix [z]
    MATLAB函数参考[z]
    计算几何常用算法概览[z]
    matlab命令行环境的常用操作[z]
    不常见数学符号或简写
    matlab加入上级路径和本级路径的方法
  • 原文地址:https://www.cnblogs.com/mantgh/p/5122284.html
Copyright © 2011-2022 走看看