一文读懂Asp.net core 依赖注入(Dependency injection)
<h2>一、什么是依赖注入</h2><ol>
<li>首先在Asp.net core中是支持依赖注入软件设计模式,或者说<span style="color: rgba(255, 0, 0, 1)"><strong>依赖注入是asp.net core的核心</strong></span>;</li>
<li>依赖注入(DI)和控制反转(IOC)基本是一个意思,因为说起来谁都离不开谁;或者可以说他们是同一个概念的不同角度描述;</li>
<li>软件设计原则中有一个依赖倒置原则(DIP),就是为了解耦;<strong><span style="color: rgba(255, 0, 0, 1)">高层模块不应该依赖于底层模块。二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象</span></strong>;而依赖注入是实现这种原则的方式之一;</li>
<li>举个现实中例子:小明去行政领一节5号电池,然后行政给了小明一节黑象牌5号电池来分析 ;</li>
<ol>
<li>小明只需要向行政领一节5号电池即可,小明不需要关心什么牌子的电池,电池从哪来的,电池的价格等等。他们俩共同需要关心的是一节5号电池即可;</li>
<li>即使后期行政给了小明北孚电池,小明仍可以正常使用;他们只需要满足一个规则(5号电池)即可;</li>
<li>小明(高层模块)不应该依赖黑象牌电池(低层模块),两者应该都依赖5号电池(抽象)。</li>
<li>如果小明直接获取到(new)黑象牌电池,如果后期业务变更提供的是北孚电池,那么我们就需要更改小明的代码;再如果公司有几百个小明,代码量可想而知;</li>
<li>为了解决直接获取(new)黑象牌电池,简单说为了解耦,我们让每位员工通过行政领取(构造函数,属性,方法等),这种即使更改其他品牌,而小明压根不需要关心;</li>
</ol>
<li>举个.Net core中的例子:.Net core中使用分布式缓存;<br><br><ol>
<li>我们只需要在构造函数中获取<strong>IDistributedCache</strong>,然后就可以在方法中直接使用缓存,我们不需要关心缓存的实现方式,存储位置等等;</li>
<li>如果缓存从内存变成Redis或者sqlserver,甚至自己实现缓存,而我们只需要在ConfigureServices中更改具体实现方式即可,而不需要更改任何使用缓存的地方;</li>
</ol></li>
</ol>
<h2> </h2>
<h2>二、Asp.net core中依赖注入的生命周期</h2>
<p>依赖注入的生命周期有三种<span>Transient,<span>Scoped和<span>Singleton;</span></span></span></p>
<p><span><span><span>1、Transient每次调用都是不同的实例,比如常用的Microsoft.Extensions.Options.IConfigureOptions<T>;</span></span></span></p>
<p><span><span><span>2、Scoped每次请求是同一个实例,如 Entity Framework contexts;</span></span></span></p>
<p><span><span><span>3、Singleton只有一个实例,如Microsoft.Extensions.Logging.ILogger<T>;</span></span></span></p>
<p><span><span><span>具体使用哪种,要根据具体情况而定;</span></span></span></p>
<p><span><span><span>1、比如我们一般的业务逻辑都是Transient,这个也是比较常用的;</span></span></span></p>
<p><span><span><span>2、Scoped相对用的比较少,当然也有很多业务逻辑也有用Scoped的;当然他的妙用肯定是每次请求一个实例,比如我们在系统中获取登录系统用户的Id,这时就可以用Scoped,不管在Service层或者Repository层等等,获取的都是同一个用户;</span></span></span> </p>
<p>3、Singleton很多都是系统级别设计用单利,比如日志;</p>
<p> </p>
<h2>三、在Asp.net core中使用依赖注入</h2>
<p>基础业务逻辑代码,获取用户列表</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> IUserInfoService
{
IEnumerable</span><UserInfo><span style="color: rgba(0, 0, 0, 1)"> GetUserInfo();
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> UserInfoService : IUserInfoService
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> IEnumerable<UserInfo><span style="color: rgba(0, 0, 0, 1)"> GetUserInfo()
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 模拟db获取数据</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> List<UserInfo> { <span style="color: rgba(0, 0, 255, 1)">new</span> UserInfo { Id = <span style="color: rgba(128, 0, 128, 1)">1</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Emrys</span><span style="color: rgba(128, 0, 0, 1)">"</span> }, <span style="color: rgba(0, 0, 255, 1)">new</span> UserInfo { Id = <span style="color: rgba(128, 0, 128, 1)">2</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">梅林</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> } };
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> UserInfoMongoService : IUserInfoService
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> IEnumerable<UserInfo><span style="color: rgba(0, 0, 0, 1)"> GetUserInfo()
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 模拟Mongodb获取数据</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> List<UserInfo> { <span style="color: rgba(0, 0, 255, 1)">new</span> UserInfo { Id = <span style="color: rgba(128, 0, 128, 1)">1</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Emrys</span><span style="color: rgba(128, 0, 0, 1)">"</span> }, <span style="color: rgba(0, 0, 255, 1)">new</span> UserInfo { Id = <span style="color: rgba(128, 0, 128, 1)">2</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">梅林</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> } };
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> UserInfo
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Id { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}</span></pre>
</div>
<p> </p>
<h3>1、传统方式</h3>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ValuesController : ControllerBase
{
<span style="color: rgba(255, 0, 0, 1)"><strong> IUserInfoService _userInfoService </strong></span></span><span style="color: rgba(255, 0, 0, 1)"><strong>= new</strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"><strong> UserInfoService();</strong></span>
</span><span style="color: rgba(0, 0, 255, 1)">public</span> IEnumerable<UserInfo><span style="color: rgba(0, 0, 0, 1)"> Get()
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> _userInfoService.GetUserInfo();
}
}</span></pre>
</div>
<p>在传统方式中,获取用户的服务类直接用new的方式,这也是很多初学者或者很多老手最经常使用的方式;从中可以发现代码耦合度太高,非常不利于维护,在所有使用到IUserInfoService的地方都要new出对象;</p>
<p>如果后期需求变更,需要替换IUserInfoService的实现,比如从Mongodb中获取数据(现实示例中,从黑象牌变成北孚电池),那么就需要在所有new出UserInfoService的地方更改代码换成UserInfoMongoService,IUserInfoService _userInfoService = new UserInfoMongoService();</p>
<p>我们如果需要new的对象需要实现单例模式(Singleton),每次请求new一个对象(Scoped)模式,那么还要另写代码实现;</p>
<p> </p>
<h3> 2、依赖注入方式</h3>
<h4>1、在Startup类的ConfigureServices方法中设置注入</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> ConfigureServices(IServiceCollection services)
{
<span style="color: rgba(255, 0, 0, 1)"><strong> services.AddTransient</strong></span></span><span style="color: rgba(255, 0, 0, 1)"><strong><IUserInfoService, UserInfoService></strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"><strong>();</strong> </span>
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}</span></pre>
</div>
<h4> 2、在构造函数中获取实例</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ValuesController : ControllerBase
{
IUserInfoService _userInfoService;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> ValuesController(<span style="color: rgba(255, 0, 0, 1)"><strong>IUserInfoService userInfoService</strong></span>)
{
_userInfoService </span>=<span style="color: rgba(0, 0, 0, 1)"> userInfoService;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> IEnumerable<UserInfo><span style="color: rgba(0, 0, 0, 1)"> Get()
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> _userInfoService.GetUserInfo();
}
}</span></pre>
</div>
<p>在使用依赖注入方式时,解决了传统方式耦合度,如果后期变更实现,只要在 <strong>services.AddTransient<IUserInfoService, <span style="color: rgba(255, 0, 0, 1)"><strong>UserInfoService</strong></span>>();</strong>变更成<strong><span style="color: rgba(255, 0, 0, 1)">UserInfoMongoService</span></strong>即可;</p>
<p>在所有使用<strong>IUserInfoService</strong>的地方无须做任何改动;而且可以非常简单的设置生命周期(Transient,Scoped,Singleton);</p>
<p> </p>
<h2>四、总结</h2>
<p>1、设置注入和获取注入的方式不止一种,示例只是演示了最简单和最常用的使用方式,其他方式可以参考文档;</p>
<p>2、可以替换.net core中的默认注入容器, 如常用的autofac,可以实现更强大的功能;详情参考 https://autofac.org/;其他容器可以参考 https://github.com/aspnet/Extensions/tree/master/src/DependencyInjection</p>
<p>3、可以直接在View中获取注入 @inject IUserInfoService userInfoService</p>
<p>4、可以在httpcontext里直接获取注入HttpContext.RequestServices.GetService<IUserInfoService >();</p>
<p>5、Startup中的ConfigureServices方法就是为了设置注入而存在的;</p>
<p> </p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">记得推荐 ^_^</span></strong></p>
</div>
<div id="MySignature" role="contentinfo">
<div style="display: block" id="MySignature"><div style="display: block" id="MySignature"><p style="background: rgb(230, 250, 230); padding: 10px 10px 10px 10px; border: 1px dashed rgb(224, 224, 224); font-family: 微软雅黑; font-size: 13px; text-indent: 0">作者:Emrys
<br>
出处:http://www.cnblogs.com/emrys5/
<br>
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
</p></div></div><br><br>
来源:https://www.cnblogs.com/emrys5/p/aspnetcoredi.html
頁:
[1]