Blazor University (46)依赖注入 —— Transient 依赖

原文链接:https://blazor-university.com/dependency-injection/dependency-lifetimes-and-scopes/transient-dependencies/

Transient 依赖

Transient 依赖是最容易理解的。在构建注册为 Transient 的可注入依赖项时,依赖项容器只是充当工厂。一旦实例被创建并注入到依赖组件中,容器就不再对它感兴趣了。

警告:这仅适用于未实现 IDisposable 的实例。为避免潜在的内存泄漏,请阅读本节底部的避免内存泄漏部分。

为了说明 Transient 依赖的生命周期,我们将创建一个简单的应用程序,以便我们可以查看对象实例的创建时间。

Transient 依赖示例

源代码[1]

首先,创建一个新的 Blazor 服务器应用。然后新建一个名为 Services 的文件夹,添加如下界面。这是我们的 UI 将用来显示由依赖容器创建并注入到我们的组件中的对象的实例编号的服务。每个实例将其 InstanceNumber 设置为下一个可用的序列号。

public interface IMyTransientService
{public int InstanceNumber { get; }
}

为了实现这个接口,我们将编写一个带有静态整数字段的类,我们可以使用它来确定下一个可用的序列号。该字段将被标记为 volatile 并使用 System.Threading.Interlocked.Increment 进行更改,因此我们可以跨多个线程修改该字段,而无需进行任何线程锁定。

public sealed class MyTransientService : IMyTransientService
{public int InstanceNumber { get; }private static volatile int PreviousInstanceNumber;public MyTransientService(){InstanceNumber = System.Threading.Interlocked.Increment(ref PreviousInstanceNumber);}
}

注册我们的依赖

在服务器端应用程序中编辑 Startup.ConfigureServices 并添加以下代码:

services.AddTransient<IMyTransientService, MyTransientService>();

在 WebAssembly 应用程序中编辑 Program.Main 并在调用 builder.Build() 之前添加以下代码。

builder.Services.AddTransient<IMyTransientService, MyTransientService>();

使用 Transient 依赖

为了使用这种 Transient 依赖,我们将创建一个组件,以便我们可以在主页上显示使用组件的多个实例。该组件将简单地声明一个注入的依赖项,然后显示它的 InstanceNumber

Shared 文件夹中,创建一个名为 MyStandardComponent.razor 的新组件,并为其添加以下标记。

@inject IMyTransientService TransientService<p>Instance = @TransientService.InstanceNumber</p>

演示 Transient 生命周期

接下来,我们将编辑 Index.razor,以便我们可以通过选中或取消选中复选框来显示/隐藏该组件的实例。除非选中相关复选框,否则我们的标记不会呈现组件的实例。因为 Blazor 仅在需要时创建组件实例,所以切换复选框将在它显示时重新创建我们的组件,并允许它在不显示时被垃圾回收。

<div><input id="show-first" type="checkbox" @bind=ShowFirst /><label for="show-first">Show first</label>@if (ShowFirst){<MyStandardComponent />}
</div><div><input id="show-second" type="checkbox" @bind=ShowSecond /><label for="show-second">Show second</label>@if (ShowSecond){<MyStandardComponent />}
</div>@code
{bool ShowFirst;bool ShowSecond;
}
  • 第 19-20 行

    声明布尔字段以确定是否应创建和呈现两个组件中的每一个。

  • 第 2 行

    在复选框上使用双向绑定,因此我们可以在 falsetrue 之间切换布尔字段。

  • 第 5 行

    如果相关字段为 true,则显示 MyStandardComponent 的一个实例。

运行应用程序

当应用程序第一次运行时,两个布尔字段都将为 false,因此两个 MyStandardComponent 标记都不会被呈现。

94f0a10c9b33e18a6cbff72ea054e2b4.jpeg

当我们选中其中一个复选框时,它将双向绑定到其相关的布尔字段,将其设置为 true。然后,用户交互将导致组件的重新渲染,从而导致我们的 MyStandardComponent 实例之一被渲染 - 因此 Blazor 将创建它的一个实例并注入一个新创建的 MyTransientService,其 InstanceNumber 为 1。

下图显示了当“Show second”是第一个要选中的复选框时的预期输出。

e326bac10307cd1baf55fa4f89520413.jpeg

选中另一个复选框将再次导致重新渲染,另一个 MyStandardComponent 将被创建并使用 InstanceNumber 为 2 的依赖项进行渲染,因为注入其中的 Transient 依赖项是按需创建的。

f16983e5e0cb969b39316cfc4c0b68e5.jpeg

每当我们取消选中一个复选框时,我们的页面标记将不再呈现相关的 MyStandardComponent,因为它只是基于 @if 语句有条件地呈现。当它被取消选中并且页面重新渲染时,现有组件不再被引用并且允许被垃圾收集。

当我们选中同一个复选框时,我们的条件将得到满足,我们的页面将呈现相关的 MyStandardComponent,将创建一个新实例,将创建一个 MyTransientService 的新实例以注入其中,我们将看到一个显示 3 的组件为其 InstanceNumber

