界面开发框架DevExpress XAF实践:集成.NET Aspire后如何实现自定义遥测?

article/2025/8/27 4:09:48

DevExpress XAF是一款强大的现代应用程序框架,允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计,开发人员可以选择内建模块,也可以自行创建,从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。

.NET Aspire是一组工具、模板和包,用于构建可观察的、可生产的应用程序。DevExpress XAF团队花费了一些时间考虑Aspire的功能,试图找到最好的集成点,让XAF开发人员能够利用Aspire开箱即用的业务流程特性。

点击获取DevExpress最新版下载

在最近的一篇文章中我们介绍了如何对一个 XAF Blazor 项目进行调整,来支持 .NET Aspire(点击这里回顾>>)。通过对启动逻辑进行一些修改——包括标准的 XAF 项目模板和 Aspire 的 Visual Studio 向导生成的代码,已经可以让 XAF Blazor 项目作为 Aspire 编排体系的一部分运行了。但那只是最小规模的编排,只有一个模块!接下来我们将会把部署方面的内容留到第三篇(敬请关注!),接下来得系列文章将介绍在示例项目中为实现以下三个场景所做的修改:

  1. 通过 OpenTelemetry 将自定义活动和指标记录到 Aspire 仪表盘
  2. 将 SQL Server 作为一个由 Aspire 协调运行的容器化依赖项
  3. 在编排中添加一个额外的服务,展示更复杂的系统结构

完整示例项目已托管在这个 GitHub 仓库中。下面基于我在第一篇文章中描述的项目初始状态,展开说明新的功能实现。

利用 OpenTelemetry 支持自定义指标与活动日志

Aspire 仪表盘的集成,是许多应用项目在启用 Aspire 后最直观的新特性之一。正如在演示项目的第一步中看到的,启用默认的跟踪和指标来源非常简单。接下来我们就会思考:如何将遥测系统用于我们自己的场景,比如记录自定义日志、报告业务指标与活动?

第一步,我创建了文件 XafAspireDemo.Blazor.Server/Controllers/ImportantBusinessOperationsController.cs,它实现了一个基本的 XAF 控制器,并提供了一个动作(Action)。该操作会自动出现在用户界面中,因此可以用作交互式测试触发器。以下是代码:

namespace XafAspireDemo.Blazor.Server.Controllers
{
public class ImportantBusinessOperationsController : Controller
{
SimpleAction importantBusinessAction;
IServiceProvider serviceProvider;public ImportantBusinessOperationsController()
{
importantBusinessAction = new SimpleAction(
this,
"ImportantBusinessAction",
PredefinedCategory.View
);
importantBusinessAction.Execute += ImportantBusinessAction_Execute;
}[ActivatorUtilitiesConstructor]
public ImportantBusinessOperationsController(IServiceProvider serviceProvider)
: this()
{
this.serviceProvider = serviceProvider;
}private async void ImportantBusinessAction_Execute(
object sender,
SimpleActionExecuteEventArgs e
)
{
var logger = serviceProvider.GetRequiredService<
ILogger<ImportantBusinessOperationsController>
>();importantBusinessAction.Enabled["ImportantBusinessActionRunning"] = false;logger.LogInformation("ImportantBusinessAction started.");try
{
// This is where we perform the magic for the important business action.
// Run a task that waits a random time between half a second and five seconds.
await Task.Run(() =>
{
Thread.Sleep(new Random().Next(500, 5000));
});
}
catch (Exception ex)
{
logger.LogError(ex, "ImportantBusinessAction failed.");
throw;
}
finally
{
importantBusinessAction.Enabled["ImportantBusinessActionRunning"] = true;
}
}protected override void OnActivated()
{
base.OnActivated();var logger = serviceProvider.GetRequiredService<
ILogger<ImportantBusinessOperationsController>
>();
logger.LogInformation("ImportantBusinessOperationsController activated.");
}protected override void OnDeactivated()
{
var logger = serviceProvider.GetRequiredService<
ILogger<ImportantBusinessOperationsController>
>();
logger.LogInformation("ImportantBusinessOperationsController deactivated.");base.OnDeactivated();
}
}
}

