ASP.NET Core 依赖注入系列一

news2024/12/28 3:48:12

什么是ASP.NET Core 依赖注入? 依赖注入也称DI是一项技术用来实现对象松耦合以至于应用程序更容易维护,ASP.NET Core通过控制器的构造函数自动注入依赖的对象,我们创建ASP.NET Core MVC应用程序演示依赖注入特性是如何工作, 在这节中我们讲解该特性

1 例子

我们创建一个ASP.NET Core MVC的应用程序

1.1 Repository

新建一个Product实体类,为了简单我们将数据存储在应用程序的内存中而不是数据库中,在Models中添加Products类,代码如下

namespace AspNetCore.DependencyInjection.Models{    public class Product    {        public string Name { get; set; }        public decimal Price { get; set; }    }}

接下来,在Models文件夹下创建一个接口名字为IRepository,这个接口中包含了最基本的方法新增,读取和删除产品,接口的代码如下:

namespace AspNetCore.DependencyInjection.Models{    public interface IRepository    {        IEnumerable<Product> Products { get; }        Product this[string name] { get; }        void AddProduct(Product product);        void DeleteProduct(Product product);    }}

现在我们在Models文件夹下创建一个Repository类继承自IRepository接口

namespace AspNetCore.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);    }}

我们在Dictionary中创建了3条数据,在该类中实现了接口中的所有成员

1.2 Controller & Views

我们修改一下HomeController.cs文件将我们的产品显示在视图上,因此更新Index方法

namespace AspNetCore.DependencyInjection.Controllers{    public class HomeController : Controller    {        public IActionResult Index()        {            return View(new Repository().Products);        }    }}

可以清楚的看到在Index方法中,创建一个Repository实例并且调用了Products属性(new Repository().Products), 这个属性返回字典中存储的所有产品,我们最后将这些数据返回到视图

HomeController以紧耦合方式依赖Repository类,我们使用依赖注入技术实现松耦合

我们现在更新一下Views->Home的Index视图:

@{    ViewData["Title"] = "Home Page";}@model IEnumerable<Product><div class="row mb-3">    <div class="col-sm">        <table class="table table-bordered align-middle">            <thead>                <tr>                    <th>名称</th>                    <th>价格</th>                </tr>            </thead>            <tbody>                @foreach (var product in Model)                {                    <tr>                        <td>@product.Name</td>                        <td>@string.Format("{0:C2}",product.Price)</td>                    </tr>                }            </tbody>        </table>    </div></div>

这个视图通过循环Model中的数据读取产品信息,显示所有的产品在表格中,运行应用程序我们将看到3个产品信息

2 使用DI来解决紧耦合

如果你看到控制器中代码你将发现紧耦合Repository.cs类,原因是我们直接创建了一个Repository对象使用下面代码:

return View(new Repository().Products);

假设一段时间后我们需求发生一些变化,我们需要将repository改变为NewRepository,因此我们需要修改控制器中的代码:

public IActionResult Index(){    return View(new NewRepository().Products);}

这是一个如何管理紧耦合组件的问题,我们为什么避开紧耦合组件?

1 它给项目维护带来了很多问题,如果一个组件改变会影响另外一个组件

2 对这些组件进行单元测试时会出现很多问题

依赖注入技术解决了这些问题,ASP.NET Core 会为控制器自动提供repository对象,这将移除紧耦合的问题

3 在控制器中实现依赖注入

如何在ASP.NET Core中实现依赖注入? 我们可以通过注册服务来解决这个问题,ASP.NET Core DI将解析依赖,在ASP.NET Core 控制器中2个步骤可以实现DI

1 移除控制器中紧耦合,添加新松耦合的依赖

2 新的依赖在ASP.NET Core 中如何解析

首先我们创建一个松耦合的依赖在控制器中,这个我们将实现一个接口并且在控制器中使用这个接口,更新一下HomeController代码因此使用这个接口来创建依赖,代码如下:

namespace AspNetCore.DependencyInjection.Controllers{    public class HomeController : Controller    {        private IRepository _repository;        public HomeController(IRepository repository)        {            _repository= repository;        }        public IActionResult Index()        {            return View(new Repository().Products);        }    }}

我们在控制器中做了2件事情

1 在控制器中添加接口IRepository

2 添加了一个构造函数,构造函数的参数是接口类型,在构造函数中我们使用构造函数参数设置接口变量的值

使用这个我们可以添加松耦合依赖在构造函数,现在你的action方法可以访问IRepository接口的方法

最后我们需要告诉ASP.NET Core 如何解析IRepository接口依赖,进入应用程序的Program.cs文件并且为DI容器注册新的服务,我们将通过下面代码完成这个工作

