第四节:配置的读取、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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2019-04-23 09:03  Yaopengfei  阅读(2401)  评论(5编辑  收藏  举报