第四節:配置的讀取、StartUp類、內置依賴注入和擴展改造


一. 配置的讀取

  在Asp.Net Core中,有一個 appsettings.json 文件,用於存儲相應的配置信息,讀取的時,要通過構造函數注入:IConfiguration Configuration,來進行讀取。

  下面是一段配置文件,我們來對其進行讀取:

 

讀取代碼:

 1 public IConfiguration Configuration { get; }
 2 public FirstController(IConfiguration configuration)
 3 {
 4      Configuration = configuration;
 5 }
 6 {
 7       var f0 = Configuration["MyFullName"];
 8       var f1 = Configuration["User:userName"];
 9       var f2 = Configuration["User:Child:childName"];
10       var f3 = Configuration["StudentList:0:sName"];
11       var f4 = Configuration["StudentList:1:sName"];
12 }

 

二. StartUp類

1. 說明:

  StartUp類中包括兩個方法,分別是ConfigureServices和Configure,前者主要用來注冊服務,后者主要用來創建和配置請 求管道,然后在Main方法中進行調用:     

 WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();

2. ConfigureServices方法

(1). 它在Configure方法調用之前,由主機調用。

(2). 需要大量設置的功能,IServiceCollection 上有 Add{Service} 擴展方法,常見的如下:

  a:services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection")));

  b:services.AddDefaultIdentity<IdentityUser>().AddDefaultUI(UIFramework.Bootstrap4).AddEntityFrameworkStores<ApplicationDbContext>();

  c:services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

3. Configure方法

(1).用於配置Http請求管道,主要通過IApplicationBuilder實例來配置。

(2).常見的管道有:

  開發人員異常頁(UseDeveloperExceptionPage)、

  HTTP嚴格傳輸安全性(UseHsts)、

  HTTPS重定向(UseHttpsRedirection)、

  靜態文件(UseStaticFiles)、

  MVC(UseMvc)。

 

三. 內置依賴注入和擴展改造

1. 說明:

  這里不再介紹什么是IOC和DI,直接介紹內置依賴注入的使用方法和生命周期,最后介紹利用AutoFac進行替換內置IOC容器。事先准備好U1-U4四個類和IU1-IU4四個接口。

接口和類的代碼:

 1   public interface IU1
 2     {
 3         string guid { get; set; }
 4         string GetName();
 5     }
 6   public interface IU2
 7     {
 8         string guid { get; set; }
 9         string GetName();
10     }
11   public interface IU3
12     {
13         string guid { get; set; }
14         string GetName();
15     }
16   public interface IU4
17     {
18         string guid { get; set; }
19         string GetName();
20     }
接口
 1  public class U1 : IU1
 2     {
 3         public string guid { get; set; }
 4 
 5         public U1()
 6         {
 7             guid = System.Guid.NewGuid().ToString("N");
 8         }
 9 
10         /// <summary>
11         /// 調用方法的時候,是單例也沒有用,每次調用都會變
12         /// </summary>
13         /// <returns></returns>
14         public string GetName()
15         {
16             return System.Guid.NewGuid().ToString("N");
17         }
18     }
19  public class U2 : IU2
20     {
21         public string guid { get; set; }
22 
23         public U2()
24         {
25             guid = System.Guid.NewGuid().ToString("N");
26         }
27 
28         /// <summary>
29         /// 調用方法的時候,是單例也沒有用,每次調用都會變
30         /// </summary>
31         /// <returns></returns>
32         public string GetName()
33         {
34             return System.Guid.NewGuid().ToString("N");
35         }
36     }
37  public class U3 : IU3
38     {
39         public string guid { get; set; }
40 
41         public U3()
42         {
43             guid = System.Guid.NewGuid().ToString("N");
44         }
45 
46         /// <summary>
47         /// 調用方法的時候,是單例也沒有用,每次調用都會變
48         /// </summary>
49         /// <returns></returns>
50         public string GetName()
51         {
52             return System.Guid.NewGuid().ToString("N");
53         }
54     }
55  public class U4 : IU4
56     {
57         public string guid { get; set; }
58 
59         public U4()
60         {
61             guid = System.Guid.NewGuid().ToString("N");
62         }
63 
64         /// <summary>
65         /// 調用方法的時候,是單例也沒有用,每次調用都會變
66         /// </summary>
67         /// <returns></returns>
68         public string GetName()
69         {
70             return System.Guid.NewGuid().ToString("N");
71         }
72     }

2. 核心:

  利用IServiceCollection services這個對象進行注冊,而這個對象在Startup類中的ConfigureServices中已經注入進去了, 也就是說我在自定義對象的注冊是的時候,可以直接在ConfigureServices類中進行注冊,然后在控制器中使用的時候通過構造函數進行注入即可。

PS:我們也可以自己 IServiceCollection container = new ServiceCollection(); 然后進行注冊(不推薦,特殊情況下可能這么用)

3. 生命周期分為三種:

  瞬時的(AddTransient)、請求內單例(AddScoped)、單例(AddSingleton 兩種寫法)。

4. 測試:

  兩次訪問該頁面,發現ViewBag.r1 和 ViewBag.r2兩次的值不同,ViewBag.r3和ViewBag.r4兩次的值相同。