5210da35c3d89f10caa3434fc3e45c3a.jpeg

  1. 该页面在没有创建任何组件的情况下呈现。

  2. 选中第 2 个复选框,将 ShowSecond 设置为 true。

  • 页面重新渲染,第 2 个组件可见。

  • 我们组件的一个新实例被创建。

  • 我们的 transient 服务的一个新实例(实例 1)被创建并注入到组件中。

选中第 1 个复选框,将 ShowFirst 设置为 true。

  • 页面重新渲染,第  1 个组件可见。

  • 我们组件的一个新实例被创建。

  • 我们的 transient 服务的一个新实例被创建(实例 2)并注入其中。

第 1 个复选框未选中,将 ShowFirst 设置为 false。

  • 第一个组件不再呈现,因此它会被垃圾回收。

  • 再次选中第 1 个复选框,将 ShowFirst 设置为 true。

  • 页面被重新渲染。

  • 我们组件的一个新实例被创建。

  • 我们的 transient 服务(实例 3)的一个新实例被创建并注入其中。

避免内存泄漏

如果类不实现 IDisposable,则仅将其注册为 Transient 依赖项,否则,您的应用程序将泄漏内存。

默认情况下,Microsoft 依赖注入容器将简单地创建注册为 Transient 的依赖项实例,然后忘记它们。当这些实例被注入的组件被收集后,这些实例就会被垃圾收集。

从历史上看,Microsoft 依赖注入框架在 ASP.NET 应用程序中被广泛使用,其中为传入的 Web 请求创建一个容器,然后在请求结束时将其处理掉。

为了避免开发人员不得不释放任何注入的依赖项的不便,Microsoft 依赖项注入容器将在释放时自动对任何实现 IDisposable 的对象调用 Dispose

为此,每当它创建一个实现 IDisposable 的实例时,容器必须存储对所创建实例的引用,以便调用它的 Dispose 方法。这意味着当创建 Transient 依赖项时,行为会根据实例是否是一次性的而有所不同。

Transient 对象通常在它们被注入的对象符合垃圾回收条件后才符合垃圾回收条件——除非它们实现了 IDisposable,在这种情况下,注入容器还将持有对创建的瞬态 IDisposable 的引用,然后它才符合垃圾回收条件,一旦创建它的容器有资格进行垃圾回收,就进行回收。

Blazor 中的依赖注入容器一直存在,直到用户关闭浏览器中包含 Blazor 应用程序的选项卡。这意味着除了在需要时创建 Transient 依赖项的新实例外,容器还将永远保留它们——导致内存泄漏。

有一种方法可以为每个组件创建一个依赖范围(因此它会在组件被释放时被释放),这将在后面的部分中介绍。

如果您想将依赖项注册为 Transient,最好避免对完全实现 IDisposable 的类这样做。

总结

将可注入依赖项注册为 Transient 使我们的依赖项容器充当该类型实例的工厂。同一个实例不能自动注入多个消费类,每个注入的实例总是唯一的。

实现 IDisposable 的类不应注册为 Transient,除非使用拥有自己 Scope 的组件,并且您确切地知道自己在做什么(您已阅读 Scoped 依赖项部分)。

参考资料

[1]

源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/DependencyInjection/TransientLifetimes

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

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

相关文章

AM335x 添加 HUAWEI MU609 Mini PCIe Module,并用pppd 启动相关设备

kernel 的配置kernel 3.2.0make menuconfigDevice Drivers --->[*] USB support ---><*> USB Serial Converter support ---><*> USB driver for GSM and CDMA modems kernel 3.2.0make menuconfigDevice Drivers --->[*] Network device supp…

深度挖掘 Laravel 生命周期

本文首发于个人博客 深度挖掘 Laravel 生命周期&#xff0c;转载请注明出处。这篇文章我们来聊聊 「Laravel 生命周期」 这个主题。虽然网络上已经有很多关于这个主题的探讨&#xff0c;但这个主题依然值得我们去研究和学习。 我想说的是当我们在决定使用某项技术的时候&#x…

构建LAMP平台及应用系统

LANP架构指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括linux操作系统、apache网站服务器、mysql数据库服务器、PHP&#xff08;或Perl、Python&#xff09;网页编程语言。在构建LAMP平台时…

C# DataRow 转 Model 对象 再也不用一个字段一个字段去写了

