本文不介绍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. pyrhon多进程操作初探

    linux系统中提供了fork函数进行进程的创建,这个接口在函数返回上比较特殊,有两个返回值,一个是子进程返回值为0,一个是父进程返回值,值大于0,表是子进程的ID.如果小于0.则表示接口出错. py ...

  2. python安装的时候报SSL连接错误的解决办法

    Collecting xlwt   Could not fetch URL https://pypi.python.org/simple/xlwt/: There was a problem conf ...

  3. dom4j 最常用最简单的用法(转)

    要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/目前最新dom4j包下载地址:http://nchc.dl.sourceforg ...

  4. SQLite学习手册(数据表和视图)

    如何列出SQLite数据库中的所有表 SQLite数据库中的信息存在于一个内置表sqlite_master中,在查询器中可以用 select * from sqlite_master 来查看,如果只要 ...

  5. 【WCF系列】(二)设计和实现服务协定

    设计和实现服务协定 WCF术语介绍 服务(Service):服务是一个构造,它公开一个或多个终结点,其中每个终结点都公开一个或多个服务操作. 终结点(EndPoint):终结点是用来发送或接收消息(或 ...

  6. hibernate框架学习笔记7:HQL查询、Criteria查询简介

    HQL查询:hibernate独有的查询语言 适用于不复杂的多表查询 示例: 实体类: package domain; public class Customer { private Long cus ...

  7. Alpha第四天

    Alpha第四天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  8. java unicode和字符串间的转换

    package ykxw.web.jyf; /** * Created by jyf on 2017/5/16. */ public class unicode { public static voi ...

  9. 直方图均衡化及matlab实现

    在处理图像时,偶尔会碰到图像的灰度级别集中在某个小范围内的问题,这时候图像很难看清楚.比如下图: 它的灰度级别,我们利用一个直方图可以看出来(横坐标从0到255,表示灰度级别,纵坐标表示每个灰度级别的 ...

  10. 不允许用(a+b)/2这种方式求两个数的均值;如下程序在Linux和32位集成开发环境中运行

    #define MAX(a,b) ((a)>(b)?(a):(b)) #include<stdio.h> int main() { int a = 10; int b = 20; i ...