如你所见,这段代码已经加入了日志记录的逻辑。它使用的是 .NET 提供的标准 ILogger<T> 接口,并结合了构造函数依赖注入(通过 IServiceProvider 获取服务实例),这是XAF推荐的方式。

ASP.NET Core 的日志基础设施会自动将这些日志输出集成到 Aspire 仪表盘中。完成上述更改后,运行程序并点击Important Business Action按钮,即可在仪表盘中查看相关日志输出。按钮会被随机禁用一段时间,并在初始化与交互过程开始时输出日志内容,在仪表盘的“结构化日志(Structured Logs)”页面即可查看这些信息。

界面开发框架DevExpress XAF实践教程图集

界面开发框架DevExpress XAF实践教程图集

要记录 OpenTelemetry 的活动(Activity)并使用计量器(Meter),您需要在应用启动时初始化这些对象,并确保相关代码能够访问到它们。可以通过全局单例模式实现,但在这个示例项目中,更合理的方式是继续使用依赖注入机制,并让它来处理生命周期管理。

以下是 XafAspireDemo.Blazor.Server.Telemetry 类的实现:

namespace XafAspireDemo.Blazor.Server
{
public class Telemetry : IDisposable
{
public ActivitySource ActivitySource { get; }
public Meter Meter { get; }
public string MeterName => Meter.Name;
public Counter<long> ImportantBusinessOperationCounter { get; }
public Histogram<double> ImportantBusinessOperationDuration { get; }public Telemetry(
string serviceName = "XafAspireDemo.Blazor.Server",
string version = "1.0.0"
)
{
ActivitySource = new ActivitySource(serviceName, version);
Meter = new Meter(serviceName, version);ImportantBusinessOperationCounter = Meter.CreateCounter<long>(
"important_business_operation.execution_count"
);
ImportantBusinessOperationDuration = Meter.CreateHistogram<double>(
"important_business_operation.execution_duration"
);
}public void Dispose()
{
ActivitySource.Dispose();
Meter.Dispose();
}
}
}

这里的 ActivitySource、Meter、Counter<T> 和 Histogram<T> 类型都来自 System.Diagnostics.Metrics 命名空间。这个类在应用启动时创建相关对象,在应用结束时自动释放。

您只需要在 Startup.cs 中注册该类为单例服务即可:

builder.AddEntityFrameworkCoreInstrumentation();
});--> var telemetry = new Telemetry();
--> services.AddSingleton(telemetry);--> services
--> .AddOpenTelemetry()
--> .WithTracing(tracing => tracing.AddSource("XafAspireDemo.Blazor.Server"))
--> .WithMetrics(metrics =>
--> {
--> metrics.AddMeter(telemetry.MeterName);
--> });services.AddSingleton(
typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>),

接下来我们要将遥测功能应用到前面创建的业务操作中,只需在 ImportantBusinessAction_Execute 方法中添加几行代码即可:

private async void ImportantBusinessAction_Execute(
object sender,
SimpleActionExecuteEventArgs e
)
{
--> var telemetry = serviceProvider.GetRequiredService<Telemetry>();
var logger = serviceProvider.GetRequiredService<
ILogger<ImportantBusinessOperationsController>
>();importantBusinessAction.Enabled["ImportantBusinessActionRunning"] = false;--> using var activity = telemetry.ActivitySource.StartActivity("ImportantBusinessAction");
logger.LogInformation("ImportantBusinessAction started.");try
{
...
}
catch (Exception ex)
{
logger.LogError(ex, "ImportantBusinessAction failed.");
--> activity?.SetStatus(ActivityStatusCode.Error);
--> activity?.AddException(ex);
throw;
}
finally
{
--> activity?.Stop();importantBusinessAction.Enabled["ImportantBusinessActionRunning"] = true;--> telemetry.ImportantBusinessOperationCounter.Add(1);
--> telemetry.ImportantBusinessOperationDuration.Record(
--> activity.Duration.TotalMilliseconds
--> );
}
}

在方法开始处,我们通过依赖注入获取遥测服务,然后开启一个活动(Activity)。如果执行过程中发生错误,会记录异常信息,并将活动状态设为错误,最后记录计数器和直方图的相关指标值。

