• 如何在.NET Core中使用依赖注入
  • 发布于 2个月前
  • 257 热度
    0 评论
我们通过一个例子来了解一下依赖链。例如:如果一个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));

        }
        // 堆代码 duidaima.com
        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();
重新运行你的应用程序你将看到有所有的产品将显示在浏览器中

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

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构造时解析
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函数创建

把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>
}
运行应用程序,你将会看到值显示到页面上

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

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的值

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

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中使用依赖注入,以及依赖注入对象的方法,以及使用不同方法注入时对象的生命周期,在Programe和Action方法以及View中获取依赖注入的服务。
用户评论