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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【一】FPGA实现SPI协议之SPI协议介绍

【一】FPGA实现SPI协议之SPI协议介绍 一、spi协议解析 spi协议有4根线&#xff0c;主机输出从机输入MOSI、主机输入从机输出MISO、时钟信号SCLK、片选信号SS\CS 。 一般用于主机和从机之间通信。由主机发起读请求和写请求&#xff0c;主机的权限是主动的&#xff0c;从机是被…

深入理解 HTTP 和 HTTPS:提升你的网站安全性(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

《点云处理》 点云去噪

前言 通常从传感器&#xff08;3D相机、雷达&#xff09;中获取到的点云存在噪点&#xff08;杂点、离群点、孤岛点等各种叫法&#xff09;。噪点产生的原因有不同&#xff0c;可能是扫描到了不想要扫描的物体&#xff0c;可能是待测工件表面反光形成的&#xff0c;也可能是相…

【AI图集】猫狗的自动化合成图集

猫是一种哺乳动物&#xff0c;通常被人们作为宠物饲养。它们有柔软的毛发&#xff0c;灵活的身体和尖锐的爪子。猫是肉食性动物&#xff0c;主要以肉类为食&#xff0c;但也可以吃一些蔬菜和水果。猫通常在夜间活动&#xff0c;因此它们需要足够的玩具和活动空间来保持健康和快…

CentOS:Docker 创建及镜像删除

1、安装docker 远程连接服务器&#xff0c;可以直接下载netsarang比较好用 家庭/学校免费 - NetSarang Website 如果有残留docker未删除干净&#xff0c;请使用 sudo yum -y remove docker docker-common docker-selinux docker-engine Step1&#xff1a;安装必要的一些…

银河麒麟v10 安装mysql 8.35

银河麒麟v10 安装mysql 8.35 1、下载Mysql安装包2、安装Mysql 8.352.1、安装依赖包2.2、安装Mysql2.3、安装后配置 1、下载Mysql安装包 访问官网下载链接 链接: https://dev.mysql.com/downloads/mysql/ 选择如下 点击下载按钮 下载安装包 2、安装Mysql 8.35 官方安装文档…

substring从字符串中提取字符串【前闭后开)

截取指定大小的字符串subString包含两种重载方式&#xff1a; substring(int beginIndex):从指定的 beginIndex(包括)开始&#xff0c;提取字符串&#xff0c;直到字符串尾&#xff1b;substring(int beginIndex,int endIndex): 从指定的beginIndex&#xff08;包括&#xff0…

ansible(不能交互)

1、定义 基于python开发的一个配置管理和应用部署工具&#xff0c;在自动化运维中异军突起&#xff0c;类似于xshell一键输入的工具&#xff0c;不需要每次都切换主机进行操作&#xff0c;只要有一台ansible的固定主机&#xff0c;就可以实现所有节点的操作。不需要agent客户端…

论文降重方法同义词替换的实践体验 快码论文

大家好&#xff0c;今天来聊聊论文降重方法同义词替换的实践体验&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;论文降重方法同义词替换的实践体验 一、…

SQL进阶理论篇(十三):数据库的查询优化器是什么?

文章目录 简介什么是查询优化器查询优化器的两种优化方式总结参考文献 简介 事务可以让数据库在增删改查的过程中&#xff0c;保证数据的正确性和安全性&#xff0c;而索引可以帮数据库提升数据的查找效率。查询优化器&#xff0c;则是帮助我们获取更高的SQL查询性能。 本节我…

美术加盟培训机构管理系统源码开发方案

一、项目背景与目标 &#xff08;一&#xff09;项目背景 美术加盟培训机构管理系统源码开发方案旨在为美术加盟培训机构提供一套全面的管理解决方案&#xff0c;以提高机构的运营效率和管理水平。该系统将涵盖平台管理、潜在学员线索跟进管理、学员管理、排课消课、续费提醒…

马云笔下的AI电商时代,到底长啥样?

前两天&#xff0c;马云“惊现”阿里内网&#xff0c;正面回应拼多多市值接近阿里巴巴。 AI电商时代刚刚开始&#xff0c;对谁都是机会&#xff0c;也是挑战。要祝贺pdd过去几年的决策&#xff0c;执行和努力。谁都牛x过&#xff0c;但能为了明天后天牛而改革的人&#xff0c;…