代碼分享:

 1  public void ConfigureServices(IServiceCollection services)
 2         {
 3             services.Configure<CookiePolicyOptions>(options =>
 4             {
 5                 // This lambda determines whether user consent for non-essential cookies is needed for a given request.
 6                 options.CheckConsentNeeded = context => true;
 7                 options.MinimumSameSitePolicy = SameSiteMode.None;
 8             });
 9             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
10 
11             //自定義注冊對象
12             {
13                 services.AddTransient<IU1, U1>();   //瞬時的
14                 services.AddScoped<IU2, U2>();      //一次請求內是不變的
15                 services.AddSingleton<IU3, U3>();  //單例的
16                 services.AddSingleton<IU4>(new U4());  //單例的
17 
18             }
19         }
 1   public class FirstController : Controller
 2     {
 3         public IU1 U1 { get; }
 4         public IU1 U11 { get; }
 5         public IU2 U2 { get; }
 6         public IU2 U22 { get; }
 7         public IU3 U3 { get; }
 8         public IU3 U33 { get; }
 9         public IU4 U4 { get; }
10         public IU4 U44 { get; }
11 
12         public FirstController(IU1 u1, IU1 u11, IU2 u2, IU2 u22, IU3 u3, IU3 u33, IU4 u4, IU4 u44)
13         {
14             U1 = u1;
15             U11 = u11;
16             U2 = u2;
17             U22 = u22;
18             U3 = u3;
19             U33 = u33;
20             U4 = u4;
21             U44 = u44;
22         }
23 
24         public IActionResult Index()
25         {
26             bool a = object.ReferenceEquals(U1, U11);
27             bool b = object.ReferenceEquals(U2, U22);
28             bool c = object.ReferenceEquals(U3, U33);
29             bool d = object.ReferenceEquals(U4, U44);
30 
31             //分兩次請求來查看
32             ViewBag.r1 = U1.guid;
33             ViewBag.r2 = U2.guid;
34             ViewBag.r3 = U3.guid;
35             ViewBag.r4 = U4.guid;
36 
37             //下面是自己創建的的模式進行訪問
38              {
39                     IServiceCollection container = new ServiceCollection();
40                     container.AddTransient<IU2, U2>();
41                     //要放在注冊的后面
42                     var provider = container.BuildServiceProvider();
43                     IU2 user1 = provider.GetService<IU2>();
44                     IU2 user2 = provider.GetService<IU2>();
45                     bool cc = object.ReferenceEquals(user1, user2);47             } 
48             return View();
49         }
50     }
1 <div class="text-center">
2     <h1 class="display-4">Welcome</h1>
3     <p>瞬時的:@ViewBag.r1</p>
4     <p>請求內單例:@ViewBag.r2</p>
5     <p>全局單例寫法1:@ViewBag.r3</p>
6     <p>全局單例寫法2:@ViewBag.r4</p>
7 </div>

補充:

  如果不想通過構造函數注入,則可以通過[FromServices]特性來給某個特定方法注入:

       如: public void Test(【FromServices】IU1 u1){    }。

兩次訪問的請求結果

 

5. 為什么要用AutoFac進行替換內置容器?

  因為某些特定的功能內置的容器不支持,比如:屬性的注入、基於名稱的注入、子容器、自定生存期管理、對遲緩初始化的 Func<T> 支持

6. 用AutoFac替換的步驟

(1). 通過Nuget安裝AutoFac【4.9.2】和Autofac.Extensions.DependencyInjection【4.4.0】

(2). 改造ConfigureServices中配置容器並返回IServiceProvider,配置代碼詳見具體類,注入的代碼封裝到DefaultModule。

 1         public IServiceProvider ConfigureServices(IServiceCollection services)
 2         {
 3             services.Configure<CookiePolicyOptions>(options =>
 4             {
 5                 // This lambda determines whether user consent for non-essential cookies is needed for a given request.
 6                 options.CheckConsentNeeded = context => true;
 7                 options.MinimumSameSitePolicy = SameSiteMode.None;
 8             });
 9             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
10 
11             // Add Autofac
12             var containerBuilder = new ContainerBuilder();
13             containerBuilder.RegisterModule<DefaultModule>();
14             containerBuilder.Populate(services);
15             var container = containerBuilder.Build();
16             return new AutofacServiceProvider(container);
17         }
DefaultModule代碼分享
特別注意:AutoFac的生命周期也有:瞬時的、單次請求內單例的、全局單例的。
 1   public class DefaultModule: Module
 2     {
 3         protected override void Load(ContainerBuilder builder)
 4         {
 5             //這里就是AutoFac的注入方式,下面采用常規的方式
 6             //詳見:https://www.cnblogs.com/yaopengfei/p/9479268.html
 7             //官網:https://autofac.org/
 8 
 9             //特別注意:其中很大的一個變化在於,Autofac 原來的一個生命周期InstancePerRequest,將不再有效。正如我們前面所說的,整個request的生命周期被ASP.NET Core管理了,
10             //所以Autofac的這個將不再有效。我們可以使用 InstancePerLifetimeScope ,同樣是有用的,對應了我們ASP.NET Core DI 里面的Scoped。
11 
12             //瞬時請求(省略InstancePerDependency 也為瞬時)
13             builder.RegisterType<U1>().As<IU1>().InstancePerDependency();
14             //單次請求內單例
15             builder.RegisterType<U2>().As<IU2>().InstancePerLifetimeScope();
16             //全局單例
17             builder.RegisterType<U3>().As<IU3>().SingleInstance();
18             builder.RegisterType<U4>().As<IU4>().SingleInstance();
19 
20         }
21     }

(3). 其他都不變,可以繼續沿用構造函數注入。

 

參考文章:

  https://www.cnblogs.com/yaopengfei/p/9479268.html   (.Net 平台下的AutoFac的用法)

  https://www.cnblogs.com/jesse2013/p/di-in-aspnetcore.html

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM