本文不介绍IoC和DI的概念,如果你对Ioc之前没有了解的话,建议先去搜索一下相关的资料

这篇文章将简单介绍一下AutoFac的基本使用以及在asp .net core中的应用

Autofac介绍

组件的三种注册方式

  1. 反射
  2. 现成的实例(new)
  3. lambda表达式 (一个执行实例化对象的匿名方法)

下面是一些简短的示例,我尽可能多的列出来一些常用的注册方式,同时在注释中解释下“组件”、“服务”等一些名词的含义

// 创建注册组件的builder
var builder = new ContainerBuilder(); //根据类型注册组件 ConsoleLogger 暴漏服务:ILogger
builder.RegisterType<ConsoleLogger>().As<ILogger>(); //根据类型注册组件 ConsoleLogger,暴漏其实现的所有服务(接口)
builder.RegisterType<ConsoleLogger>().AsImplementedInterfaces(); // 根据实例注册组件 output 暴漏服务:TextWriter
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>(); //表达式注册组件,这里我们是在构造函数时传参->"musection" 暴漏服务:IConfigReader
builder.Register(c =new ConfigReader("mysection")).As<IConfigReader>(); //表达式注册组件,解析时传参
var service = scope.Resolve<IConfigReader>(
new NamedParameter("section", "mysection")); //反射注册组件,直接注册了ConsoleLogger类(必须是具体的类),如果ConsoleLogger有多个构造函数,将会取参数最多的那个构造函数进行实例化
builder.RegisterType<ConsoleLogger>(); //反射注册组件,手动指定构造函数,这里指定了调用 MyComponent(ILogger log,IConfigReader config)的构造函数进行注册
builder.RegisterType<MyComponent>()
.UsingConstructor(typeof(ILogger), typeof(IConfigReader)); //注册MySingleton类中的静态变量"Instance",ExternallyOwned()函数指定自己控制实例的生命周期,而不是由autofac自动释放
builder.RegisterInstance(MySingleton.Instance).ExternallyOwned(); //一个组件暴漏两个服务
builder.RegisterType<CallLogger>().As<ILogger>().As<ICallInterceptor>(); //注册当前程序集中以“Service”结尾的类
builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces();
//注册"MyApp.Repository"程序集中所有的类
builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces(); //构建一个容器完成注册
var rootcontainer = builder.Build(); //可以通过下面这种方式手动获取IConfigReader 的实现类
//这种手动解析的方式需要 从生命周期作用域内获取组件,以保证组件最终被释放
//不要直接从根容器rootcontainer中解析组件,很有可能会导致内存泄漏
using(var scope = rootcontainer.BeginLifetimeScope())
{
var reader = scope.Resolve<IConfigReader>();
}

如果不止一个组件暴露了相同的服务, Autofac将使用最后注册的组件作为服务的提供方。 想要覆盖这种行为, 在注册代码后使用 PreserveExistingDefaults() 方法修改

生命周期

using(var scope = rootcontainer.BeginLifetimeScope())

上面的这段代码创建了一个生命周期作用域

生命周期作用域是可释放的,在作用域内解析的组件一定要保证在using之内使用或者最后手动调用组件的Dispose()函数

避免引用类的生命周期大于被引用类的生命周期 :如service 引用 repository 如果service的生命周期为单例,repository的生命周期为perrequest。service不会释放,所以最终会造成相关的repository始终无法释放的情况(Captive Dependencies

虽然我们需要尽可能的避免直接从根容器解析组件,但总有例外的情况,对于非单例的组件,一定不要忘记调用组件的Dispose函数,实际上对于非单例的组件,从项目架构上来说,理论上应该是从构造函数注入进去的而不是手动解析。 需要手动解析的应该为一些配置帮助类等

对于一个具体组件(类)的生命周期分为以下几种(后面的函数是autofac对应的函数):

  • 每个依赖一个实例(Instance Per Dependency) (默认) ----InstancePerDependency()
  • 单一实例(Single Instance) 单例 ----SingleInstance()
  • 每个生命周期作用域一个实例(Instance Per Lifetime Scope)----InstancePerLifetimeScope()
  • 每个匹配的生命周期作用域一个实例(Instance Per Matching Lifetime Scope)----InstancePerMatchingLifetimeScope()
  • 每个请求一个实例(Instance Per Request) asp.net web请求----InstancePerRequest()
  • 每次被拥有一个实例(Instance Per Owned) ----InstancePerOwned()

如果你以前在传统的ASP.NET MVC项目中用过autofac,需要注意一些区别:

  • .net Core中需要使用InstancePerLifetimeScope替代之前(传统asp.net)的InstancePerRequest,保证每次HTTP请求只有唯一的依赖实例被创建。InstancePerRequest请求级别已经不存在了
  • .net Core中Web Api与Mvc的注册方式一样
  • .net Core中不再需要注册控制器,控制器由.net core创建,不归autofac管理(除了控制器的构造函数),这也解释了为什么不再使用InstancePerRequest生命周期,但是可以通过AddControllersAsServices()函数改变,想要深入了解的可以查看:https://www.strathweb.com/2016/03/the-subtle-perils-of-controller-dependency-injection-in-asp-net-core-mvc/

AutoFac 在asp .net core中的使用

在.net core 中使用autofac还是比较简单的,相比于传统的asp.net web 项目,省去了很多步骤

引入nuget程序包:

  • Autofac
  • Autofac.Extensions.DependencyInjection

startup 中代码:

    public static IContainer AutofacContainer;
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//注册服务进 IServiceCollection
services.AddMvc();
ContainerBuilder builder = new ContainerBuilder();
//将services中的服务填充到Autofac中.
builder.Populate(services);
//新模块组件注册
builder.RegisterModule<DefaultModuleRegister>();
//创建容器.
AutofacContainer = builder.Build();
//使用容器创建 AutofacServiceProvider
return new AutofacServiceProvider(AutofacContainer);
}

上面代码调用了builder的RegisterModule函数,这个函数需要传入一个TModule的泛型,称之为autofac的模块

模块的功能就是把所有相关的注册配置都放在一个类中,使代码更易于维护和配置,下面展示了DefaultModuleRegister中的代码

DefaultModuleRegister:

public class DefaultModuleRegister : Module
{
protected override void Load(ContainerBuilder builder)
{
//注册当前程序集中以“Ser”结尾的类,暴漏类实现的所有接口,生命周期为PerLifetimeScope
builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Ser")).AsImplementedInterfaces().InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerLifetimeScope();
//注册所有"MyApp.Repository"程序集中的类
//builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces();
} public static Assembly GetAssembly(string assemblyName)
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(AppContext.BaseDirectory + $"{assemblyName}.dll");
return assembly;
}
}

Configure函数中可以选择性的加上程序停止时Autofac的释放函数:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
} app.UseStaticFiles(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//程序停止调用函数
appLifetime.ApplicationStopped.Register(() => { AutofacContainer.Dispose(); });
}

Controller中代码:

    private IUserSer _user;
private IUserSer _user2;
public HomeController(IUserSer user, IUserSer user2)
{
_user = user;
_user2 = user2;
}
public IActionResult Index()
{
using (var scope = Startup.AutofacContainer.BeginLifetimeScope())
{
IConfiguration config = scope.Resolve<IConfiguration>();
IHostingEnvironment env = scope.Resolve<IHostingEnvironment>();
}
string name = _user.GetName();
string name2 = _user2.GetName();
return View();
}

可以看到,因为我们将IServiceCollection中的服务填充到了autofac中了,所以现在可以在任何位置通过AutoFac解析出来.net core默认注入的服务(IConfiguration,IHostingEnvironment等)了

正常项目使用中,我们应该将AutofacContainer放在一个公共的类库中以便各个工程均可调用

