【asp.net core 系列】14 .net core 中的IOC
0.前言
通过前面几篇,我们了解到了如何实现项目的基本架构:数据源、路由设置、加密以及身份验证。那么在实现的时候,我们还会遇到这样的一个问题:当我们业务类和数据源越来越多的时候,我们无法通过普通的构造对象的方法为每个实例进行赋值。同时,传统意义上的赋值遇到底层切换或者其他修改的时候,就需要修改大量的代码,对改变不友好。为了改变这种现状,我们基于面向接口编程,然后使用一些DI功能和IOC框架。
1. IOC和DI
先来给大家解释几个概念,IOC全称Inversion of Control,翻译过来就是控制反转,是面向对象编程的一种设计原则,用来降低代码之间的耦合度。所谓的控制反转简单来讲就是将类中属性或者其他参数的初始化交给其他方处理,而不是直接使用构造函数。
public class Demo1
{
}
public class Demo2
{
public Demo1 demo;
}
对于以上简单示例代码中,在Demo2类中持有了一个Demo1的实例。如果按照之前的情况来讲,我们会通过以下方法为demo赋值:
// 方法一
public Demo1 demo = new Demo1();
// 方法二
public Demo2()
{
demo = new Demo1();
}
这时候,如果Demo1变成下面的样子:
public class Demo1
{
public Demo1(Demo3 demo3)
{
// 隐藏
}
}
public class Demo3
{
}
那么,如果Demo2 没有持有一个Demo3的实例对象,这时候创建Demo1的时候就需要额外构造一个Demo3。如果Demo3需要持有另外一个类的对象,那么Demo2中就需要多创建一个对象。最后就会发现这样就陷入了一个构造“地狱”(我发明的词,指这种为了一个对象却得构造一大堆其他类型的对象)。
实际上,对于Demo2并不关心Demo1的实例对象是如何获取的,甚至都不关心它是不是Demo1的子类或者接口实现类。我在示例中使用了类,但这里可以同步替换成Interface,替换之后,Demo2在调用Demo1的时候,还需要知道Demo1有实现类,以及实现类的信息。
为了解决这个问题,一些高明的程序员们提出了将对象的创建这一过程交给第三方去操作,而不是调用类来创建。于是乎,上述代码就变成了:
public class Demo2
{
public Demo1 Demo {get;set;}
public Demo2(Demo1 demo)
{
Demo = demo;
}
}
似乎并没有什么变化?对于Demo2来说,Demo2从此不再负责Demo1的创建,这个步骤交由Demo2的调用方去创建,Demo2从此从负责维护Demo1这个对象的大麻烦中解脱了。
但实际上构造地狱的问题还是没有解决,只不过是通过IOC的设计将这一步后移了。这时候,那些大神们想了想,不如开发一个框架这些实体对象吧。所以就出现了很多IOC框架:AutoFac、Sping.net、Unity等。
说到IOC就不得不提一下DI(Dependency Injection)依赖注入。所谓的依赖注入就是属性对应实例通过构造函数或者使用属性由第三方进行赋值。也就是最后Demo2的示例代码中的写法。
早期IOC和DI是指一种技术,后来开始确定这是不同的描述。IOC描述的是一种设计模式,而DI是一种行为。
2. 使用asp.net core的默认IOC
在之前的ASP.NET 框架中,微软并没有提供默认的IOC支持。在最新的asp.net core中微软提供了一套IOC支持,该支持在命名空间:
Microsoft.Extensions.DependencyInjection
里,在代码中引用即可。
主要通过以下几组方法实现:
public static IServiceCollection AddScoped<TService>(this IServiceCollection services) where TService : class;
public static IServiceCollection AddSingleton<TService>(this IServiceCollection services) where TService : class;
public static IServiceCollection AddTransient<TService>(this IServiceCollection services) where TService : class;
这里只列出了这三组方法的一种重载版本。
这三组方法分别代表三种生命周期:
- AddScored 表示对象的生命周期为整个Request请求
- AddTransient 表示每次从服务容器进行请求时创建的,适合轻量级、 无状态的服务
- AddSingleton 表示该对象在第一次从服务容器请求后获取,之后就不会再次初始化了
这里每组方法只介绍了一个版本,但实际上每个方法都有以下几个版本:
public static IServiceCollection AddXXX<TService>(this IServiceCollection services) where TService : class;
public static IServiceCollection AddXXX(this IServiceCollection services, Type serviceType, Type implementationType);
public static IServiceCollection AddXXX(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory);
public static IServiceCollection AddXXX<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService;
public static IServiceCollection AddXXX(this IServiceCollection services, Type serviceType);
public static IServiceCollection AddXXX<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class;
public static IServiceCollection AddXXX<TService, TImplementation>(this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory)
where TService : class
where TImplementation : class, TService;
其中:implementationFactory 表示通过一个Provider实现TService/TImplementation 的工厂方法。当方法指定了泛型的时候,会自动依据泛型参数获取要注入的类型信息,如果没有使用泛型则必须手动传入参数类型。
asp.net core如果使用依赖注入的话,需要在Startup方法中设置,具体内容可以参照以下:
public void ConfigureServices(IServiceCollection services)
{
//省略其他代码
services.AddScoped<ISysUserAuthRepository,SysUserAuthRepository>();
}
asp.net core 为DbContext提供了不同的IOC支持,AddDbContext:
public static IServiceCollection AddDbContext<TContext>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder> optionsAction = null,
ServiceLifetime contextLifetime = ServiceLifetime.Scoped,
ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
where TContext : DbContext;
使用方法如下:
services.AddDbContext<DefaultContext>();
3. AutoFac 使用
理论上,asp.net core的IOC已经足够好了,但是依旧原谅我的贪婪。如果有二三百个业务类需要我来设置的话,我宁愿不使用IOC。因为那配置起来就是一场极其痛苦的过程。不过,可喜可贺的是AutoFac可以让我免收这部分的困扰。
这里简单介绍一下如何使用AutoFac作为IOC管理:
cd Web # 切换目录到Web项目
dotnet package add Autofac.Extensions.DependencyInjection # 添加 AutoFac的引用
因为asp.net core 版本3更改了一些逻辑,AutoFac的引用方式发生了改变,现在不介绍之前版本的内容,以3为主。使用AutoFac需要先在 Program类里设置以下代码:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory()) // 添加这行代码
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
在Program类里启用AutoFac的一个Service提供工厂类。然后在Startup类里添加如下方法:
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterType<DefaultContext>().As<DbContext>()
.WithParameter("connectStr","Data Source=./demo.db")
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(Assembly.Load("Web"))
.Where(t => t.BaseType.FullName.Contains("Filter"))
.AsSelf();
builder.RegisterAssemblyTypes(Assembly.Load("Domain"),
Assembly.Load("Domain.Implements"), Assembly.Load("Service"), Assembly.Load("Service.Implements"))
.AsSelf()
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.PropertiesAutowired();
}
修改:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Filters.Add<UnitOfWorkFilterAttribute>();
}).AddControllersAsServices();// 这行新增
// 省略其他
}
4. 总结
这一篇简单介绍了如何在Asp.net Core中启用IOC支持,并提供了两种方式,可以说是各有优劣。小伙伴们根据自己需要选择。后续会为大家详细深入AutoFac之类IOC框架的核心秘密。
更多内容烦请关注我的博客《高先生小屋》