这样,当您执行该业务操作时,Aspire 仪表盘便能显示相应的指标与活动信息。值得注意的是,OpenTelemetry 会自动关联活动与指标(如执行时长记录),不需要你手动建立连接。

界面开发框架DevExpress XAF实践教程图集

界面开发框架DevExpress XAF实践教程图集


http://www.hkcw.cn/article/nicvTFwgtP.shtml

相关文章

t009-线上代驾管理系统

项目演示地址 摘 要 使用旧方法对线上代驾管理系统的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在线上代驾管理系统的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题…

测试Bug篇

本节概要&#xff1a; 软件测试的生命周期 bug的概念 buh要素 bug等级 bug生命周期 对于bug的定级与开发发生冲突如何解决 一、 软件测试的⽣命周期 软件测试贯穿于软件的整个生命周期&#xff0c;针对这句话我们⼀起来看⼀下软件测试是如何贯穿软件的整个生命周期。 软…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.2 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.2 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用。 dataframe<-data.frame( Surfacec(74,64,60,92…

无人机报警器探测模块技术解析!

一、运行方式 1. 频谱监测与信号识别 全频段扫描&#xff1a;模块实时扫描900MHz、1.5GHz、2.4GHz、5.8GHz等无人机常用频段&#xff0c;覆盖遥控、图传及GPS导航信号。 多路分集技术&#xff1a;采用多传感器阵列&#xff0c;通过信号加权合并提升信噪比&#xff0c;…

从本地到云端:Code App+SSH协议在iPad开发中的性能优化实战

文章目录 前言1. 在iPad下载Code APP2.安装cpolar内网穿透2.1 cpolar 安装2.2 创建TCP隧道 3. iPad远程vscode4. 配置固定TCP端口地址4.1 保留固定TCP地址4.2 配置固定的TCP端口地址4.3 使用固定TCP地址远程vscode 前言 在春日的公园长椅上&#xff0c;当编程灵感突然闪现时&a…

【QQ音乐】sign签名| data参数加密 | AES-GCM加密 | webpack实战 (下)

1.目标 网址&#xff1a;https://y.qq.com/n/ryqq/toplist/26 我们知道了 sign P(n.data)&#xff0c;其中n.data是明文的请求参数 2.webpack生成data加密参数 那么 L(n.data)就是密文的请求参数。返回一个Promise {<pending>}&#xff0c;所以L(n.data) 是一个异步函数…

2025年05月29日Github流行趋势

项目名称&#xff1a;agenticSeek 项目地址url&#xff1a;https://github.com/Fosowl/agenticSeek项目语言&#xff1a;Python历史star数&#xff1a;11898今日star数&#xff1a;2379项目维护者&#xff1a;Fosowl, steveh8758, klimentij, ganeshnikhil, apps/copilot-pull-…

Python自动化之selenium语句——打开、关闭浏览器和网页

目录 一、打开谷歌浏览器 1.双击桌面的Pycharm工具 2.新建Python文件&#xff0c;输入文件名 3.新建的Python文件如下 4.安装selenium库 5.导入包 二、打开网页、关闭网页、关闭浏览器 1.导入增加一个时间包 2.使用函数打包之前写的浏览器的配置 3.调用 4.打开百度网…

实时操作系统在脑机接口中的技术平衡:满足实时性与 AI 算力需求

在当今医疗科技蓬勃发展的时代&#xff0c;实时操作系统&#xff08;RTOS&#xff09;正逐渐成为医疗设备领域中不可或缺的关键技术。随着脑机接口等前沿技术的飞速发展&#xff0c;对实时性和算力的双重需求达到了前所未有的高度&#xff0c;而 RTOS 在其中扮演着至关重要的角…

循环神经网络(RNN)模型

一、概述 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一种专门设计用于处理序列数据&#xff08;如文本、语音、时间序列等&#xff09;的神经网络模型。其核心思想是通过引入时间上的循环连接&#xff0c;使网络能够保留历史信息并影响当前输出。 …

【stm32开发板】原理图设计(电源部分)附:设计PCB流程