.Net Core 学习之路-AutoFac的使用的更多相关文章

  1. .Net Core 学习之路-基础

    .Net Core出来好久了,一直在了解,但始终没有应用到实际项目中.... 准备用.net core搞个SSO,才发现它和.net framework的变化并不是一点点... .net core还在 ...

  2. .NET Core学习之路

    1.NET Core环境搭建 安装.NET Core: .NET Core 包括.NET Core Runtime 和 .NET Core SDK: NET Core = 应用运行依赖的 .NET C ...

  3. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  4. .NET Core 学习资料精选:入门

    开源跨平台的.NET Core,还没上车的赶紧的,来不及解释了-- 本系列文章,主要分享一些.NET Core比较优秀的社区资料和微软官方资料.我进行了知识点归类,让大家可以更清晰的学习.NET Co ...

  5. [原创]java WEB学习笔记54:Struts2学习之路---概述,环境的搭建

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  6. OpenGL学习之路(一)

    1 引子 虽然是计算机科班出身,但从小对几何方面的东西就不太感冒,空间想象能力也较差,所以从本科到研究生,基本没接触过<计算机图形学>.为什么说基本没学过呢?因为好奇(尤其是惊叹于三维游戏 ...

  7. OpenGL学习之路(四)

    1 引子 上次读书笔记主要是学习了应用三维坐标变换矩阵对二维的图形进行变换,并附带介绍了GLSL语言的编译.链接相关的知识,之后介绍了GLSL中变量的修饰符,着重介绍了uniform修饰符,来向着色器 ...

  8. OpenGL学习之路(五)

    1 引子 不知不觉我们已经进入到读书笔记(五)了,我们先对前四次读书笔记做一个总结.前四次读书笔记主要是学习了如何使用OpenGL来绘制几何图形(包括二维几何体和三维几何体),并学习了平移.旋转.缩放 ...

  9. springboot 学习之路 4(日志输出)

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

随机推荐

  1. Java几种建立实例的方法

    1.new something obj=new something();   2.clone 根据现有的对象实例来建立里一个新对象实例. 只限于实现了java.lang.Cloneable接口的类.否 ...

  2. Java多线程:线程池

    一. 背景 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池可以对线程进行统一的分配.调优和监控,并有以下好处:     第一:降低资源消耗.通过重复利用已 ...

  3. linux下安装Sublime Text3并将它的快捷方式放进启动器中

    Sublime Text是一个代码编辑器,我主要是用它来编辑python.下面就来简单说明下它在linux的安装过程吧! 1.添加sublime text3的仓库 首先按下快捷键ctrl+alt+t打 ...

  4. Factorials

    Factorials 阶乘 题目大意:给你一个数n,求出n ! 的最后一个非零位. 注释:n<=4200 想法:开始的想法是觉得这道题应该比较的有趣,因为我们知道,一个数的阶乘的最后的非零位后面 ...

  5. BLESS学习笔记

    BLESS全称:Bloom-filter-based Error Correction Solution for High-throughput Sequencing Reads,即基于布隆过滤器的高 ...

  6. Beta冲刺第二天

    一.昨天的困难 没困难 二.今天进度 局部测试并修复出现的bug 1.林洋洋:修复登录页面显示问题,修复日程查询问题 2.黄腾达:修复创建协作开始时间和结束时间没做检验的问题 3.张合胜:修复页面内容 ...

  7. Linux下Apache服务的查看和启动

      cd到/etc/rc.d/init.d/目录,并列出该目录下的所有文件,看看是否有httpd   使用httpd -v查看已经安装的httpd的版本   使用rpm -qa | grep http ...

  8. JAVA_SE基础——35.static修饰成员函数

    在Java中适用static关键字修饰的方法称为静态方法. 声明静态方法的语法格式如下: 权限修饰符 static 数据类型 方法名(){ 方法体 } 静态方法 可以使用类名直接调用     类名.方 ...

  9. 机器学习中 K近邻法(knn)与k-means的区别

    简介 K近邻法(knn)是一种基本的分类与回归方法.k-means是一种简单而有效的聚类方法.虽然两者用途不同.解决的问题不同,但是在算法上有很多相似性,于是将二者放在一起,这样能够更好地对比二者的异 ...

  10. CentOS 7 GUI图形界面安装

    在此之前先获取root权限,进行以下命令: 1. 在命令行下输入下面的命令来安装Gnome包: yum groupinstall "GNOME Desktop" "Gra ...