.NET 10 登场:LTS 版本助力开发者解锁性能与功能新高度(第二部分)

作者:微信公众号:【架构师老卢】
3-30 9:12
3

ASP.NET Core 10

ASP.NET Core 10 在 Blazor、SignalR、最小 API(Minimal APIs)和 OpenAPI 3.1 等方面引入了多项改进。此次更新聚焦于性能提升、开发便捷性以及与现代 Web 标准的更好集成。

Blazor 增强功能

  1. QuickGrid 的 RowClass 参数:Blazor 的 QuickGrid 组件现在包含一个 RowClass 参数,允许开发人员根据行数据动态地将 CSS 类应用到网格行上。 示例
<QuickGrid ... RowClass="ApplyRowStyle">
    ...
</QuickGrid>

@code {
    private string ApplyRowStyle({TYPE} rowItem) =>
        rowItem.{PROPERTY} == {VALUE} ? "{CSS STYLE CLASS}" : null;
}

这为基于特定条件设置网格样式提供了更大的灵活性。

  1. Blazor 脚本优化:以前,Blazor 脚本作为嵌入资源在 ASP.NET Core 共享框架中提供。在.NET 10 中,这些脚本现在作为静态 Web 资源提供,并带有自动压缩和指纹识别功能,从而改善了加载时间和缓存效率。

  2. 路由模板高亮显示:[Route]特性现在支持对路由模板进行语法高亮显示,使得在代码编辑器中可视化和管理端点结构变得更加容易。

SignalR 增强功能

ASP.NET Core 10 为 SignalR 带来了更新,不过具体细节将在未来的预览版中提供。

最小 API(Minimal APIs)增强功能

最小 API 持续发展,使得使用更少的依赖构建轻量级 Web 服务变得更加容易。更多的更新将在发布时进行记录。

OpenAPI 3.1 支持

ASP.NET Core 10 引入了对 OpenAPI 3.1 的支持,该版本与 2020–12 JSON 模式草案保持一致。此次更新使 API 文档更加准确且结构更好,但也引入了一些不兼容的变更。

  1. OpenAPI 3.1 的关键变更:可空属性不再使用 nullable: true。相反,现在使用一个包含 null 的数组的 type 关键字。OpenAPI 3.1 现在是生成文档的默认版本,不过如果需要,开发人员仍然可以配置 OpenAPI 3.0。 示例:设置 OpenAPI 版本
builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0;
});

对于在构建时生成 OpenAPI 文档,可以使用 MSBuild 选项指定版本:

<OpenApiGenerateDocumentsOptions>--openapi-version OpenApi3_0</OpenApiGenerateDocumentsOptions>
  1. OpenAPI 3.1 中的不兼容变更:.NET 10 中的一个主要变化是移除了 OpenApiAny,现在它由 JsonNode 替代。 之前(.NET 9 示例)
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
    if (context.JsonTypeInfo.Type == typeof(WeatherForecast))
    {
        schema.Example = new OpenApiObject
        {
            ["date"] = new OpenApiString(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd")),
            ["temperatureC"] = new OpenApiInteger(0),
            ["temperatureF"] = new OpenApiInteger(32),
            ["summary"] = new OpenApiString("Bracing"),
        };
    }
    return Task.CompletedTask;
});

之后(.NET 10 更新)

options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
    if (context.JsonTypeInfo.Type == typeof(WeatherForecast))
    {
        schema.Example = new JsonObject
        {
            ["date"] = DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"),
            ["temperatureC"] = 0,
            ["temperatureF"] = 32,
            ["summary"] = "Bracing",
        };
    }
    return Task.CompletedTask;
});

这些变化会影响所有 OpenAPI 版本,即使显式指定了 OpenAPI 3.0 也是如此。

  1. 以 YAML 格式提供 OpenAPI:ASP.NET Core 10 现在允许以 YAML 格式提供生成的 OpenAPI 文档,与 JSON 相比,YAML 格式可能更易于阅读和维护。 如何启用 YAML 格式
app.MapOpenApi("/openapi/{documentName}.yaml");

目前,仅在通过端点提供 OpenAPI 文档时才支持 YAML 格式。在未来的版本中有望实现构建时生成 YAML 文档。

  1. ProducesResponseType 中的响应描述:[ProducesResponseType]特性现在支持一个可选的描述参数,使 API 文档更加清晰和信息丰富。 示例
[HttpGet(Name = "GetWeatherForecast")]
[ProducesResponseType<IEnumerable<WeatherForecast>>(StatusCodes.Status200OK, 
    Description = "The weather forecast for the next 5 days.")]
public IEnumerable<WeatherForecast> Get()

这一变化通过提供更详细的响应描述改进了 OpenAPI 文档。

  1. 身份验证和授权增强功能:身份验证和授权方面的更多改进将在 ASP.NET Core 10 的未来更新中详细介绍。

  2. 其他改进:对使用顶级语句的应用程序进行测试的更好支持。以前,C# 9 及更高版本中的顶级语句应用程序要求开发人员手动声明:

public partial class Program