【asp.net core 系列】14 .net core 中的IOC的更多相关文章
- asp.net core 系列 14 错误处理
一.概述 本文介绍处理 ASP.NET Core 应用中常见错误的一些方法.主要是关于:开发环境异常页:非开发环境配置自定义异常处理页:配置状态代码页(没有正文响应,http状态400~599的). ...
- asp.net core系列 50 Identity 授权(中)
1.5 基于策略的授权 在上篇中,已经讲到了授权访问(authorization)的四种方式.其中Razor Pages授权约定和简单授权二种方式更像是身份认证(authentication) ,因为 ...
- ASP.NET MVC系列:web.config中ConnectionString aspnet_iis加密与AppSettings独立文件
1. web.config中ConnectionString aspnet_iis加密 web.config路径:E:\Projects\Libing.Web\web.config <conne ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 拥抱.NET Core系列:MemoryCache 缓存过期
在上一篇"拥抱.NET Core系列:MemoryCache 初识"中我们基本了解了缓存的添加.删除.获取,那么今天我们来看看缓存的过期机制.这里和上篇一样将把"Micr ...
- 拥抱.NET Core系列:MemoryCache 缓存过期 (转载)
阅读目录 MSCache项目 MSCache提供的过期方式 绝对时间到期 滑动时间到期 自定义过期策略 过期策略组合拳 缓存过期回调 写在最后 在上一篇”拥抱.NET Core系列:MemoryCac ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)
Ajax跨域问题及解决方案 目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...
- 探索ASP.Net Core 3.0系列四:在ASP.NET Core 3.0的应用中启动时运行异步任务
前言:在本文中,我将介绍ASP.NET Core 3.0 WebHost的微小更改如何使使用IHostedService在应用程序启动时更轻松地运行异步任务. 翻译 :Andrew Lock ht ...
随机推荐
- Rocket - subsystem - CrossingWrapper
https://mp.weixin.qq.com/s/3-MfNJDCIgOBqUbf4fuerQ 简单介绍CrossingWrapper的实现. 1. CrossesToOnlyOneClockDo ...
- Sublime Text3 注册码(Windows/Build 3176版本)| 开发工具
转自:dushusir.com 1.修改hosts文件(路径:C:\Windows\System32\drivers\etc): 0.0.0.0 www.sublimetext.com 0.0.0.0 ...
- (Java实现) 营救
问题 B: 营救 时间限制: 1 Sec 内存限制: 128 MB 题目描述 铁塔尼号遇险了!他发出了求救信号.距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里. 通过侦测,哥伦比亚号获 ...
- Java实现 蓝桥杯VIP 算法训练 阿尔法乘积
蓝桥杯–阿尔法乘积 问题描述 计算一个整数的阿尔法乘积.对于一个整数x来说,它的阿尔法乘积是这样来计算的:如果x是一个个位数,那么它的阿尔法乘积就是它本身:否则的话,x的阿尔法乘积就等于它的各位非0的 ...
- Java实现 蓝桥杯VIP 算法训练 奇偶判断
问题描述 能被2整除的数称为偶数,不能被2整除的数称为奇数.给一个整数x,判断x是奇数还是偶数. 输入格式 输入包括一个整数x,0<=x<=100000000. 输出格式 如果x是奇数,则 ...
- Java实现 LeetCode 260 只出现一次的数字 III(三)
260. 只出现一次的数字 III 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次. 找出只出现一次的那两个元素. 示例 : 输入: [1,2,1,3,2,5] 输出 ...
- Java中List,Set,Map的区别以及API的使用
1.面试题:你说说collection里面有什么子类. (其实面试的时候听到这个问题的时候,你要知道,面试官是想考察List,Set) 正如图一,list和set是实现了collection接口的. ...
- 【工作Vlog】Jmeter响应结果乱码解决方案
资料:https://blog.51cto.com/ydhome/1864340 方法一:使用后置控制器"Beanshell PostProcessor"(动态修改,灵活) 添加后 ...
- nginx功能介绍和基本安装
一.简介 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外ngi ...
- 4.vue class 绑定- model基础应用
//代码可以复制自行体验 <template> <div id="app" @click.stop="test('你点击了我big- ...