一、PCB设计流程 二、操作步骤 1.新建工程 文件→新建→工程 2.命名工程 保存后进入该页面 自生成了一个原理图和PCB 3.新建图页及重命名 右键第一个图页&#xff0c;选择新建图页 右键选择重命名可以为图页改名 4.取消设计规则的22项 5.原理图尺寸调整 如果觉得原理图框的…

MCP入门实战(极简案例)

MCP简介 MCP(Model Context Protocol,模型上下文协议)2024年11月底由 Antbropic 推出的一种开放标准,旨在统一大型语言模型(LLM)与外部数据源和工具之间的通信协议。 Function Calling是AI模型调用函数的机制,MCP是一个标准协议,使AI模型与API无缝交互,而Al Agent是一个…

SCL语言两台电机正反转控制程序从选型、安装到调试全过程的详细步骤指南(下)

阶段三&#xff1a;PLC 编程 (SCL 语言)&#xff08;为了学会结构体和I/O映射可能看着有点复杂&#xff0c;多电机控制及维护好修改&#xff09; 程序结构思路&#xff1a; 1. 定义清晰的数据结构 (STRUCT) 来管理每台电机的所有变量&#xff08;输入、输出、状态、互锁条件&…

apptrace 的优势以及对 App 的价值

官网地址&#xff1a;AppTrace - 专业的移动应用推广追踪平台 apptrace 的优势以及对 App 的价值​ App 拉起作为移动端深度链接技术的关键应用&#xff0c;能实现从 H5 网页到 App 的无缝跳转&#xff0c;并精准定位到 App 内指定页面。apptrace 凭借专业的技术与丰富的经验…

西门子嵌入式学习笔记---(1)裸机和调度器开发

&#x1f308;个人主页&#xff1a; 羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 裸机和调度器开发的对比 嵌入式开发是为了特定目的而设计的计算系统编写软件的过程&#xff0c;这些系统通常会具有受限的资源&#xff08;处理能力&#xff0c;、内存、能源等&…

Rust使用Cargo构建项目

文章目录 你好&#xff0c;Cargo&#xff01;验证Cargo安装使用Cargo创建项目新建项目配置文件解析默认代码结构 Cargo工作流常用命令速查表详细使用说明1. 编译项目2. 运行程序3.快速检查4. 发布版本构建 Cargo的设计哲学约定优于配置工程化优势 开发建议1. 新项目初始化​2. …

Python自动化之selenium语句——元素点击、输入、清空和八大元素定位方法

目录 一、元素定位配置 1.导包 2.查找元素 二、元素交互操作 1.点击 2.输入 3.清空 三、元素定位方法 1.ID 2.NAME 3.CLASS_NAME 4.TAG_NAME 5.LINK_TEXT 6.PARTIAL_LINK_TEXT 7.CSS_SELECTOR 8.XPATH 本节讲解元素定位相关知识 一、元素定位配置 1.导包 2.查…

C++并集查找

前言 C图论 C算法与数据结构 本博文代码打包下载 基本概念 并查集&#xff08;Union-Find&#xff09;是一种用于处理动态连通性&#xff08;直接或间接相连&#xff09;的数据结构&#xff0c;主要支持两种操作&#xff1a;union 和 find。通过这两个基本操作&#xff0c;可…

DeepSeek - 尝试一下GitHub Models中的DeepSeek

1.简单介绍 当前DeepSeek使用的人很多&#xff0c;各大AI平台中也快速引入了DeekSeek&#xff0c;比如Azure AI Foundary(以前名字是Azure AI Studio)中的Model Catalog, HuggingFace, GitHub Models等。同时也出现了一些支持DeepSeek的.NET类库。微软的Semantic Kernel也支持…

2025年人文发展与教育心理学国际会议(ICHDEP 2025)

2025年人文发展与教育心理学国际会议&#xff08;ICHDEP 2025&#xff09; 2025 International Conference on Humanistic Development and Educational Psychology 一、大会信息 会议简称&#xff1a;ICHDEP 2025 大会地点&#xff1a;中国广州 审稿通知&#xff1a;投稿后2…