ASP.NET Core 中的依赖注入

目录

依赖注入示例项目

存储库

控制器和视图

利用DI解决紧耦合问题

在控制器中实现依赖注入

单类型依赖注入

[ASP.NET Core 中的依赖注入类型](#ASP.NET Core 中的依赖注入类型)

依赖注入方法

[1. 添加瞬态](#1. 添加瞬态)

[2. 添加作用域](#2. 添加作用域)

[3. 添加单例](#3. 添加单例)

瞬态服务示例

范围服务示例

单例服务示例

依存链

依赖注入操作方法

[ASP.NET Core 依赖注入工厂](#ASP.NET Core 依赖注入工厂)

[JSON 文件的依赖注入](#JSON 文件的依赖注入)

视图中的依赖注入


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

示例代码:https://download.csdn.net/download/hefeng_aspnet/92599904

什么是 ASP.NET Core 中的依赖注入?依赖注入(简称"DI")是 ASP.NET Core 的一种技术,用于实现对象之间的松耦合,从而简化应用程序的维护。在 ASP.NET Core 中,.NET 运行时引擎会自动注入依赖类的对象,主要通过控制器构造函数来实现。这大大简化了开发人员的工作。

让我们创建一个ASP.NET Core 6.0应用程序来演示 依赖注入功能的工作原理。本教程将全面讲解该功能,请务必一次性完整阅读。

依赖注入示例项目

打开Visual Studio 2022选择ASP.NET Core Web 应用程序(模型-视图-控制器)模板创建一个新项目。请确保选择**.Net 6.0 框架**。

存储库

此应用需要临时存储空间来存放一些产品。为了简化操作,我们将这些产品存储在"内存存储库"中,而不是数据库中。因此,首先在应用的++Models文件夹中添加++ Product.cs类。其代码如下所示。

namespace DependencyInjection.Models

{

public class Product

{

public string Name { get; set; }

public decimal Price { get; set; }

}

}

接下来,在同一个 Models 文件夹内创建一个名为IRepository 的接口。该接口包含用于向存储库添加、读取和删除产品的属性和方法。该接口的代码如下所示:

namespace DependencyInjection.Models

{

public interface IRepository

{

IEnumerable<Product> Products { get; }

Product this[string name] { get; }

void AddProduct(Product product);

void DeleteProduct(Product product);

}

}

现在我们来看存储库。之前创建的"IRepository"接口将被另一个名为 `Repository` 的类继承,该类将作为我们的存储库。接下来,在"Models"文件夹中创建`Repository.cs`类,并将以下代码添加到其中:

namespace DependencyInjection.Models

{

public class Repository : IRepository

{

private Dictionary<string, Product> products;

public Repository()

{

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);

}

}

这里我们将 3 个产品数据存储在一个字典中(参见类的构造函数)。其余代码的含义显而易见,只是简单地实现了接口的属性和方法。通过这种方式,它创建了用于从存储库中读取、添加和删除产品的方法和属性。

控制器和视图

现在让我们更新HomeController.cs文件,以便在视图中显示我们的产品。因此,需要更新"Index"操作方法,如下所示。

using DependencyInjection.Models;

using Microsoft.AspNetCore.Mvc;

using System.Diagnostics;

namespace DependencyInjection.Controllers

{

public class HomeController : Controller

{

public IActionResult Index()

{

return View(new Repository().Products);

}

}

}

您可以清楚地看到,在索引操作方法中,我创建了一个新的 Repository 类对象,并调用了它的 Products 属性new Repository().Products。该属性返回字典中存储的所有 3 个产品。最后,我将这些产品返回给视图。

我的 Home Controller 与 Repository 类之间存在紧耦合关系。现在我将使用依赖注入技术来降低它们的耦合度。

现在,请使用以下代码更新位于Views ➤ Home文件夹内的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>

}

<table class="table table-bordered table-sm table-striped">

<thead>

<tr><th>Name</th><th>Price</th></tr>

</thead>

<tbody>

@if (Model == null)

{

<tr><td colspan="3" class="text-center">No Model Data</td></tr>

}

else

{

@foreach (var p in Model)

{

<tr>

<td>@p.Name</td>

<td>@string.Format("{0:C2}", p.Price)</td>

</tr>

}

}

</tbody>

</table>

此视图通过遍历 ViewData 对象读取产品信息,并以表格形式显示所有产品。运行您的应用程序,您将看到如下图所示的全部 3 个产品:

利用DI解决紧耦合问题

如果你查看控制器的代码,你会发现它与Repository.cs类紧密耦合。原因是我们直接使用 new 关键字创建了 Repository 类的对象。

return View(new Repository().Products);

假设一段时间后,需要将存储库更改为名为NewRepository.cs的另一个类。因此,我们需要像这样更改 Controller 中的代码:

public IActionResult Index()

{

return View(new NewRepository().Products);

}

这是管理紧耦合组件的问题。

为什么紧耦合代码不好?

  1. 这会在项目维护阶段带来问题。如果一个组件发生变化,就会影响其他组件。
  2. 对这些组件进行单元测试时会遇到很多问题。

依赖**注入(DI)**技术可以解决这些问题。ASP.NET Core 可以自动为 Controller 类提供存储库对象,从而消除紧耦合问题。

下一节我们将探讨如何在控制器中实现依赖注入。

在控制器中实现依赖注入

如何在 ASP.NET Core 中实现依赖注入?最简单的方法是注册一个服务,该服务的作用是指定 ASP.NET Core 依赖注入如何解析依赖项。在 ASP.NET Core 控制器中实现依赖注入需要两个步骤。

  1. 将控制器从紧密耦合的依赖关系中解耦为松散耦合的依赖关系。
  2. 具体说明 ASP.NET Core 运行时应如何解决这种新的(松耦合的)依赖关系。

首先,我们将在控制器中创建松耦合依赖关系。为此,我们将实现一个接口,并在控制器中使用该接口(而不是 Repository 类)。回想一下,我之前创建了一个名为++IRepository 的++接口,现在我将使用这个接口。

public interface IRepository

{

IEnumerable<Product> Products { get; }

Product this[string name] { get; }

void AddProduct(Product product);

void DeleteProduct(Product product);

}

存储库类实现了如下所示的接口。

public class Repository : IRepository

{

...

}

现在更新 Home Controller 代码,以便使用此接口创建此依赖项。请查看以高亮方式显示的更改。

using DependencyInjection.Models;

using Microsoft.AspNetCore.Mvc;

using System.Diagnostics;

namespace DependencyInjection.Controllers

{

public class HomeController : Controller

{

private IRepository repository;

public HomeController(IRepository repo)

{

repository = repo;

}

public IActionResult Index()

{

return View(repository.Products);

}

}

}

我们现在已经在控制器中完成了这两项工作。

  1. 在控制器中添加了一个接口类型(即IRepository )的变量。
  2. 添加了一个++构造函数,该构造函数带有一个此接口类型的参数++。在构造函数内部,我们将接口变量的值设置为构造函数参数的值。

这样,我们就为控制器添加了松耦合依赖关系。

现在,在您的操作方法中,我们可以使用接口的 Products 属性来访问产品。

return View(repository.Products);

**通过这项更改,控制器现在与存储库类松耦合。如果将来需要更改存储库,只需创建一个新的存储库即可。由于控制器现在与存储库松耦合,**因此无需对控制器进行任何更改。

最后,我们需要告诉 ASP.NET Core 如何解析IRepository接口的依赖项。因此,请打开应用程序的Program.cs文件,并注册一个新的服务,以便依赖注入 (DI) 可以自动解析依赖项。该服务的作用就是解析依赖项。

这是通过添加代码来实现的------ builder.Services.AddTransient<IRepository, Repository>()。请查看下面两行高亮显示的代码,您需要将它们添加到应用程序的 Program 类中。

using DependencyInjection.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<IRepository, Repository>();

// Add services to the container.

builder.Services.AddControllersWithViews();

var app = builder.Build();

// removed for brevity and clarity

注意:此服务将以瞬态方式创建(稍后详述),因此,每当请求"IRepository"对象时,都应通过提供"Repository"类型的实现来解决。AddTransient 方法的第一个参数是接口类型(此处为 IRepository),第二个参数是实现类(此处为 Repository.cs)。简而言之,这意味着:如果发现对 IRepository 的依赖,则通过创建 Repository 类的对象来解决它。

如果您使用的是 ASP.NET Core 5.0 或更早版本,则还有一个名为Startup.cs 的文件。您需要将上述代码添加到此文件中。因此,请打开 Startup.cs 文件,并在ConfigureServices()方法中添加如下所示的代码行:

public void ConfigureServices(IServiceCollection services)

{

services.AddTransient<IRepository, Repository>();

services.AddControllersWithViews();

}

现在重新运行应用程序,你会看到产品显示如下,但在这里你使用了依赖注入来轻耦合控制器和存储库类。

假设以后你需要显示来自另一个存储库(例如NewRepository.cs )的产品。那么你只需要将 AddTransient 方法更改为 -- builder.Services.AddTransient<IRepository, NewRepository>()。

下图展示了依赖注入的概念:

恭喜你已成功在项目中使用依赖注入技术。现在让我们来了解一些依赖注入的其他高级主题。

单类型依赖注入

如果一个类没有实现任何接口,那么它就是一个单类型类 。接下来,我们将探讨如何在这种情况下使用依赖注入技术 。首先,在 Models 文件夹中创建一个名为ProductSum.cs 的新类,并将以下代码添加到该类中:

namespace DependencyInjection.Models

{

public class ProductSum

{

public IRepository Repository { get; set; }

public ProductSum(IRepository repo)

{

Repository = repo;

}

public decimal Total => Repository.Products.Sum(p => p.Price);

}

}

请注意,此类未实现任何接口,但在构造函数中指定了对IRepository的依赖。它有一个名为Total 的属性,该属性返回 Repository 类所有乘积的总和。

该类依赖于 IRepository 接口,并且由于我之前已经添加的配置,将由服务提供者解析。

现在,在你的主控制器中,在构造函数中为ProductSum类创建一个依赖项,并设置一个 ViewBag 变量来存储所有产品的总和。这个 ViewBag 变量的值将显示在视图中。

下面显示的是更新后的Home控制器代码:

using DependencyInjection.Models;

using Microsoft.AspNetCore.Mvc;

using System.Diagnostics;

namespace DependencyInjection.Controllers

{

public class HomeController : Controller

{

private IRepository repository;

private ProductSum productSum;

public HomeController(IRepository repo, ProductSum psum)

{

repository = repo;

productSum = psum;

}

public IActionResult Index()

{

ViewBag.Total = productSum.Total;

return View(repository.Products);

}

}

}

现在配置服务提供程序,告诉它如何解析这个新的依赖项。所以,请将代码添加builder.Services.AddTransient<ProductSum>()到"Program.cs"文件中。

using DependencyInjection.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllersWithViews();

builder.Services.AddTransient<IRepository, Repository>();

builder.Services.AddTransient<ProductSum>();

var app = builder.Build();

// removed for brevity and clarity

请注意,在这种情况下,服务类型和实现类型之间没有映射关系。我使用了仅带一个参数的`AddTransient()`方法。这样,我指示服务提供者初始化 ` ProductSum`类来解决对该类型的依赖关系。这就是单类型依赖注入。

运行您的应用程序,您将在顶部看到所有产品的总价:

services.AddTransient<ProductSum>()在 ASP.NET Core 5.0 或更早版本中,在"Startup.cs"类的ConfigureServices()方法中添加以下代码行。

public void ConfigureServices(IServiceCollection services)

{

services.AddTransient<IRepository, Repository>();

services.AddTransient<ProductSum>();

services.AddControllersWithViews();

}

ASP.NET Core 中的依赖注入类型

依赖注入创建的服务具有生命周期,该生命周期定义了两件事:

  1. 它们何时会被创造出来。
  2. 它们在被垃圾回收器删除之前会在内存中保留多长时间。

服务可以有 3 个生命周期:

  1. 瞬态------每次请求时都会创建。
  2. 作用域 -- 每个客户端请求(连接)创建一次。
  3. 单例模式------仅在第一次请求时使用。

依赖注入方法

注册服务有三种方法:瞬态、作用域和单例。

1. 添加瞬态

`AddTransient` 方法以瞬态方式注册服务。这意味着每次请求服务时都会创建该服务。这也意味着每次依赖注入 (DI) 解析请求的对象时,都会创建一个新的该对象实例。

您已经看到了AddTransient()依赖注入方法,每次在控制器中请求 IRepository 接口时,都会创建一个新的++Repository.cs类对象。++

2. 添加作用域

使用AddScoped 方法 注册的服务并非总是像AddTransient 方法 那样被重新创建。实际上,它们会被重用于来自同一客户端的请求。这意味着,如果我们使用 AddScoped 方法代替 AddTransient,那么++Repository.cs++类对象只会创建一次,并在浏览器发出的每个后续请求中共享。

但是,如果我们从另一台电脑的浏览器请求该应用程序,那么(对于这个新客户端)将创建一个新的服务,并为每个后续请求共享该服务。

3. 添加单例

`AddSingleton` 方法仅为首次请求创建服务,之后每次请求都会重复使用该服务。请注意,与 `AddScoped` 方法不同,这里的服务将在所有其他客户端之间共享。

AddTransient、AddScoped 和 AddSingleton 方法各有 3 种变体:

  1. <service, implType>()
    这种变体为每个依赖项创建一个实现类型的实例。在前面题为"实现依赖注入(DI)"的章节中,我已经使用过这种变体。

  2. <service>()
    这种变体用于注册单一类型对象。我在前面的章节中也介绍过这一点。

  3. <service>(factoryFunc)
    这种变体用于使用 lambda 表达式注册工厂函数,我们还可以在这里添加自定义逻辑。我稍后会实现这种变体。

瞬态服务示例

正如您现在所知,瞬态服务必须通过"AddTransient"方法在Program类中注册。我们的应用程序中有两个瞬态服务,它们之前已经创建,分别是Repository和ProductSum。

builder.Services.AddTransient<IRepository, Repository>();

builder.Services.AddTransient<ProductSum>();

ProductSum.cs依赖于 IRepository,如构造函数中所述。

public class ProductSum

{

public IRepository Repository { get; set; }

public ProductSum(IRepository repo)

{

Repository = repo;

}

public decimal Total => Repository.Products.Sum(p => p.Price);

}

家庭控制器在构造函数中指定了对这两个服务的依赖关系。

public HomeController(IRepository repo, ProductSum psum)

{

}

现在重写了Repository.cs类中的ToString()方法,如下所示:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

namespace DependencyInjection.Models

{

public class Repository : IRepository

{

// ...

private string guid = System.Guid.NewGuid().ToString();

public override string ToString()

{

return guid;

}

}

}

这次重写将创建一个新的GUID 值,这将有助于识别何时以及如何通过依赖注入创建Repository.cs类的对象。

接下来,转到主控制器,并在其索引操作中添加两个 ViewBag变量。第一个 ViewBag 变量将包含从Repository服务接收的 GUID,而第二个 ViewBag 变量将包含从ProductSum服务接收的 GUID 。

更新后的代码如下所示:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using DependencyInjection.Models;

using Microsoft.AspNetCore.Mvc;

namespace DependencyInjection.Controllers

{

public class HomeController : Controller

{

// Removed for clarity

public IActionResult Index()

{

// ViewBag.Total = productSum.Total;

ViewBag.HomeControllerGuid = repository.ToString();

ViewBag.TotalGuid = productSum.Repository.ToString();

return View(repository.Products);

}

}

}

现在运行您的应用程序,您将在顶部看到显示的 GUID 值,请参见下图。

为什么两个 GUID 不同?因为每次浏览器调用 Home 控制器时,都会创建 Repository.cs 类的两个对象。第一个对象由 Repository 服务创建,而第二个对象由 ProductSum 服务创建(回想一下,ProductSum 的构造函数依赖于 IRepository)。

这些实例并非共享的。如果我们使用作用域服务,则只会创建一个 Repository 类的对象,并且该对象也会在 ProductSum 服务中共享。我们将在作用域服务示例中看到这一点。

范围服务示例

要了解作用域服务,请使用AddScoped方法更改 Program 类中 Repository 服务的注册过程。

builder.Services.AddScoped<IRepository, Repository>();

重新运行应用程序,您会发现这次两个 GUID 的值相同。这意味着服务提供者这次只创建了一个 Repository 类的对象,该对象由 ProductSum 服务共享。这就是作用域服务和瞬态服务之间的区别。

按 F5 键刷新页面,你会看到生成了一个新的 GUID (因为浏览器发起了一个新的 HTTP 请求)。但是,这两个 GUID 的值是相同的。

下图用红色标记标示出这个物体:

单例服务示例

最后,我们来看看单例服务。首先,使用AddSingleton方法更改 Repository 服务的注册信息。

builder.Services.AddSingleton<IRepository, Repository>();

重新运行应用程序,你会发现两个 GUID 值相同;刷新页面,你会发现 GUID 值根本没有改变。

下图对此进行了说明:

原因在于,Repository 类对象仅在首次创建时创建,并且每次请求都会共享该对象。即使多个客户端在其浏览器中请求 Home Controller,也只会创建一个对象并在它们之间共享。所有客户端每次都会看到相同的 GUID。

依存链

依赖链 的含义是:依赖项本身依赖于另一个组件,也就是说,每个被请求的依赖项又会依次请求其自身的依赖项。例如,如果组件"Alpha"依赖于名为"Beta"的组件,而"Beta"又依赖于名为"Gamma"的组件,那么这就构成了一条依赖链。

ASP.NET Core 非常智能,能够很好地解决这些依赖链。让我举个例子来说明。

在 Models 文件夹中添加一个名为IStorage.cs的类文件,并使用它来定义如下所示的接口:

namespace DependencyInjection.Models

{

public interface IStorage

{

IEnumerable<Product> Items { get; }

Product this[string key] { get; set; }

bool ContainsKey(string key);

void RemoveItem(string key);

}

}

现在从这个接口继承一个名为Storage.cs 的新类。该类的代码如下:

namespace 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) => items.ContainsKey(key);

public void RemoveItem(string key) => items.Remove(key);

}

}

Storage 类定义了 Product 对象的简单存储机制的行为。

现在打开之前创建的Repository.cs类,并在构造函数中添加对IStorage接口的依赖。以下高亮部分展示了更改:

namespace DependencyInjection.Models

{

public class Repository : IRepository

{

private IStorage storage;

public Repository(IStorage repo)

{

storage = repo;

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);

}

}

现在所有方法和属性都将适用于 IStorage 对象。通过这些更改,您创建了一个如下的依赖链:

  1. Home Controller 类依赖于 IRepository 对象。
  2. IRepository 对象又依赖于 IStorage 对象。

现在我只需要告诉 ASP.NET Core 服务提供程序如何解析这个依赖链 。所以请转到++Program.cs++ 文件,并添加如下所示的代码行 ( services.AddTransient<IStorage, Storage>() )。

using DependencyInjection.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllersWithViews();

builder.Services.AddTransient<IRepository, Repository>();

builder.Services.AddTransient<IStorage, Storage>();

var app = builder.Build();

// removed for brevity and clarity

对于 ASP.NET Core 5.0 或更早版本,您需要在Startup.cs类中添加如下所示的代码行:

public void ConfigureServices(IServiceCollection services)

{

services.AddTransient<IRepository, Repository>();

services.AddTransient<IStorage, Storage>();

services.AddControllersWithViews();

}

重新运行应用程序,您将像以前一样在浏览器中看到所有产品。唯一的区别在于,您现在已经解决了依赖链问题。

依赖注入操作方法

通过 Controller 的构造函数声明依赖项可能会很昂贵,因为每次创建 Controller 时都会解析依赖项,而且并非所有操作方法都需要该服务。

因此,我们也可以在 Action 方法上执行依赖注入。这样只会让特定的 Action 方法启动服务,从而创建所需的对象。

我们需要在操作方法上添加[FromServices]特性,以指定它依赖于该服务。

在主页控制器中,修改Index 操作方法,使其包含一个ProductSum类型的参数,并为其添加[FromServices]特性。同时,从控制器的构造函数中移除 ProductSum 特性。

更新后的代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using DependencyInjection.Models;

using Microsoft.AspNetCore.Mvc;

namespace DependencyInjection.Controllers

{

public class HomeController : Controller

{

private IRepository repository;

public HomeController(IRepository repo)

{

repository = repo;

}

public IActionResult Index([FromServices] ProductSum productSum)

{

// ViewBag.Total = productSum.Total;

ViewBag.HomeControllerGuid = repository.ToString();

ViewBag.TotalGuid = productSum.Repository.ToString();

return View(repository.Products);

}

}

}

现在,只有在调用Index操作方法时才会解析ProductSum类型,而不会在调用 Controller 时解析。

ASP.NET Core 依赖注入工厂

这种工厂函数 变体用于注册一个工厂函数,该函数将被调用以++创建实现对象++ 。因此,您可以使用它来++创建自己的逻辑++,以告知应用程序何时以及如何解决依赖关系。

在 Models 文件夹内创建一个名为ProductionRepository.cs 的新类,并将以下代码添加到该类中:

namespace 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);

}

}

