日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

core控制器属性注入的用处_了解ASP.NET Core 依赖注入,看这篇就够了

發布時間:2025/3/15 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 core控制器属性注入的用处_了解ASP.NET Core 依赖注入,看这篇就够了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DI在.NET Core里面被提到了一個非常重要的位置, 這篇文章主要再給大家普及一下關于依賴注入的概念,身邊有工作六七年的同事還個東西搞不清楚。另外再介紹一下.NET? Core的DI實現以及對實例生命周期的管理(這個是經常面試會問到的問題)。最后再給大家簡單介紹一下在控制臺以及Mvc下如何使用DI,以及如何把默認的Service Container?替換成Autofac。

一、什么是依賴注入

1.1 依賴

1.2 什么注入

為什么反轉

何為容器

二、.NET Core DI

2.1 實例的注冊

2.2 實例生命周期之單例

2.3 實例生命周期之Tranisent

2.4 實例生命周期之Scoped

三、DI在ASP.NET Core中的應用

3.1 在Startup類中初始化

3.2 Controller中使用

3.3 View中使用

3.4 通過HttpContext來獲取

四、如何替換其它的Ioc容器

一、什么是依賴注入(Denpendency Injection)

這也是個老身常談的問題,到底依賴注入是什么? 為什么要用它? 初學者特別容易對控制反轉IOC(Iversion of Control),DI等概念搞暈。

1.1依賴

當一個類需要另一個類協作來完成工作的時候就產生了依賴。比如我們在AccountController這個控制器需要完成和用戶相關的注冊、登錄 等事情。其中的登錄我們由EF結合Idnetity來完成,所以我們封裝了一個EFLoginService。這里AccountController就有一個ILoginService的依賴。

這里有一個設計原則:依賴于抽象,而不是具體的實現。所以我們給EFLoginService定義了一個接口,抽象了LoginService的行為。

1.2 什么是注入

注入體現的是一個IOC(控制反轉的的思想)。在反轉之前 ,我們先看看正轉。

AccountController自己來實例化需要的依賴。

private ILoginService _loginService;

public AccountController()

{

_loginService = new EFLoginService()

}

大師說,這樣不好。你不應該自己創建它,而是應該由你的調用者給你。于是你通過構造函數讓外界把這兩個依賴傳給你。

public AccountController(ILoginService loginService)

{

_loginService = loginService;

}

把依賴的創建丟給其它人,自己只負責使用,其它人丟給你依賴的這個過程理解為注入。

1.3 為什么要反轉?

為了在業務變化的時候盡少改動代碼可能造成的問題。

比如我們現在要把從EF中去驗證登錄改為從Redis去讀,于是我們加了一個 RedisLoginService。這個時候我們只需要在原來注入的地方改一下就可以了。

var controller = new AccountController(new EFLoginService());

controller.Login(userName, password);

// 用Redis來替換原來的EF登錄

var controller = new AccountController(new RedisLoginService());

controller.Login(userName, password);

1.4 何為容器

上面我們在使用AccountController的時候,我們自己通過代碼創建了一個ILoggingServce的實例。想象一下,一個系統中如果有100個這樣的地方,我們是不是要在100個地方做這樣的事情? 控制是反轉了,依賴的創建也移交到了外部。現在的問題是依賴太多,我們需要一個地方統一管理系統中所有的依賴,容器誕生了。

容器負責兩件事情:

綁定服務與實例之間的關系

獲取實例,并對實例進行管理(創建與銷毀)

二、.NET Core DI

2.1 實例的注冊

前面講清楚DI和Ioc的關鍵概念之后,我們先來看看在控制臺中對.NET Core DI的應用。在.NET Core中DI的核心分為兩個組件:IServiceCollection和 IServiceProvider。

IServiceCollection 負責注冊

IServiceProvider 負責提供實例

通過默認的 ServiceCollection(在Microsoft.Extensions.DependencyInjection命名空間下)有三個方法:

var serviceCollection = new ServiceCollection()

.AddTransient()

.AddSingleton()

.AddScoped();

這三個方法都是將我們的實例注冊進去,只不過實例的生命周期不一樣。什么時候生命周期我們下一節接著講。

