DevExpress XAF是一款强大的现代应用程序框架,允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计,开发人员可以选择内建模块,也可以自行创建,从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。
.NET Aspire是一组工具、模板和包,用于构建可观察的、可生产的应用程序。DevExpress XAF团队花费了一些时间考虑Aspire的功能,试图找到最好的集成点,让XAF开发人员能够利用Aspire开箱即用的业务流程特性。该团队认为Aspire是一个潜在的"一键解决方案",是XAF解决方案向导中一些模板的更现代的替代品,它可以实现以下一些目标:
- 简化冗长且容易出错的设置过程,就像在Linux上的Azure应用服务和Nginx支持文档中描述的那样,以及其他流行的web服务器配置。
- 为开发和部署环境提供所需的数据库和其他应用程序资源(例如,使用Docker设置)。
团队希望能够为客户节省大量的时间,无论他们是否使用XAF!目前,由于Microsoft仍在快速开发Aspire,这在很大程度上是一个移动的目标。与此同时,一些功能已经被广泛使用,可以认为是稳定的,所以现在我们决定发布一些细节,来帮助您在自己的XAF项目中使用Aspire工具。
在上文中(点击这里回顾>>),我们主要为大家介绍了如何将将Aspire添加到XAF Blazor项目,本文将继续介绍第三方软件包的更新等。
第三方软件包更新
正如之前内容中所解释的,由于Aspire是尖端技术,坚持使用最新版本是有意义的。为了保持一致性,官方建议使用所有内容的最新版本,建议在进行其他更改之前先这样做。
您可以为每个项目打开NuGet包管理器并以这种方式安装更新,但官方更建议使用Package Manager Console窗口(您可以从Visual Studio的工具菜单中打开它),Get-Package -updates命令显示所有可用的更新:
vbscript
PM> Get-Package -updates
Id Versions Description ProjectName
-- -------- ----------- -----------
Microsoft.EntityFrameworkCore.Sq... {9.0.3} Microsoft SQL Server database provider for... XafAspireDemo.Module
Microsoft.Data.SqlClient {6.0.1} The current data provider for SQL Server a... XafAspireDemo.Module
System.IdentityModel.Tokens.Jwt {8.6.1} Includes types that provide support for cr... XafAspireDemo.Module
Microsoft.EntityFrameworkCore.In... {9.0.3} In-memory database provider for Entity Fra... XafAspireDemo.Module
Microsoft.EntityFrameworkCore.Pr... {9.0.3} Lazy loading proxies for Entity Framework ... XafAspireDemo.Module
No package updates are available from the current package source for project 'XafAspireDemo.Blazor.Server'.
Aspire.Hosting.AppHost {9.1.0} Core library and MSBuild logic for .NET As... XafAspireDemo.AppHost
OpenTelemetry.Instrumentation.As... {1.11.1} ASP.NET Core instrumentation for OpenTelem... XafAspireDemo.ServiceDefaults
OpenTelemetry.Exporter.OpenTelem... {1.11.2} OpenTelemetry protocol exporter for OpenTe... XafAspireDemo.ServiceDefaults
OpenTelemetry.Instrumentation.Ru... {1.11.1} .NET runtime instrumentation for OpenTelem... XafAspireDemo.ServiceDefaults
Microsoft.Extensions.Http.Resili... {9.3.0} Resilience mechanisms for HttpClient. XafAspireDemo.ServiceDefaults
Microsoft.Extensions.ServiceDisc... {9.1.0} Provides extensions to HttpClient that ena... XafAspireDemo.ServiceDefaults
OpenTelemetry.Extensions.Hosting {1.11.2} Contains extensions to start OpenTelemetry... XafAspireDemo.ServiceDefaults
OpenTelemetry.Instrumentation.Http {1.11.1} Http instrumentation for OpenTelemetry .NET. XafAspireDemo.ServiceDefaults
现在运行Update-Package命令,等待所有的包都更新到最新版本。
在此之后还有一个小问题:AppHost项目文件中的Sdk引用仍然指向9.0.0版本:
XML
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
将此手动修复到9.1.0版本,因为这是最新的可用版本。
<Sdk Name="Aspire.AppHost.Sdk" Version="9.1.0" />
注意:您可以使用新的.NET Upgrade Assistant Visual Studio Extension来自动更新依赖项,包括SDK版本。
服务默认扩展
首先,可以简单地从Module项目中删除额外的Extensions.cs副本,这是不必要的。
在ServiceDefaults项目中的Extensions.cs中实现的类Extensions可以用下面的代码完全替换,注意,这个实现包含与原始文件使用的完全相同的默认代码,不同之处在于如何应用代码。标准文件在大多数情况下使用IHostApplicationBuilder接口,而替换文件直接使用IServiceCollection,这使得与Blazor应用程序的启动代码交互变得容易得多。
cs
public static class Extensions
{
public static void AddAspireServiceDefaults(this IServiceCollection services)
{
services.AddMetrics();
services.AddOpenTelemetry();
services.AddHealthChecks().AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
services.AddServiceDiscovery();
services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler();
http.AddServiceDiscovery();
});
}
public static IServiceCollection ConfigureOpenTelemetry(
this IServiceCollection services,
IConfiguration configuration,
IWebHostEnvironment environment
)
{
services
.AddLogging(logging =>
{
logging.AddOpenTelemetry(options =>
{
options.IncludeFormattedMessage = true;
options.IncludeScopes = true;
});
})
.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing
.AddSource(environment.ApplicationName)
.AddSource("Microsoft.AspNetCore.SignalR.Server")
.AddAspNetCoreInstrumentation()
// Uncomment the following line to enable gRPC instrumentation
//.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
});
AddOpenTelemetryExporters(services, configuration);
return services;
}
private static void AddOpenTelemetryExporters(
IServiceCollection services,
IConfiguration configuration
)
{
var useOtlpExporter = !string.IsNullOrWhiteSpace(
configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]
);
if (useOtlpExporter)
{
services.AddOpenTelemetry().UseOtlpExporter();
}
}
public static void MapDefaultAspireDevEndpoints(this IEndpointRouteBuilder endpoints)
{
endpoints.MapHealthChecks("/health");
endpoints.MapHealthChecks(
"/alive",
new HealthCheckOptions { Predicate = r => r.Tags.Contains("live") }
);
}
}
与向导创建的原始文件一样,您应该将此视为一个起点,并根据自己的应用程序系统需要调整扩展方法的代码。与标准代码相比,所应用的一个变化是增加了额外的跟踪源Microsoft.AspNetCore.SignalR.Server,这使得来自SignalR的遥测信息在Aspire仪表板中可用,这是需要根据您自己的需求进行更改的示例。
修改启动代码
所有这些更改都应用于Blazor.Server项目中的Startup.cs文件,我们首先扩展构造函数,除了配置之外,还包括对环境对象的引用:
cs
public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
{
Configuration = configuration;
WebHostEnvironment = webHostEnvironment;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
就在ConfigureServices方法的开头,添加了对新扩展方法的调用,这两个新行在这里有一个-->前缀:
cs
public void ConfigureServices(IServiceCollection services) {
--> services.AddAspireServiceDefaults();
--> services.ConfigureOpenTelemetry(Configuration, WebHostEnvironment);
services.AddSingleton(
typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>),
typeof(ProxyHubConnectionHandler<>));
...
在这一点上,我们还应用了一个可选的扩展,在项目中添加了NuGet包OpenTelemetry.Instrumentation.EntityFrameworkCore(这目前是一个预发布版本!),然后用这些额外的代码行启用EF Core的instrumentation:
cs
public void ConfigureServices(IServiceCollection services) {
services.AddAspireServiceDefaults();
services.ConfigureOpenTelemetry(Configuration, WebHostEnvironment);
--> services.ConfigureOpenTelemetryTracerProvider(builder =>
--> {
--> builder.AddEntityFrameworkCoreInstrumentation();
--> });
services.AddSingleton(
typeof(Microsoft.AspNetCore.SignalR.HubConnectionHandler<>),
typeof(ProxyHubConnectionHandler<>));
...
最后,对Configure方法做了一个更改。在它的最后添加了一个块,它使用Aspire向导创建的标准扩展方法有条件地添加端点映射:
cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapXafEndpoints();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
endpoints.MapControllers();
});
--> if (env.IsDevelopment())
--> {
--> app.UseEndpoints(endpoints =>
--> {
--> endpoints.MapDefaultAspireDevEndpoints();
--> });
--> }
}
此时,可以运行应用程序了,Aspire Dashboard在浏览器中正确地出现了。然而Blazor项目的资源没有显示任何端点,这使得它实际上无法访问。

添加Blazor应用程序端点
AppHost项目中的Program.cs中的代码现在是应用程序系统的入口点,这是Aspire配置其编排的地方,即使现在只有一个项目需要配置。根据自己的需求修改这段代码并不罕见,在这种情况下,发现需要一个显式调用来帮助Aspire理解Blazor应用程序有一个HTTPS端点:
cs
var builder = DistributedApplication.CreateBuilder(args);
builder
.AddProject<Projects.XafAspireDemo_Blazor_Server>("xafaspiredemo-blazor-server")
--> .WithHttpsEndpoint();
builder.Build().Run();
现在,演示应用程序有了一个端点条目,通过它可以像以前一样访问应用程序。

在Blazor前端运行一些操作后,Aspire Dashboard也开始在Traces和Metrics面板中显示条目,您可以在这里深入研究并详细分析应用程序操作。