现在,在Program.cs类中,我们将注册一个开发模式下的测试服务和一个生产模式下的正式服务。我们可以通过 Func 委托并添加一个 lambda 函数来实现这一点。

using DependencyInjection.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllersWithViews();

IWebHostEnvironment env = builder.Environment;

builder.Services.AddTransient<IRepository>(provider =>

{

if (env.IsDevelopment())

{

var x = provider.GetService<Repository>();

return x;

}

else

{

return new ProductionRepository();

}

});

builder.Services.AddTransient<Repository>();

var app = builder.Build();

// Configure the HTTP request pipeline.

...

这段代码会检查环境变量的值,并据此注册相应的服务。这无疑是 ASP.NET Core 依赖注入的一大优势。

JSON 文件的依赖注入

通过使用依赖注入技术,您还可以将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();

// Configure the HTTP request pipeline.

...

现在,您可以在任何控制器或视图中读取此 JSON 文件中的值。因此,请创建一个名为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();

}

}

}

从 JSON 读取的值将以两个 ViewData 变量的形式返回给视图。

因此,请在"视图"➤"设置"文件夹中添加"索引"视图,并将以下代码添加到其中:

@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>

}

运行您的应用程序,然后访问 SettingsController 的 URL,在我的示例中为https://localhost:44301/Settings。您将看到视图中显示的 JSON 文件中的值。请参见下面的屏幕截图。