/*************************************************************************************** 文 件 名: DalUtiles.cs* 描 述: * * 版 本&#xff1a; V1.0* 创 建 者&#xff1a; JackieZheng* 创建时间&#xff1a; 2022/10/16 下午 05:42* * 历史更新记录* 版本…

pyqt2_官网教程

sklearn实战-乳腺癌细胞数据挖掘&#xff08;博主亲自录制视频&#xff09; https://study.163.com/course/introduction.htm?courseId1005269003&utm_campaigncommission&utm_sourcecp-400000000398149&utm_mediumshare Articles You can find a collection of P…

VUE页面发布后显示空白 原因之一及解决办法

<template><div><div></div></div><el-dialog></el-dialog> </template> 改为&#xff1a; <template><div><div></div><el-dialog></el-dialog></div> </template> …

Windows10安装WSL2和Ubuntu的过程

因为在Windows10环境中安装了2个相同的包导致冲突&#xff0c;所以想到了通过WSL2Docker的方式进行编程开发。因为Docker Desktop直接安装就行了&#xff0c;不做介绍。本文主要介绍WSL2和Ubuntu的安装过程。一.安装前的环境准备1.升级Windows系统因为低于某个版本号不支持WSL2…

Hyper-V数据文件丢失解决方案(有图有真相)

一、Hyper-V虚拟化故障概述 1、虚拟机环境故障虚拟化环境为ESXI虚拟化服务器&#xff0c;虚拟机环境&#xff0c;虚拟机的硬盘文件和配置文件放在北京某服务器托管公司的DELL MD3200存储中&#xff08;存储由5块容量为600G的硬盘组成raid磁盘阵列&#xff09;。该存储中4块硬盘…

关于bedtools merge 功能中sort 命令的解释

Bedtools 是一个很好的用来处理区间的工具&#xff0c;很多时候用这个底层语言编写的小工具比自己写的脚本运行快很多&#xff0c;但是这个工具中的某些功能对输入文件有一定的要求&#xff0c;比如说里面的一个merge函数&#xff0c;这是里面的一个note&#xff1a; Note&…

cocos2dx 3.x(屏幕截图的两种方法)

【RenderTexture】 RenderTexture这个动态纹理类&#xff0c;顾名思义就是可以动态创建纹理图片。 屏幕截图主要步骤&#xff1a; > 开始截图&#xff1a;render->begin(); > 遍历场景&#xff1a;scene->visit(); > 结束截图&#xff1a;render->end(); >…

SQL小技巧,动态输出本周各天日期

SET DATEFIRST 1; --设置周一为每周第一天 SELECT DATEFIRST;WITH w AS(SELECTCONVERT(varchar(10),T.[Date],120) AS [Date],DATENAME(weekday, T.[Date] ) AS [Week],DATEPART(WK, T.[Date]) AS WeekIndexFROM(SELECTDATEADD(DAY, number, DATEADD(wk, DATEDIFF(wk, 0, get…

开源的价值观与文化的传递

| 作者&#xff1a;Sharan Foga, Apache 软件基金会董事&#xff08;2021 届、2022 届&#xff09;&#xff0c;曾亲身来到 2019 中国开源年会&#xff08;COSCon19&#xff09;以本文内容发表主题演讲。| 翻译&#xff1a;刘天栋.Ted&#xff0c;徐红伟.stronghx| 审阅&#x…

用python来更改小伙伴的windows开机密码,不给10块不给开机

今天教大家用python脚本来控制小伙伴们windows电脑的开机密码。没错就是神不知鬼不觉&#xff0c;用random()随机生成的密码&#xff0c;只有你自己知道哦~ 代码呢分两部分&#xff0c;一部分是client端跟server端两个。你只需要想办法让小伙伴运行你的client端脚本就OK啦。不过…

Vue中@click.stop与@click.prevent

Vue中click.stop与click.prevent 一、click.stop 问题&#xff1a;父元素中添加了一个click事件&#xff0c;其下面的子元素中也添加了click事件&#xff0c;此时&#xff0c;我想点击子元素获取子元素的点击事件&#xff0c;但却触发的是父元素的事件&#xff1a; <view cl…

ES6 promise

如何使用promise对象? 参考连接&#xff1a; http://es6.ruanyifeng.com/#docs/promise 转载于:https://www.cnblogs.com/taoshengyijiuai/p/6963279.html

巧用ThreadPool.QueueUserWorkItem实现接口二次调用

背景最近做了个项目有个接口涉及到批量计算的问题&#xff0c;耗时比较长。大家都知道&#xff0c;接口等待时间太长肯定是不可取的。那么只能做异步处理了&#xff1b;但是问题来了这个项目没有什么消息队列、redis之类的使用&#xff0c;本着怎么简单怎么来的思路&#xff0c…

el-upload 防止选择上传重复文件

<el-uploadref"uploadRef"multipledragaction"":auto-upload"false":file-list"msgPara.MsgFileList":on-change"handleFileChanged" ><el-button type"primary">选择文件</el-button> </el…

jmete 学习--基础之名词解释

一.jmeter 体系结构 1.名词解释 元件 jmemter工具菜单中的一个子菜单&#xff0c;如http请求&#xff0c;事务控制器等&#xff0c;就是一个元件。 组件 一组元件的集合&#xff0c;比如逻辑控制器中有事务控制器&#xff0c;仅一次控制器等&#xff0c;这些都是hi元件&#x…

Testing - 软件测试知识梳理 - 自动化测试

软件开发的过程是一个持续集成和改进的过程&#xff0c;而每一次的改进都可能引进新bug,因此当软件的一部&#xff0c;或者全部修改时&#xff0c;都需要对软件产品重新进行测试。 其目的是要验证修改后的产品是符合需求的&#xff0c;而当没有自动化测试代码时&#xff0c;往往…