​​​​​​​

using AspNetCore.DependencyInjection.Models;var builder = WebApplication.CreateBuilder(args);builder.Services.AddTransient<IRepository, Repository>();// Add services to the container.builder.Services.AddControllersWithViews();var app = builder.Build();

现在运行应用程序,你将会看到产品显示在页面上,这里我们使用了DI将控制器和Repository类解耦,假设在一段时间后我们需要从另外一个类NewRepository.cs展示产品,你只需要修改一下下面代码就可以了

builder.Services.AddTransient<IRepository, NewRepository>()

4 依赖注入针对单个类型

如果你有一个简单的类没有实现任何接口,该类是一个简单类型,让我们了解如何在这个例子中使用DI,在Models文件夹中创建一个新的类叫ProductSum.cs并添加如下代码

namespace AspNetCore.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接口通过ServiceProvider来解析,我们在之前已经做了配置

在HomeController的构造函数中创建一个ProductSum类的依赖,并且设置一个ViewBag变量包含所有产品的总和,这个ViewBag值将显示在视图,更新HomeController的代码:

namespace AspNetCore.DependencyInjection.Controllers{    public class HomeController : Controller    {        private IRepository _repository;        private ProductSum _productSum;        public HomeController(IRepository repository, ProductSum productSum)        {            _repository = repository;            _productSum = productSum;        }        public IActionResult Index()        {            return View(new Repository().Products);        }    }}

在Program类中添加下面代码:

using AspNetCore.DependencyInjection.Models;var builder = WebApplication.CreateBuilder(args);builder.Services.AddTransient<IRepository, Repository>();builder.Services.AddTransient<ProductSum>();// Add services to the container.builder.Services.AddControllersWithViews();var app = builder.Build();

在这里我们使用了AddTransient()只有一个参数,以这种方式告诉ServiceProvider初始化ProductSum类并解析这个类型的依赖,这个依赖注入单个类型,没有任何接口

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/670476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指offer45 把数组排成最小的数

剑指offer45 把数组排成最小的数 文章目录 剑指offer45 把数组排成最小的数题目描述思路实现参考文献 题目描述 输入一个非负整数数组&#xff0c;把数组里的所有数字拼接起来排成一个数&#xff0c;打印能拼接出来的所有数字中最小的一个。 思路 此题求拼接起来的最小数字&…

Selenium教程__使用switch_to.window方法处理窗口切换(12)

想一下这样的场景&#xff0c;打开页面A点击一个链接&#xff0c;在一个新的窗口打开页面B&#xff0c;由于之前的driver实例对象在页面A&#xff0c;但是你接下来操作的元素在页面B中&#xff0c;此时脚本就会报错找不到元素。该场景需要使用到selenium的switch_to.window&…

CMake 编译并链接动态库

问题描述 目录结构如下&#xff1a; |---CMP|---mmath|---mmath.h|---mmath.cpp|---CMakeLists.txt|---CMP.cpp|---CMakeLists.txt需要把mmath子项目编译成动态链接库并被CMP.cpp调用 代码如下&#xff1a; //mmath.h namespace mmath { int __declspec(dllexport) add(int…

Python基础(20)——Python函数讲解二

Python基础&#xff08;20&#xff09;——Python函数讲解二 文章目录 Python基础&#xff08;20&#xff09;——Python函数讲解二目标一. 变量作用域二. 多函数程序执行流程三. 函数的返回值四. 函数的参数4.1 位置参数4.2 关键字参数4.3 缺省参数4.4 不定长参数 五. 拆包和交…

pytest和ValueError: Expect x to not have duplicates(个人笔记)

1.项目在新环境报错为没有pytest 解决办法&#xff1a; 在设置里面的Tools里面的某个选项改为&#xff08;如下图&#xff09; 2.同一个项目在旧电脑正常运行&#xff0c;到了新电脑新环境莫名报错 报错为 interpolate.interp1d里面的某个函数报错 具体报错为&#xff1a;Valu…

Bean属性校验

Servlet是一个规范&#xff0c;Tomcat实现的 JDBC是一个规范&#xff0c;各个厂商实现的 JSR303也是一个规范&#xff0c;有人提供实现 我们只需要面向接口编程即可。 一般来说&#xff0c;以javax开头的groupId&#xff0c;都是规范 JSR303提供规范&#xff0c;其余框架实现规…

软考A计划-系统集成项目管理工程师-信息化系统的生命周期-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

Mysql数据库操作总结

