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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

ASP.NET Core 注册单例方案

發布時間:2023/12/4 asp.net 74 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 注册单例方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一個單例是沒有公共構造函數的,只能通過靜態的 Instance?屬性獲取,這是單例的標準初衷,一個單例是不想讓別人調用它的構造函數的。但是 aspnetcore?中提供的?AddSingleton<TService, TImplementation>() ,只提供了類型,而無法注入對象實例,單實例對象還是要框架深層構造的,這實際上并不是安全的做法。?

如果使用了標準的單例設計方法,則無法由框架直接生成單實例,這就需要使用點小技巧了。?

單例設計

public class Singleton<T> where T : class {protected static T instance;protected static object locker = new object();public static T Instance{get{if (instance == null){lock (locker){if (instance == null) //防止線程重入{IEnumerable<ConstructorInfo> constructors = typeof(T).GetTypeInfo().DeclaredConstructors;ConstructorInfo ci = constructors.ToList()[0];instance = ci.Invoke(new object[] { }) as T;}}}return instance;}}protected Singleton(){IEnumerable<ConstructorInfo> constructors = typeof(T).GetTypeInfo().DeclaredConstructors;constructors.ActionForeach(c => {if (c.IsPublic){throw new InvalidOperationException("禁止從public構造函數中實例化!");}});}}

以上要點有三個:

1?使用次 if?判斷和 locker?保護,防止線程重入時構造多個實例,確保唯一性;

2?在基類中,使用反射調用子類的構造函數完成實例化;

3 基類的構造函數是受保護的,它會檢查,禁止子類的公共構造函數調用。

第3條隱藏了一個知識點:子類在初始化實例時,默認會調用基類的構造函數。

因為以上三條機制確保了單例的唯一性,所以反射只會在第一次使用時調用,對性能的影響可以忽略不計。

?

單例的使用

使用起來非常簡單

public class Root:Singleton<Root> {protected Root() { }public void DoSomething() {Console.WriteLine("I feel very happy, cus I'm unique."); } }

假設有一個類,叫做Root,由于業務需要,它必須要以單例實現,顧名思義,根只能有一個。

如果不重寫 protected?構造函數,則可能發生以下情況:

Root root = new Root();

這是被禁止的,萬一忘記寫了 protected Root(){}?這一行,就會拋出異常,可見在??Singleton<T>?中進行判斷,是十分有必要的。

在業務需要的地方,就可以用通常使用的單例模式來調用 :

Root.Instance.DoSomething();

至此,單例模式完成。

一個真實的業務場景

假設主模塊是?Main.dll,?它是一個 aspnetcore?工程, 它調用了?A.dll?作為它的類庫。由于某種原因,Root?類必須要在?Main?工程中實現,而不能放到?A?工程中。但是A工程要用到?Root?的方法。如果讓?A?工程來引用? Main?工程,這就是反向引用了,這會形成循環引用,是不被允許的。

所以我們可以把 Root?的方法抽象出接口來,注冊到?aspnet?框架中,我們可以這樣做:

在?A.csproj?中,暴露接口給自己調用:

public interface IRoot {void DoSomething(); }

在 Main.csproj?中實現這個接口:

class Root:Singleton<Root>, IRoot {protected Root() { }public void DoSomething() {Console.WriteLine("I feel very happy, cus I'm unique.");} }

然后就是注冊了,在 Main.csproj?工程的?Startup.cs?文件的??ConfigureServices?方法中進行注冊:

public void ConfigureServices(IServiceCollection services) {services.AddControllersWithViews();services.AddSession();//...其他代碼services.AddSingleton<IRoot, Root>(); }

這樣就可以了嗎? no no no ,?這樣肯定是不行的,因為前面我們設計的單例,是這樣使用的: Root.Instance.DoSomething();? 而不是 Root root = new Root();?

這會導致注入失敗,因為框架注冊要求 Root 有一個公共無參構造函數,況且它并不知道Root有個靜態屬性 Instance ,而且只能通過 Instance?來訪問。

單例注入方案

下面說到正題了,既然不能直接注冊單例,我們可以使用一個中間接口來注入,這個中間接口提供了單例的訪問對象,而且它擁有一個沒有寫出來的默認公共構造方法,它的構造函數,與 Root 類的構造函數,毫無關系,所以可以由框架創建。

在 A.csproj?工程中定義:

public interface IRootProvider {IRoot Root { get; } }

在?Main.csproj?中實現:

public class RootProvider : IRootProvider {public IRoot Root { get => SomeNamespace.Root.Instance; } }

然后再注冊:

public void ConfigureServices(IServiceCollection services) {services.AddControllersWithViews();services.AddSession();//...其他代碼services.AddScoped<IRootProvider, RootProvider>();services.AddScoped<ISomeService, SomeService>(); }

look,?我們已經不需要使用?AddSingleton?來注入了,因為? RootProvider?不必是單實例的。?

在?A.csproj? 中愉快地使用:

public class SomeService:ISomeService {private IRoot root;public SomeService(IRootProvider rootProvider){this.root = rootProvider.Root;}public void SomeBusiness(){this.root.DoSomething();} } SomeService 是在主模塊中注入的服務,在主模塊中構造,構造的前提是要有一個 IRootProvider 的實例,同時 IRootProvider 要在它的前一行注冊,這個很重要。 到這里,本文就結束了,但我還是想啰嗦一下:在A中使用的 IRoot root 一點也看不出單例的痕跡,因為 IRoot 只是一個業務接口;同時 IRootProvider 也只提供了 IRoot 的 get 方法, 所以對于 A 模塊的開發者,完全不必知道 Root 的存在,更不必知道什么 Singleton<Root> 跟 Instance 的破事。我們已經完全隱藏了單例模式的實現,這是解決這個問題附帶的收獲。這個設計是不是徹底實現了 面向接口編程 的規范? 快夸我吧! 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的ASP.NET Core 注册单例方案的全部內容,希望文章能夠幫你解決所遇到的問題。

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