【asp.net core 系列】14 .net core 中的IOC

来源:https://www.cnblogs.com/c7jie/archive/2020/06/28/13201056.html
-Advertisement-
Play Games

0.前言 通過前面幾篇,我們瞭解到瞭如何實現項目的基本架構:數據源、路由設置、加密以及身份驗證。那麼在實現的時候,我們還會遇到這樣的一個問題:當我們業務類和數據源越來越多的時候,我們無法通過普通的構造對象的方法為每個實例進行賦值。同時,傳統意義上的賦值遇到底層切換或者其他修改的時候,就需要修改大量的 ...


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框架的核心秘密。

更多內容煩請關註我的博客《高先生小屋》

file


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JAVA中繼承和多態的理解 繼承的概念 繼承是java面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。 繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。 類的繼承格式 在Java中通過extends關鍵字可以申 ...
  • 學習記錄1--Springboot的Maven自定義打包 在以往的開發中,Springboot應用預設打成一個jar,雖然方便但是會有很多問題,比如不方便修改配置文件,修改一個處代碼就要更新整包等等,而maven中也有這樣的插件可以給我們提供幫助 複製引用依賴插件 <plugin> <groupId ...
  • 切片 import numpy as np # 使用切片參數start:stop:step來進行切片操作 a_array=np.arange(10) print(a_array,'\n') b_array=a_array[1:10:2] print(b_array,'\n') c_array=a_a ...
  • 線性表: 定義:由零個或多個數據元素組成的有限序列。 首先他是一個序列,也就是說元素之間是有先來後到 若元素存在多個,則第一個元素無前驅,最後一個元素無後繼,其他元素有且只有一個前驅和後繼 另外,線性表強調是有限的。 數學語言的定義: 若將線性表記為(a1,...,ai-1,ai,ai+1,...a ...
  • 目 錄 1 選題.......................................................................................................................... 1 2 系統需求分析......... ...
  • Spyder簡介 Spyder (前身是 Pydee) 是一個強大的互動式 Python 語言開發環境,提供高級的代碼編輯、交互測試、調試等特性,支持包括 Windows、Linux 和 OS X 系統。 ● 菜單欄(Menu bar):顯示可用於操縱Spyder各項功能的不同選項。 ● 工具欄(T ...
  • Quartz:定時非同步任務 任務:做什麼事情; 觸發器:定義時間; 調度器:將任務、觸發器一一對應。 實現步驟(獨立使用): 1.jar 2.任務(service):Job 3.測試方法:job、觸發器、調度器 scheduler.shutdown(); 立刻關閉 scheduler.shutdow ...
  • 相信很多朋友對於邏輯式編程語言,都有一種最熟悉的陌生人的感覺。一方面,平時在書籍、在資訊網站,偶爾能看到一些吹噓邏輯式編程的話語。但另一方面,也沒見過周圍有人真正用到它(除了SQL)。 本系列將儘可能簡潔地說明邏輯式編程語音的原理,並實現一門簡單的邏輯式編程語言。考慮到C#的用戶較多,因此選擇用C#... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...