文章目录 1. DDL(Data Definition Language - 数据定义语言)1.1 数据库1.2 数据表(创建查询删除)1.3 数据表(修改) 2. 数据类型2.1 数值2.2 字符2.3 日期 3. 字段约束3.1 约束3.2 主键约束修改3.3 主键自增 联合主键 4. DML(Data Manipulation Language - 数据操作语言)4.1 添…

本地搭建svn仓库 + 调试svn hooks

本地搭建SVN仓库 调试svn hooks : 文章目录 本地搭建SVN仓库 调试svn hooks :1. 环境准备&#xff1a;2. 搭建本地仓库的过程&#xff1a;3. 将写好的svn hooks pre-commit.bat放到hooks目录内。4. 创建仓库的本地working copy: 1. 环境准备&#xff1a; 需要安装TortoiseSV…

APP专项测试之——网络测试

软件网络测试考虑四种状态下的测试 1、正常网络 wifi&#xff1a;无线网络情况下&#xff0c;软件可正常使用 流量&#xff1a;手机数据情况下&#xff0c;软件可正常使用 2、弱网 概念&#xff1a;在厕所&#xff0c;电梯&#xff0c;停车场&#xff0c;地下商场等封闭性的…

python 包(模块)制作

文档&#xff1a;Quickstart - setuptools 68.0.0.post20230619 documentation 目录结构 sdk目录里面存放源码 在setup.py所在层级目录下执行如下命令既可生成wheel文件 python setup.py sdist bdist_wheel 上传: 需要把生成的.wheel文件上传到 pypi上&#xff0c;才能使用pi…

优秀的测试用例是如何设计的?

这篇文章我们主要聊一下测试工程师最通用的也是最根本的技能&#xff0c;测试用例的设计能力。 测试用例 测试用例是通过使用在测试计划中确定的测试技术&#xff0c;对于已确定的测试条件进行逐步推敲&#xff0c;精炼而设计出来的重点说明如何具体操作产生何种结果的文档。…

Linux自主学习 - 2

一、gcc编译器 第一个HelloWorld 1、查看当前工作目录/home/yang/coding下为空 2、使用vim写一个C源程序hello.c 进入vim界面后&#xff0c;按下i键进入编辑模式&#xff0c;vim窗口下方出现“INSERT”字样 编辑完成后&#xff0c;先按ESC键退出编辑模式&#xff0c;然后输入:…

onnxruntime推理

pytorch模型训练 这里以pytorch平台和mobilenet v2网络为例&#xff0c;给出模型的训练过程。具体代码如下所示&#xff1a; import os import torchvision.transforms as transforms from torchvision import datasets import torch.utils.data as data import torch import…

Java面试题Class类的理解?创建类的对象的方式?

1.Class类的理解 1.类的加载过程&#xff1a; 程序经过javac.exe命令以后&#xff0c;会生成一个或多个字节码文件(.class结尾)。 接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件 加载到内存中。此过程就称为类的加载。加载到内存中的类&…

一起来了解多领域自动采样器的功能特点

多领域自动采样器体积小&#xff0c;便携式设计&#xff0c;功能丰富&#xff0c;操作简便可用于海洋、河流、船舶、沟渠、深井、排污口等多种场景的水样采集&#xff0c;尤其适用于窨井、下水道、沟渠 等空间狭小、现场条件恶劣的工作场合&#xff0c;可以在环保、科研、污水验…

【计算机组成原理】辅助存储器

目录 一、磁盘存储器 二、固态硬盘SSD 三、虚拟存储系统 一、磁盘存储器 大多数计算机外存储器采用磁盘记录&#xff0c;如今正在逐渐被SSD固态硬盘取代 磁表面存储&#xff1a;磁性材料薄层涂在金属或塑料表面做磁载体存储信息 硬磁盘存储器&#xff1a;基底&#xff08;磁…

【深度学习】近万字解读深度学习领域有哪些瓶颈?

文章目录 一、导读二、深度学习缺乏理论支撑三、领域内越来越工程师化思维四、对抗样本是深度学习的问题&#xff0c;但不是深度学习的瓶颈五、知乎网友的回答5.1 作者&#xff1a;Giant5.2 作者&#xff1a;知乎用户5.3 作者&#xff1a;何之源 一、导读 虽然深度学习在图像、…

Java去掉 txt 文件中的空格空行【代码记录】

文章目录 1、需求2、代码3、结果 1、需求 2、代码 package com.zibo.main;import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern;public cla…

外卖商城平台微信小程序 后端ssm

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 外卖商城平台微信小程序 前言一、组织结构二、使用步骤1.后端登录代码2.运行截图 源代码 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 本外卖商城…