ServiceCollection的默認實現是提供一個ServiceDescriptor的List

public interface IServiceCollection : IList

{

}

我們上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的擴展方法, 都是往這個List里面添加ServiceDescriptor。

private static IServiceCollection Add(IServiceCollection collection,

Type serviceType,

Type implementationType,

ServiceLifetime lifetime)

{

var descriptor =

new ServiceDescriptor(serviceType, implementationType, lifetime);

collection.Add(descriptor);

return collection;

}

2.2 實例的生命周期之單例

我們上面看到了,.NET Core DI 為我們提供的實例生命周其包括三種:

Transient: 每一次GetService都會創建一個新的實例

Scoped:? 在同一個Scope內只初始化一個實例 ,可以理解為( 每一個request級別只創建一個實例,同一個http request會在一個 scope內)

Singleton :整個應用程序生命周期以內只創建一個實例

對應了Microsoft.Extensions.DependencyInjection.ServiceLifetime的三個枚舉值

public enum ServiceLifetime

{

Singleton,

Scoped,

Transient

}

為了大家能夠更好的理解這個生命周期的概念我們做一個測試:

定義一個最基本的IOperation里面有一個 OperationId的屬性,IOperationSingleton也是一樣,只不過是另外一個接口。

public interface IOperation

{

Guid OperationId { get; }

}

public interface IOperationSingleton : IOperation { }

public interface IOperationTransient : IOperation{}

public interface IOperationScoped : IOperation{}

我們的 Operation實現很簡單,可以在構造函數中傳入一個Guid進行賦值,如果沒有的話則自已New一個 Guid。

public class Operation :

IOperationSingleton,

IOperationTransient,

IOperationScoped

{

private Guid _guid;

public Operation() {

_guid = Guid.NewGuid();

}

public Operation(Guid guid)

{

_guid = guid;

}

public Guid OperationId => _guid;

}

在程序內我們可以多次調用ServiceProvider的GetService方法,獲取到的都是同一個實例。

var services = new ServiceCollection();

// 默認構造

services.AddSingleton();

// 自定義傳入Guid空值

services.AddSingleton(

new Operation(Guid.Empty));

// 自定義傳入一個New的Guid

services.AddSingleton (

new Operation(Guid.NewGuid()));

var provider = services.BuildServiceProvider();

// 輸出singletone1的Guid

var singletone1 = provider.GetService();

Console.WriteLine($"signletone1: {singletone1.OperationId}");

// 輸出singletone2的Guid

var singletone2 = provider.GetService();

Console.WriteLine($"signletone2: {singletone2.OperationId}");

Console.WriteLine($"singletone1 == singletone2 ? : { singletone1 == singletone2 }");

我們對IOperationSingleton注冊了三次,最后獲取兩次,大家要注意到我們獲取到的始終都是我們最后一次注冊的那個給了一個Guid的實例,前面的會被覆蓋。

2.3 實例生命周期之Tranisent

這次我們獲取到的IOperationTransient為兩個不同的實例。

var services = new ServiceCollection();

services.AddTransient();

var provider = services.BuildServiceProvider();

var transient1 = provider.GetService();

Console.WriteLine($"transient1: {transient1.OperationId}");

var transient2 = provider.GetService();

Console.WriteLine($"transient2: {transient2.OperationId}");

