ASP.NET Core 依赖注入系列三

8 依赖关系链
我们通过一个例子来了解一下依赖链,例如:如果一个alpha的组件有依赖于一个beta的组件,然而beta组件又依赖于另外一个组件gamma,这就形成了一个依赖链,ASP.NET Core 能够很好的解析这个依赖链,让我们通过一个例子来了解
在Models文件夹下添加一个新的接口IStorage.cs,定义如下:.
namespace AspNetCore.DependencyInjection.Models{    public interface IStorage    {        IEnumerable<Product> Items { get; }        Product this[string key] { get; set; }        bool ContainsKey(string key);        void RemoveItem(string key);    }}
接下来创建一个新的Storage类继承该接口
namespace AspNetCore.DependencyInjection.Models{    public class Storage : IStorage    {        private Dictionary<string, Product> items = new Dictionary<string, Product>();        public Product this[string key]        {            get { return items[key]; }            set { items[key] = value; }        }        public IEnumerable<Product> Items => items.Values;        public bool ContainsKey(string key)        {            return items.ContainsKey(key);        }        public void RemoveItem(string key)        {            items.Remove(key);        }    }}
这个Storage类针对Product对象定义了一个简单存储机制,现在我们进入Repository类,在构造函数中创建一个IStorage接口的依赖,代码如下:
namespace AspNetCore.DependencyInjection.Models{    public class Repository : IRepository    {        private IStorage _storage;        public Repository(IStorage storage)        {            _storage = storage;            new List<Product> {                new Product { Name = "Women Shoes", Price = 99M },                new Product { Name = "Skirts", Price = 29.99M },                new Product { Name = "Pants", Price = 40.5M }            }.ForEach(p => AddProduct(p));
        }
        public IEnumerable<Product> Products => _storage.Items;        public Product this[string name] => _storage[name];        public void AddProduct(Product product) => _storage[product.Name] = product;        public void DeleteProduct(Product product) => _storage.RemoveItem(product.Name);
        private string guid = Guid.NewGuid().ToString();        public override string ToString()        {            return guid;        }    }}
现在所有方法和属性将使用IStorage对象工作,在这里我们创建一个依赖链:
1 HomeController类依赖于IRepository对象
2 IRepository对象依赖于IStorage对象
现在我们告诉ASP.NET Core 服务如何解析依赖链,因此进入Program.cs类,添加下面代码
var builder = WebApplication.CreateBuilder(args);
//builder.Services.AddTransient<IRepository, Repository>();
//builder.Services.AddScoped<IRepository, Repository>();//builder.Services.AddSingleton<IRepository,Repository>();builder.Services.AddTransient<ProductSum>();builder.Services.AddTransient<IRepository, Repository>();builder.Services.AddTransient<IStorage, Storage>();// Add services to the container.builder.Services.AddControllersWithViews();var app = builder.Build();

重新运行你的应用程序你将看到有所有的产品将显示在浏览器中

ASP.NET Core 依赖注入系列三

9 在Programe类中获取服务

我们可以通过下面代码在Programe类中获取服务

ASP.NET Core 依赖注入系列三

10 Action方法中获取服务

通过Controller构造函数声明依赖是非常昂贵的,我们可以通过在请求的方法中获取服务
我们将添加一个[FromServices] 特性在action方法中指定它依赖的服务
我们进入HomeController修改Index,使用[FromServices]从方法中获取ProductSum服务,  把ProductSum从构造函数中移除

代码如下:

namespace AspNetCore.DependencyInjection.Controllers{    public class HomeController : Controller    {        private IRepository _repository;        public HomeController(IRepository repository)        {            _repository = repository;        }        public IActionResult Index([FromServices] ProductSum _productSum)        {            ViewBag.HomeControllerGUID = _repository.ToString();            ViewBag.TotalGUID = _productSum.Repository.ToString();            return View(_repository.Products);        }    }}
当Index方法调用时解析ProductSum类型,不在Controller构造时解析
11 ASP.NET Core 工厂方法注入

我们可以使用工厂模式来注册服务,因此你可以使用它创建你自己的逻辑告诉应用程序如果解析依赖,在Models文件夹下创建一个新的类ProductionRepository.cs,代码如下:

namespace AspNetCore.DependencyInjection.Models{    public class ProductionRepository : IRepository    {        private Dictionary<string, Product> products;        public ProductionRepository()        {            products = new Dictionary<string, Product>();            new List<Product> {                new Product { Name = "Women Shoes", Price = 99M },                new Product { Name = "Skirts", Price = 29.99M },                new Product { Name = "Pants", Price = 40.5M }            }.ForEach(p => AddProduct(p));        }        public IEnumerable<Product> Products => products.Values;        public Product this[string name] => products[name];        public void AddProduct(Product product) => products[product.Name] = product;        public void DeleteProduct(Product product) => products.Remove(product.Name);    }}