这是必要的,以便测试项目可以引用 Program 类。在.NET 10 中,如果未显式声明,源生成器会自动生成 public partial class Program。如果开发人员手动添加了它,新的分析器会建议删除它以避免冗余。

适用于.NET 10 的.NET MAUI

.NET 10 中的.NET MAUI 专注于在.NET MAUI、适用于 Android 的.NET、适用于 iOS 的.NET 以及 macOS 方面进行质量改进。此次更新增强了稳定性、性能和开发人员体验,确保了一个更加完善和可靠的多平台开发框架。

控件增强功能

  1. CollectionView 和 CarouselView:在.NET 9 中,为 iOS 和 Mac Catalyst 上的 CollectionView 和 CarouselView 引入了可选处理程序,提高了性能和稳定性。在.NET 10 中,这些处理程序现在是默认的,确保了更好的响应性和可靠性。

适用于 Android 的.NET 改进

  1. 对 API 36(Android 16)和 JDK 21 的支持:适用于 Android 的.NET 现在包括对 Android API 36(Android 16 “Baklava”)和 JDK 21 的支持,使该框架与最新的 Android 发展保持一致。 要针对 Android 16 预览 API

    • 通过 Android SDK 管理器下载 Android 16(Baklava)SDK。
    • 将项目的 TargetFramework 更新为 net10.0-android36。
  2. 推荐的最低支持 API 级别:默认的最低支持 Android API 已从 21(Lollipop)更新为 24(Nougat)。仍然支持 API 21,但建议更新到 API 24 以避免由 Java 默认接口方法引起的运行时问题。

  3. 对 Android 的 dotnet run 支持:以前,由于缺少指定目标设备或模拟器的参数,.NET for Android 项目不支持 dotnet run 命令。在.NET 10 中,现在可以使用 dotnet run 运行 Android 项目,并提供了新的选项:

// 在连接的物理 Android 设备上运行
dotnet run -p:AdbTarget=-d  

// 在正在运行的 Android 模拟器上运行  
dotnet run -p:AdbTarget=-e  

// 在特定的 Android 设备或模拟器上运行  
dotnet run -p:AdbTarget="-s emulator-5554"

AdbTarget 属性允许开发人员在运行应用程序时指定要使用的设备。

  1. 默认启用 Marshal 方法:.NET 9 中引入了一种新的 Marshal 方法机制,通过优化 Java 调用 C# 代码的方式来提高启动性能。在.NET 9 中,此功能默认是禁用的。在.NET 10 中,默认启用此功能以进一步提高性能。如果出现启动挂起的情况,可以使用以下 MSBuild 属性禁用它:
<PropertyGroup>
    <AndroidEnableMarshalMethods>false</AndroidEnableMarshalMethods>
</PropertyGroup>
  1. 改进的 Maven 库绑定:使用 @(AndroidMavenLibrary) 从 Maven 存储库下载和绑定 Java 库的开发人员现在可以指定一个替代的工件文件名。
<ItemGroup>
    <AndroidMavenLibrary Include="com.facebook.react:react-android"
                         Version="0.76.0"
                         ArtifactFilename="react-android-0.76.0-release.aar" />
</ItemGroup>

这在处理不遵循标准命名约定的库时提高了灵活性。

  1. 更快的设计时构建:为了加快 Visual Studio 设计时的构建速度,.NET 10 不再调用 aapt2。相反,直接解析.aar 文件和 Android 资源,在某些情况下将构建时间从超过 2 秒减少到 600 毫秒以下。

  2. 一般 Android 改进:适用于 Android 的.NET 现在可以使用 JDK 21 进行构建。通过移除依赖 System.Reflection.Emit 的路径,启动性能得到了提高。修复了 ApplicationAttribute.ManageSpaceActivity 以防止出现 InvalidCastException 错误。

适用于 iOS、tvOS、Mac Catalyst 和 macOS 的.NET

  1. 更新的平台支持:.NET 10 现在支持最新的平台版本:

    • iOS:18.2
    • tvOS:18.2
    • Mac Catalyst:18.2
    • macOS:15.2
  2. 默认启用修剪警告:以前,由于基类库中的问题,修剪警告被抑制。现在这些警告在.NET 9 中已得到解决,在.NET 10 中默认启用。要禁用修剪警告,添加以下 MSBuild 属性:

<PropertyGroup>
    <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
</PropertyGroup>
  1. 在库中捆绑原始资源:.NET MAUI 中的库项目可以包含捆绑的资源,如故事板、xib 文件、图像、CoreML 模型和纹理图集。以前,这些资源在嵌入之前需要进行预处理,但这种方法有一些缺点:处理需要一台 Mac 和苹果的工具链。在应用程序构建期间无法基于原始资源做出决策。在.NET 9 中,引入了对在库中嵌入原始资源的可选支持。在.NET 10 中,此行为默认启用。要选择不启用,使用以下属性:
<PropertyGroup>
    <BundleOriginalResources>false</BundleOriginalResources>
</PropertyGroup>

这一变化简化了库的构建,并为开发人员提供了对资源处理方式的更多控制。