Console.WriteLine($"transient1 == transient2 ? :

{ transient1 == transient2 }");

2.4 實例生命周期之Scoped

.NET Core人IServiceProvider提供CreateScope產生一個新的ServiceProvider范圍,在這個范圍下的Scope標注的實例將只會是同一個實例。換句話來說:用Scope注冊的對象,在同一個ServiceProvider的 Scope下相當于單例。

同樣我們先分別注冊IOperationScoped、IOperationTransient和IOperationSingletone 這三個實例,用對應的Scoped、Transient、和Singleton生命周期。

var services = new ServiceCollection()

.AddScoped()

.AddTransient()

.AddSingleton();

接下來我們用ServiceProvider.CreateScope方法創建一個Scope

var provider = services.BuildServiceProvider();

using (var scope1 = provider.CreateScope())

{

var p = scope1.ServiceProvider;

var scopeobj1 = p.GetService();

var transient1 = p.GetService();

var singleton1 = p.GetService();

var scopeobj2 = p.GetService();

var transient2 = p.GetService();

var singleton2 = p.GetService();

Console.WriteLine(

$"scope1: { scopeobj1.OperationId }," +

$"transient1: {transient1.OperationId}, " +

$"singleton1: {singleton1.OperationId}");

Console.WriteLine($"scope2: { scopeobj2.OperationId }, " +

$"transient2: {transient2.OperationId}, " +

$"singleton2: {singleton2.OperationId}");

}

接下來

scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,

transient1: fb35f570-713e-43fc-854c-972eed2fae52,

singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225

scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956,

transient2: 2766a1ee-766f-4116-8a48-3e569de54259,

singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225

如果再創建一個新的Scope運行,

scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,

transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,

singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225

scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729,

transient2: 74c37151-6497-4223-b558-a4ffc1897d57,

singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225

大家注意到上面我們一共得到了 4個Transient實例,2個Scope實例,1個Singleton實例。

這有什么用?

如果在Mvc中用過Autofac的InstancePerRequest的同學就知道,有一些對象在一個請求跨越多個Action或者多個Service、Repository的時候,比如最常用的DBContext它可以是一個實例。即能減少實例初始化的消耗,還能實現跨Service事務的功能。(注:在ASP.NET Core中所有用到EF的Service 都需要注冊成Scoped )

而實現這種功能的方法就是在整個reqeust請求的生命周期以內共用了一個Scope。

三、DI在ASP.NET Core中的應用

3.1在Startup類中初始化

ASP.NET Core可以在Startup.cs的? ConfigureService中配置DI,大家看到 IServiceCollection這個參數應該就比較熟悉了。

public void ConfigureServices(IServiceCollection services)

{

services.AddTransient,

EFLoginService>();

services.AddMvc();

)

ASP.NET Core的一些組件已經提供了一些實例的綁定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的擴展方法。

public static IMvcBuilder AddMvc(this IServiceCollection services)

{

if (services == null)

{

throw new ArgumentNullException(nameof(services));

}

var builder = services.AddMvcCore();

builder.AddApiExplorer();

builder.AddAuthorization();

AddDefaultFrameworkParts(builder.PartManager);

...

}

3.2 Controller中使用

一般可以通過構造函數或者屬性來實現注入,但是官方推薦是通過構造函數。這也是所謂的顯式依賴。

private ILoginService _loginService;

public AccountController(

ILoginService loginService)

{

_loginService = loginService;

}

我們只要在控制器的構造函數里面寫了這個參數,ServiceProvider就會幫我們注入進來。這一步是在Mvc初始化控制器的時候完成的,我們后面再介紹到Mvc的時候會往細里講。

3.3 View中使用

在View中需要用@inject 再聲明一下,起一個別名。

@using MilkStone.Services;

@model MilkStone.Models.AccountViewModel.LoginViewModel

@inject ILoginService loginService

@loginService.GetUserName()

3.4 通過 HttpContext來獲取實例

HttpContext下有一個RequestedService同樣可以用來獲取實例對象,不過這種方法一般不推薦。同時要注意GetService<>這是個范型方法,默認如果沒有添加Microsoft.Extension.DependencyInjection的using,是不用調用這個方法的。

HttpContext.RequestServices.GetService>();

四、如何替換其它的Ioc容器

Autofac也是不錯的選擇,但我們首先要搞清楚為什么要替換掉默認的 DI容器?,替換之后有什么影響?.NET Core默認的實現對于一些小型的項目完全夠用,甚至大型項目麻煩點也能用,但是會有些麻煩,原因在于只提供了最基本的AddXXXX方法來綁定實例關系,需要一個一個的添加。如果項目可能要添加好幾百行這樣的方法。

如果熟悉Autofac的同學可能會這下面這樣的代碼有映象。

builder.RegisterGeneric(typeof(LoggingBehavior)).As(typeof(IPipelineBehavior));

builder.RegisterGeneric(typeof(ValidatorBehavior)).As(typeof(IPipelineBehavior));

這會給我們的初始化帶來一些便利性,我們來看看如何替換Autofac到ASP.NET Core。我們只需要把Startup類里面的 ConfigureService的 返回值從 void改為 IServiceProvider即可。而返回的則是一個AutoServiceProvider。

public IServiceProvider ConfigureServices(IServiceCollection services){

services.AddMvc();

// Add other framework services

// Add Autofac

var containerBuilder = new ContainerBuilder();

containerBuilder.RegisterModule();

containerBuilder.Populate(services);

var container = containerBuilder.Build();

return new AutofacServiceProvider(container);

}

4.1 有何變化

其中很大的一個變化在于,Autofac 原來的一個生命周期InstancePerRequest,將不再有效。正如我們前面所說的,整個request的生命周期被ASP.NET Core管理了,所以Autofac的這個將不再有效。我們可以使用 InstancePerLifetimeScope ,同樣是有用的,對應了我們ASP.NET Core DI 里面的Scoped。

轉載原址:http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/

總結

以上是生活随笔為你收集整理的core控制器属性注入的用处_了解ASP.NET Core 依赖注入,看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中文字幕无产乱码 | 求欧美精品网址 | 手机看片日韩国产 | 午夜男人av | 美女免费黄视频 | 亚洲情射| 精品久久久久久久久久久 | 动漫av在线免费观看 | 国产精品一级二级三级 | 久久人人妻人人人人妻性色av | 欧美777 | 午夜少妇视频 | 亚洲视频精品在线 | 青青草视频免费播放 | 亚洲乱码国产乱码精品精软件 | 国产成人一区二区三区免费看 | 中文字幕久热 | 逼特逼视频在线观看 | 美国免费高清电影在线观看 | 国产ts人妖系列高潮 | 国产av不卡一区二区 | 久久久精品在线观看 | 欧美黄色一级生活片 | 在线免费观看成年人视频 | 欧美老司机| 欧美精品福利 | 久久精品人妻一区二区三区 | 国产精品久久一 | 亚洲最大网 | 天天躁日日躁狠狠很躁 | 国产精品理伦片 | 一区两区小视频 | 日韩色在线 | 国产美女网站视频 | 欧美日韩h| 国产美女无遮挡免费视频 | 久久影音先锋 | 成人片在线视频 | 国产视频久久久久久 | 免看一级a毛片一片成人不卡 | 亚洲成人高清在线观看 | 精品国产91乱码一区二区三区 | 波多野结衣中文字幕一区二区 | 爱射综合 | 亚洲精品一级片 | 亚洲国产精品国自产拍av | av中文字幕网 | 亚洲女优在线观看 | 国产女人18毛片18精品 | 影视先锋av资源 | 韩国久久久久 | 国产最新视频在线 | 少妇高潮久久久 | 91字幕网 | 性猛交╳xxx乱大交 偷偷操不一样的久久 | 国产a视频免费观看 | 久久久久欧美 | 佐山爱av在线 | 免费无码一区二区三区 | 各种含道具高h调教1v1男男 | 九九色在线| 亚洲av高清一区二区三区 | 午夜av在线播放 | 超碰人人人人人人 | 欧美激情一区在线 | 人妻av一区二区三区 | 看黄网站在线观看 | 99国产精品久久久 | 偷拍一区二区 | 最近中文字幕免费mv视频7 | 国产精品久久久久久久裸模 | jizz性欧美2 视频在线日韩 | 少妇一晚三次一区二区三区 | 中文字幕在线免费播放 | 无码人妻精品一区二区蜜桃网站 | 一级一级黄色片 | 成人午夜免费视频 | 久久色在线 | 亚洲在线免费看 | 91视频亚洲 | 在线免费观看a视频 | 国产亚洲色婷婷久久99精品 | 中国肥胖女人真人毛片 | 天堂网av2014 | 日本男人天堂网 | 亚洲欧美日韩一区二区三区在线观看 | 久久久久三级 | 国产精品18p | 夫妻性生活自拍 | 国产美女永久免费 | 日韩综合一区二区三区 | 免费av在线| 被警察猛c猛男男男 | 激情午夜网 | 无遮挡的裸体按摩的视频 | 精品国产高清在线观看 | 免费在线观看黄视频 | av一起看香蕉 | 午夜在线观看免费视频 |