视图中的依赖注入

ASP.NET Core 支持使用指令将依赖项注入 @inject到视图中。我将给出两个示例来帮助理解这一点。

  1. 从 JSON 文件注入值

就像我在上一篇主题" JSON文件的依赖注入"中所做的那样,这次我将直接在视图中注入mysettings.json文件中的值。

请记住,我在前面的章节中已经在 Program.cs 文件中完成了配置部分。

向SettingsController添加一个名为Show的新操作。

public IActionResult Show()

{

return View();

}

接下来,添加名为Show.cshtml的视图,并将以下代码添加到其中。

@using Microsoft.Extensions.Options;

@using 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 值由给定的代码显示。

@settingsOptions.Value.Title

@settingsOptions.Value.Version

运行您的应用程序并访问 URL -- https://localhost:44301/Settings/Show。您将在视图中看到显示的值(见下图)。

  1. 配置依赖注入

appsettings.json 中的值可以直接注入到视图中。操作非常简单,只需使用 inject 指令,然后显示这些值即可。以下代码演示了如何操作。

@inject IConfiguration Configuration

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

我的appsettings.json文件包含以下值,我将在视图中显示这些值。

{

"Logging": {

"LogLevel": {

"Default": "Information",

"Microsoft": "Warning",

"Microsoft.Hosting.Lifetime": "Information"

}

},

"AllowedHosts": "*"

}