EF Core 10 的新特性

EF Core 10(EF10)在 LINQ 查询翻译方面引入了改进,并增强了 ExecuteUpdateAsync 方法,使数据库操作更加灵活和高效。此版本需要.NET 10 进行编译和运行,并且与较旧的.NET 版本或.NET Framework 不兼容。

LINQ 和 SQL 查询翻译改进

EF Core 10 继续完善查询翻译,优化性能并扩展对常用 LINQ 操作的支持。

  1. 关键改进:对 DateOnly.ToDateTime(TimeOnly) 的翻译支持(#35194,由 @mseada94 贡献)。对连续 LIMIT 操作的优化处理(#35384,由 @ranma42 贡献)。对 ICollection 上的 Count 操作的性能改进(#35381,由 @ChrisJollyAU 贡献)。这些增强功能有助于确保查询被翻译成高效的 SQL,同时保持预期的行为。

对 ExecuteUpdateAsync 的增强

  1. 更轻松的动态更新:ExecuteUpdateAsync 允许在数据库中进行任意更新操作。以前,这些更新必须使用表达式树指定,这使得动态构建它们变得困难。 之前(EF Core 9 — 使用表达式树):更新博客的浏览计数并在有条件的情况下修改其名称需要手动构建一个表达式树,这使得过程复杂且容易出错:
// Base setters - update the Views only
Expression<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>> setters =
    s => s.SetProperty(b => b.Views, 8);

// Conditionally add SetProperty(b => b.Name, "foo") to setters, based on the value of nameChanged
if (nameChanged)
{
    var blogParameter = Expression.Parameter(typeof(Blog), "b");

    setters = Expression.Lambda<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>>(
        Expression.Call(
            instance: setters.Body,
            methodName: nameof(SetPropertyCalls<Blog>.SetProperty),
            typeArguments: [typeof(string)],
            arguments:
            [
                Expression.Lambda<Func<Blog, string>>(Expression.Property(blogParameter, nameof(Blog.Name)), blogParameter),
                Expression.Constant("foo")
            ]),
        setters.Parameters);
}

await context.Blogs.ExecuteUpdateAsync(setters);

之后(EF Core 10 — 使用标准 Lambda 表达式):在 EF Core 10 中,ExecuteUpdateAsync 现在支持常规的 Lambda 表达式,使得动态执行有条件的更新变得更加简单:

await context.Blogs.ExecuteUpdateAsync(s =>
{
    s.SetProperty(b => b.Views, 8);
    if (nameChanged)
    {
        s.SetProperty(b => b.Name, "foo");
    }
});

这一改进消除了对复杂表达式树操作的需求,使得更新更容易编写和维护。

C# 14 的新特性

C# 14 引入了几个新的语言特性,专注于提高代码清晰度、减少样板代码并增强性能。关键更新包括对未绑定泛型类型的 nameof 运算符、Span 的隐式转换以及 lambda 参数的新选项。这些特性需要.NET 10 并在 Visual Studio 2022 中得到支持。

  1. 新的 field 关键字:field 关键字通过消除显式声明后备字段的需要来简化属性访问器。 之前(C# 13 — 使用显式后备字段):以前,确保属性不能设置为 null 需要手动定义一个后备字段:
private string _msg;
public string Message
{
    get => _msg;
    set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}

之后(C# 14 — 使用 field):使用新的 field 关键字,编译器会自动生成后备字段:

public string Message
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

此特性减少了样板代码,同时保持了功能。但是,如果一个类已经包含一个名为 field 的成员,开发人员可以使用 @field 或 this.field 来避免冲突。

  1. Span 和 ReadOnlySpan 的隐式转换:C# 14 为 Span 和 ReadOnlySpan 提供了一流的支持,实现了这些类型与标准数组之间更自然的转换。 主要优点:在不牺牲安全性的情况下提高性能。更直观地处理跨度,减少了手动转换的需求。与扩展方法和泛型类型推断的兼容性更好。这些变化使得使用跨度更加无缝,特别是在高性能应用程序中。

  2. nameof 中的未绑定泛型类型:在 C# 的以前版本中,nameof 运算符只能用于封闭的泛型类型(例如,nameof(List) 将返回 "List")。 C# 14 中的新特性:现在,也可以使用未绑定的泛型类型:

Console.WriteLine(nameof(List<>)); // 输出: "List"

此特性在需要处理泛型类型名称的元编程场景中有所改进。

  1. 简单 lambda 参数的修饰符:C# 14 允许在 lambda 表达式中添加参数修饰符(scoped、ref、in、out、ref readonly),而无需显式声明类型。 之前(C# 13 — 修饰符需要显式类型)
TryParse<int> parse = (string text, out int result) => int.TryParse(text, out result);

之后(C# 14 — 支持类型推断)

delegate bool TryParse<T>(string text, out T result);

TryParse<int> parse = (text, out result) => int.TryParse(text, out result);

这一变化减少了冗余并提高了 lambda 表达式的可读性。

相关留言评论
昵称:
邮箱:
阅读排行