现在我们在开发环境和生产环境中分别注册不同的服务,我们通过函数代理并且添加lambda函数创建

ASP.NET Core 依赖注入系列三

12 把JSON文件注入应用程序

我们可以使用依赖注入将JSON文件注入到Controller或者View,让我们展示一下如何指定这个工作
在项目根目录创建一个JSON文件命名为mysettings.json, 将下面内容添加到JSON文件中:
{    "Title": "Dependency Injection Tutorial",    "Version": 3}

针对这个JSON文件创建一个类,在Models文件夹下创建一个MyJson.cs类

public class MyJson{    public string Title { get; set; }    public int Version { get; set; }}
接下来配置应用程序从JSON文件读取到类,因此在你的应用程序中添加下面代码
using DependencyInjection.Models;var builder = WebApplication.CreateBuilder(args); // Add services to the container.builder.Services.AddControllersWithViews();builder.Host.ConfigureAppConfiguration((hostingContext, config) =>{    config.AddJsonFile("mysettings.json",                       optional: false, //file is not optional                       reloadOnChange: true);});builder.Services.Configure<MyJson>(builder.Configuration);var app = builder.Build();
现在可以从任何Controller或者View中读取JSON文件的值,因此我们创建一个Controller并命名为SettingsController.cs,在这个控制器中添加构造函数并且添加IOptions<MyJson>类型的参数, 这个参数通过依赖注入的技术提供JSON文件中的值,代码如下:
using DependencyInjection.Models;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Options;
namespace DependencyInjection.Controllers{    public class SettingsController : Controller    {        private readonly MyJson _settings;        public SettingsController(IOptions<MyJson> settingsOptions)        {            _settings = settingsOptions.Value;        }        public IActionResult Index()        {            ViewData["Title"] = _settings.Title;            ViewData["Version"] = _settings.Version;            return View();        }    }}
我们将这两个值显示到视图中,因此在Views->Settings文件加下添加Index视图,并在视图中添加如下代码:
@if (ViewData.Count > 0){    <table class="table table-bordered table-sm table-striped">        @foreach (var kvp in ViewData)        {            <tr><td>@kvp.Key</td><td>@kvp.Value</td></tr>        }    </table>}
运行应用程序,你将会看到值显示到页面上

ASP.NET Core 依赖注入系列三

13 View中获取依赖注入对象

使用@inject指令可以在ASP.NET Core View 中使用依赖注入,我们通过两个例子来了解:

13.1 将JSON文件注入到View

前面我们介绍了依赖注入JSON文件的值到控制器中,这次我将注入mysettings.json文件值到View中,在前面我们已经在Program.cs类中做配置

在SettingsController中添加一个新的Show方法

public IActionResult Show(){    return View();}
接下来添加名为Show.cshtml的View和下面代码
@using Microsoft.Extensions.Options;@using AspNetCore.DependencyInjection.Models@inject IOptions<MyJson> settingsOptions<table class="table table-bordered table-sm table-striped">    <tr>        <td>Title</td>        <td>@settingsOptions.Value.Title</td>    </tr>    <tr>        <td>Version</td>        <td>@settingsOptions.Value.Version</td>    </tr></table>

注意:通过下面代码显示JSON的值

ASP.NET Core 依赖注入系列三

运行程序输入URL-https://localhost:7206/Settings/Show, 你将看到值显示在View

ASP.NET Core 依赖注入系列三

13.2 appsettings.json注入View

我们可以将appsettings.json文件的值注入的view,这个过程非常简单,你只需要使用inject指令然后显示他们的值,代码如下:

@inject IConfiguration Configuration<div>@Configuration["Logging:LogLevel:Default"]</div>

我们将下面appsettings.json文件的值显示到页面

{  "Logging": {    "LogLevel": {      "Default": "Information",      "Microsoft.AspNetCore": "Warning"    }  },  "AllowedHosts": "*"}

我们将显示Default,Microsoft.AspNetCore节点的值,在SettingsController中添加Detail方法

public IActionResult Detail(){    return View();}

在Detail视图中添加如下代码

@inject IConfiguration Configuration
<table class="table table-bordered table-sm table-striped">    <tr>        <td>Default</td>        <td>@Configuration["Logging:LogLevel:Default"]</td>    </tr>    <tr>        <td>Microsoft</td>        <td>@Configuration["Logging:LogLevel:Default"]</td>    </tr>    <tr>        <td>Microsoft.Hosting.Lifetime</td>        <td>@Configuration["Logging:LogLevel:Microsoft.AspNetCore"]</td>    </tr></table>
显示页面

ASP.NET Core 依赖注入系列三

总结

这节中我们主要讲解了如何在ASP.NET Core中使用依赖注入,以及依赖注入对象的方法,以及使用不同方法注入时对象的生命周期,在Programe和Action方法以及View中获取依赖注入的服务

源代码地址

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.DependencyInjection/AspNetCore.DependencyInjection