ASP.NET Core MVC依赖注入理解(极简个人版)
依赖注入
文献来源:《Pro ASP.NET Core MVC》 Adam Freeman 第18章 依赖注入
1 依赖注入原理
- 所有可能变化的地方都用接口
- 在使用接口的地方用什么实体类通过在
ConfigureService中注册解决 - 注册的实体类需要指定在何种生命周期中有效
- Transient
- Scoped
- Singleton
2 接口
接口只定义契约,不定义实现。

//IRepository.cs
using System.Collections.Generic;
namespace DependencyInjection.Models{public interface IRepository{IEnumerable<Product> Products{get;}Product this[string name]{get;}void AddProduct(Product product);void DeleteProduct(Product product);}
}//MemoryRepository.cs
using System.Collections.Generic;namespace DependencyInjection.Models{public class MemoryRepository:IRepository{private Dictionary<string, Product> products;public MemoryRepository(){products = new Dictionary<string, Product>();new List<Product{new Product{Name="Kayak", Price=275M},new Product{Name="Lifejacket", Price=48.95M},new Product{Name="Soccer ball", Price=19.50M},}.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 数据绑定页面
页面绑定代码使用@model和ViewBag实现。
//Index.cshtml
@using DependencyInjection.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model IEnumerable<Product>
@{layout=null;}<!DOCTYPE html>
<html><head><meta name="viewport" content="width=device-width" /><title>Dependency Injection</title><link rel="stylesheet" asp-href-include="lib/bootstrap/dist/css/*.min.css" /></head><body class="panel-body">@if(ViewData.Count>0){<table class="table table-bordered table-condense table-striped">@foreach(var kvp in ViewData){<tr><td>@kvp.Key</td><td>@kvp.Value</td></tr>}</table>}<table class="table table-bordered table-condense 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></body>
</html>
该页面绑定了2组数据集
ViewData集合@model IEnumerable<Product>
后台绑定
//HomeController.cs
//使用实体类的Products属性绑定页面
using Microsoft.AspNetCore.Mvc;
using DependencyInjection.Models;public class HomeController:Controller{public ViewResult Index() => View(new MemoryRepository().Products);
}
4 ASP.NET MVC定义依赖注入
4.1 接口依赖注入
- 单实例依赖注入
首先将后台处理由指定的实体类换成接口
//HomeController.cs
using Microsoft.AspNetCore.Mvc;
using DependencyInjection.Models;
using DependencyInjection.Infrastructure;namespace DependencyInjection.Controllers{//增加接口私有变量private IRepository repository;//通过构造函数传参至该私有变量public HomeController(IRepository repo){repository = repo;}//绑定接口的Products属性//运行时由ASP.NET MVC框架确定使用何种实体类public ViewResult Index()=>View(repository.Products);
}
然后配置接口与实体类之间的关系
//Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using DependencyInjection.Infrastructure;
using DependencyInjection.Model;namespace DependencyInjection{public void ConfigureServices(IServicesCollection services){services.AddTransient<IRepository, MemoryRepository>();...}...
}
services.AddTransient告诉service provider如何处理依赖。这里要注意一点,service provider是整个MVC框架服务的总提供者。
-
链式依赖
某实体类依赖于某接口,且该实体类中的成员变量又依赖于另一接口。

//MemoryRepository.cs
using DependencyInjection.Models{public class MemoryRepository:IRepository{private IModelStorage storage;//新增私有变量用于指定所属的仓库public MemoryStorage(IModelStorage storage){storage = modelStorage;new List<Product>{new Product{Name="Kayak",Price=275M},new Product{Name="Lifejacket", Price=48.95M},new Product{Name="Soccer ball", Price=19.50M}}.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); }}
}
在ConfigureServices中注册。
//Startup.cs
...
namespace DependencyInjection{public class Startup{public void ConfigureServices(IServiceCollection services){services.AddTransient<IRepository, MemoryRepository>();services.AddTransient<IModelStorage, DictionaryStorage>();...}...}
}
4.2 实体类依赖注入
假设存在实体类ProductTotalizer用于计算总价。
using System.Linq;
namespace DependencyInjection.Models{public class ProductTotalizer{public ProductTotalizer(IRepository repo){Repository = repo;}//所述仓库用接口表示public IRepository Repository {get;set;}//总价public decimal Total => Repository.Products.Sum(p=>p.Price);}
}

在HomeController中加入ProductTotalizer变量。
...
public class HomeController:Controller{private IRepository repository;private ProductTotalizer totalizer;public HomeController(IRepository repo, ProductTotalizer total){repository = repo;totalizer = total;}public viewResult Index(){ViewBag.Total = totalizer.Total;return View(repository.Products);}
}
在Index.cshtml中包含了对ViewBag的显示,这里实际绑定了2个数据,第一个是ViewBag,第二个是repository。
为了明确在Controller中使用何种ProductTotalizer(可能在后面的开发中,ProductTotalizer是父类),可以对其进行强行指定。
//Startup.cs
...
public void ConfigureServices(IServicesCollection services){...services.AddTransient<ProductTotalizer>();...
}
5 服务生命周期
| 类别 | 生命周期 |
|---|---|
| Transient | 只要有调用就创建新的对象。就算类型一样,但是对象不一样 |
| Scoped | 在一个Controller之中,只要类型一样,对象就一样。刷新Controller之后对象变了,但是多个同一类型的对象还是同一个。 |
| Singleton | 只要初始化了,就一直是这个对象,不管是否刷新Controller |
5.1 Transient
首先在service provider中注册IRepository的调用使用MemoryRepository。
...
public void ConfigureServices(IServiceCollection services){services.AddTransient<IRepository, MemoryRepository>();...
}
...
在repository中加入ToString()函数,该函数的实现中包含了GUID的生成。
//MemoryRepository.cs
using System.Collections.Generic;
namespace DependencyInjection.Models{public class MemoryRepository:IRepository{private IModelStorage storage;private string guid = System.Guid.NewGuid().ToString();public MemoryRepository(IModelStorage modelStore){storage = modelStore;...}...public override string ToString(){return guid;}}
}
在下图中可以看到,当HomeController调用repository时,service provider会针对每一次调用都生成一个新的对象。

5.2 Scoped
其他的调用都一样,除了在service中注册使用AddScoped之外。
//Startup.cs
...
public void ConfigureServices(IServiceCollection services){service.AddScoped<IRepository, MemoryRepository>();...
}

5.3 Singleton
其他的调用都一样,除了在service中注册使用AddSingleton之外。
//Startup.cs
...
public void ConfigureServices(IServiceCollection services){services.AddSingleton<IRepository, MemoryRepository>();...
}
...

6 其他依赖注入
6.1 Action依赖注入
上述的依赖注入是针对整个Controller,但有的时候只想针对某一个Action进行依赖注入。此时只需要使用[FromServices]即可。
using Microsoft.AspNetCore.Mvc;
using DependencyInjection.Models;
using DependencyInjection.Infrastructure;namespace DependencyInjection.Controllers{public class HomeController:Controller{private IRepository repository;public HomeController(IRepository repo){repository = repo;}public ViewResult Index([FromServices]ProductTotalizer totalizer){ViewBag.HomeController = repository.ToString();ViewBag.Totalizer = totalizer.Repository.ToString();return View(repository.Products);}}
}
上述代码表示在Index中需要使用ProductTotalizer时,从service provider处获得。
6.2 手工进行依赖注入
除了上述的注册方式外,还有一些其他的注册方式。比如,当没有依赖出现时,而你又想获得一个接口的实例,该实例依赖于接口。在这种情况下,你可以直接通过service provider来实现。
...
public class HomeController:Controller{public ViewResult Index([FromServices]ProductTotalizer totalizer){IRepository repository=HttpContext.RequestServices.GetService<IRepository>();...}
}
...
相关文章:
ASP.NET Core MVC依赖注入理解(极简个人版)
依赖注入 文献来源:《Pro ASP.NET Core MVC》 Adam Freeman 第18章 依赖注入 1 依赖注入原理 所有可能变化的地方都用接口在使用接口的地方用什么实体类通过在ConfigureService中注册解决注册的实体类需要指定在何种生命周期中有效 TransientScopedSingleton 2…...
美光将于 2025 年推出 1γ DRAM,并在日本生产HBM
美国内存巨头美光正准备从 2025 年开始在其位于日本广岛的晶圆厂生产最先进的“1γ”DRAM。同时,公司计划在同一晶圆厂生产高带宽存储器(HBM),以满足对生成式人工智能应用日益增长的需求。 据《日经亚洲》12月13日报道࿰…...
【Docker】以service形式离线安装卸载的docker、compose服务
CentOS7离线卸载Docker步骤 移除开机自启 [rootCenOS-1 system]# systemctl disable docker移除注册文件 rm -rf /etc/systemd/system/docker.service删除相关安装目录 rm -rf $(find / -name docker)CentOS7离线安装Docker、Compose步骤 资源地址:docker_20.10…...
Dubbo RPC-Redis协议
Redis协议 特性说明 Redis 是一个高效的 KV 存储服务器。基于 Redis 实现的 RPC 协议。 2.3.0 以上版本支持。 使用场景 缓存,限流,分布式锁等 使用方式 引入依赖 从 Dubbo 3 开始,Redis 协议已经不再内嵌在 Dubbo 中,需要单…...
展开说说:Android之常用的延时执行策略
总结了以下六种常用的Android延时执行策略,以此记录: 1、TimerTask 2、Handler.postDelayed 3、Handler.sendEnptyMessageDelayeed 4、Thread.sleep线程休眠-需要在子线程 5、使用AlarmManager-全局定时器或者闹钟 6、Wait 首先定义一个时间常量&…...
Jenkins在window下配置Android打包配置
在Windows下配置Jenkins进行Android打包的步骤如下: 安装Jenkins:从Jenkins官网下载适用于Windows的安装包,并按照安装向导的指示完成安装。 启动Jenkins服务:启动Jenkins服务,确保服务正常运行。 配置Jenkins&#…...
云原生系列2-GitLab和Jenkins
1、GitLab类似github,是个私有仓库 1、GitLab安装,至少8G内存4核cpu # 查找Gitlab镜像 docker search gitlab/gitlab-ce # gitlab镜像拉取 docker pull gitlab/gitlab-ce # 查看镜像 docker images # 本机先建3个目录,为了gitlab容器通过挂…...
xcode无线真机调试详细图文步骤
步骤一、 步骤二: 步骤三: 配置完到这里,点击真机右键,菜单栏并未出现connect via ip address 选项,也没出现无线连接的小地球图标,别慌,接着进行下一步操作即可。 步骤四: 1.打开…...
EasyExcel合并相同内容单元格及动态标题功能的实现
一、最初版本 导出的结果: 对应实体类代码: import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.al…...
【论文解读】Comparing VVC, HEVC and AV1 using Objective and Subjective Assessments
时间:2020 级别:IEEE 机构: IEEE 组织 摘要: 对3种最新的视频编码标准HEVC (High Efficiency video Coding)测试模型HM (High Efficiency video Coding)、amedia video 1 (AV1)和Versatile video Coding测试模型 (VTM)进行了客观和…...
动态窗口法Dynamic Window Approach在动态环境中避障
以这个博主的代码为基础,加了一个碰撞检测,但是这个碰撞检测目前还不完善,思路应该是这个思路,以后有时间再完善吧。 动态窗口法:【路径规划】局部路径规划算法——DWA算法(动态窗口法)|&#…...
2023.12.15 FineBI与kettle
1.结构化就是可以用schema描述的数据,就是结构化数据,能转为二维表格, 如CSV,Excel, 2.半结构化就是部分可以转换为二维表格,如JSON,XML 3.非结构化数据,就是完全无法用二维表格表示的数据,如Word文档,Mp4,图片,等文件. kettle的流程 新建转换-构建流图-配置组件-保存运行 使…...
Python tkinter 初探Toplevel控件搭建父子窗口
目录 Toplevel控件搭建父子窗口 最简明的父子窗口框架 改进一:屏蔽和开放按钮 改进二:子窗口始终在主窗口之上 改进三:增加子窗口的关闭协议 改进四:使子窗口长获焦点 总结 Toplevel控件搭建父子窗口 最近,用P…...
SpringCloud源码探析(十二)-基于SpringBoot开发自定义中间件
1.概述 中间件是一种介于操作系统和应用软件之间,为应用软件提供服务功能的软件,按功能划分有消息中间件(Kafka、RocketMQ)、通信中间件(RPC通信中间件,dubbo等),应用服务器等。中间…...
基于CNN+数据增强+残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)+数据集+模型(一)
系列文章目录 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型(一) 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型…...
python实现贪吃蛇游戏
文章目录 1、项目说明2、项目预览3、开发必备4、贪吃蛇代码实现4.1、窗口和基本参数实现4.2、绘制背景4.3、绘制墙壁4.4、绘制贪吃蛇4.5、绘制食物4.6、实现长度信息显示4.7、定义游戏暂停界面4.8、定义贪吃蛇死亡界面4.9、实现贪吃蛇碰撞效果4.10、实现添加食物功能4.11、实现…...
ios备忘录怎么导入华为 方法介绍
作为一个常常需要在不同设备间切换的人,我深知备忘录的重要性。那些突如其来的灵感、重要的会议提醒、甚至是生活中的琐碎小事,我们都习惯性地记录在备忘录里。但当我决定从iPhone转向华为时,一个问题困扰了我:如何将那些珍贵的备…...
electron与cesium组件入门应用功能
electron与cesium组件入门应用功能 运行应用效果图: electron应用目录,需要包括三个文件: index.html main.js package.json (一)、创建一个新项目 目录名称:project_helloWolrd (二)、生成package.json文件 npm init --yes(三&#x…...
Jenkins Docker Cloud在Linux应用开发CI中的实践
Jenkins Docker Cloud在Linux应用开发CI中的实践 背景 通过代码提交自动触发CI自动构建、编译、打包是任何软件开发组织必不可少的基建,可以最大程度保证产物的一致性,方便跨组跨部门协作,代码MR等。 Docker在流水线中越来越重要ÿ…...
【NotebookLM播客化实战指南】:3步将静态文档转化为高转化率AI播客,92%用户留存提升实测数据曝光
更多请点击: https://intelliparadigm.com 第一章:NotebookLM文档播客化功能详解 NotebookLM 是 Google 推出的基于用户上传文档进行 AI 增强理解与交互的实验性工具,其“文档播客化”(Document Podcasting)功能允许用…...
保姆级教程:在Win10上用VS2022搞定TensorRT 8.5.2.2(含zlibwapi.dll缺失等常见坑点)
从零到一:Windows 10 VS2022 深度集成 TensorRT 8.5 全流程实战 TensorRT 作为 NVIDIA 推出的高性能深度学习推理引擎,能够显著提升模型在 NVIDIA GPU 上的执行效率。但对于 Windows 平台的新手开发者来说,从环境配置到第一个示例程序成功运…...
深入GORM源码:手把手教你为自定义字段打造专属‘Clause钩子’
深入GORM源码:手把手教你为自定义字段打造专属‘Clause钩子’ 在当今快速迭代的业务场景中,数据库操作早已不再是简单的CRUD。当我们面对复杂的状态流转、多租户隔离或敏感数据加密时,往往需要在数据持久化层植入特定的业务逻辑。GORM作为Go生…...
图解CA注意力机制:用Keras一步步拆解‘宽高分离池化’,理解位置信息如何嵌入通道注意力
图解CA注意力机制:用Keras拆解‘宽高分离池化’的视觉密码 当我们谈论注意力机制时,脑海中往往会浮现SE(Squeeze-and-Excitation)模块的通道加权画面。但今天要探讨的CA(Coordinate Attention)机制…...
STATA CLI:我把 Stata 接进了命令行,也接进了 AI 工作流
为什么要做这个工具 我写 stata-cli,不是因为想再造一个 Stata,也不是因为命令行天然高级,而是因为 Stata 明明是很多实证研究者最熟悉的工具,却一直很难进入现代自动化工作流。 做计量、做实证、做政策评估的人都知道,…...
终极指南:5分钟让Illustrator批量替换效率提升10倍
终极指南:5分钟让Illustrator批量替换效率提升10倍 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 还在为Adobe Illustrator中繁琐的批量替换工作而烦恼吗?&…...
Harness层数据清洗自动化
Harness层数据清洗自动化:解放数据团队生产力的核心方案 开篇引子 上周我帮一家年GMV超20亿的电商客户排查数据故障,他们的数仓团队反馈连续3天的用户订单报表交易额比实际支付金额少了1200万,排查了3个小时才定位到根因:新接入的外卖业务系统的订单状态字段新增了枚举值6…...
别再死磕ViT了!用Swin-Transformer搞定高分辨率图像识别,保姆级原理拆解
高分辨率图像识别新范式:Swin-Transformer实战指南 当计算机视觉工程师面对4K医学影像或卫星地图时,传统ViT模型往往会遭遇显存爆炸的尴尬。我曾在一个遥感项目中发现,直接将ViT应用于20482048像素的图像,单次前向传播就消耗了32G…...
AI辅助编程工具Cursor在经济学研究中的应用与实战指南
1. 从零开始:为什么经济学家需要AI辅助编程工具 如果你是一名经济学研究者、研究生或者研究助理,我猜你肯定经历过这样的场景:为了清洗一份来自世界银行或国家统计局的复杂面板数据,你对着Stata或者R的代码文档反复调试࿰…...
WeChatMsg:微信聊天记录本地化解析与多格式导出技术方案
WeChatMsg:微信聊天记录本地化解析与多格式导出技术方案 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeC…...