我将显示节点的值------Default、Microsoft 和 Microsoft.Hosting.Lifetime。

前往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:Microsoft"]</td>

</tr>

<tr>

<td>Microsoft.Hosting.Lifetime</td>

<td>@Configuration["Logging:LogLevel:Microsoft.Hosting.Lifetime"]</td>

</tr>

</table>

请访问以下网址进行测试:https://localhost:44301/Settings/Detail。您将看到appsettings.json中的值,如下图所示。

参考文章:https://www.yogihosting.com/aspnet-core-dependency-injection/

果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
昊坤说不出的梦4 小时前
【实战】监控上下文切换及其优化方案
java·后端
疯狂踩坑人4 小时前
【Python版 2026 从零学Langchain 1.x】(二)结构化输出和工具调用
后端·python·langchain
橘子师兄5 小时前
C++AI大模型接入SDK—ChatSDK封装
开发语言·c++·人工智能·后端
@ chen6 小时前
Spring事务 核心知识
java·后端·spring
一点技术7 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
RANCE_atttackkk7 小时前
Springboot+langchain4j的RAG检索增强生成
java·开发语言·spring boot·后端·spring·ai·ai编程
好好研究9 小时前
Spring Boot - Thymeleaf模板引擎
java·spring boot·后端·thymeleaf
爬山算法9 小时前
Hibernate(76)如何在混合持久化环境中使用Hibernate?
java·后端·hibernate
她说..9 小时前
策略模式+工厂模式实现单接口适配多审核节点
java·spring boot·后端·spring·简单工厂模式·策略模式