使用 Visual Studio 2022 中的 .HTTP 文件

注释 以 # 或 // 开头的行是注释,当 Visual Studio 发送 HTTP 请求时,将忽略这些行。 变量 以 @ 开头的行使用语法 @VariableName=Value 定义变量。 @hostname=localhost @port=44320 GET https://{{hostname}}:{{port}}/weatherforecast 多个请求 请求格式为: [<HTTP-verb>] <url> [<HTTP-version>] [<request-headers>] [<request-body>] GET https://localhost:7220/weatherforecast ### GET https://localhost:7220/weatherforecast?date=2023-05-11&location=98006 ### GET https://localhost:7220/weatherforecast HTTP/3 ### 请求标头 GET https://localhost:7220/weatherforecast Date: Wed, 27 Apr 2023 07:28:00 GMT ### GET https://localhost:7220/weatherforecast Cache-Control: max-age=604800 Age: 100 ### 请求正文 POST https://localhost:7220/weatherforecast Content-Type: application/json { "date": "2023-05-11", "location": "98006" } 使用模板创建 HTTP 文件 右键单击 ASP.NET Core 项目 添加>新建项 ASP.NET Core>常规 选择 HTTP 文件,然后选择添加 使用终结点资源管理器 视图>其他窗口>终结点资源管理

2026年3月10日

使用分布式锁解决并发问题

单进程应用程序中的锁 在单机环境下,我们可以使用线程锁来解决并发问题,但是在分布式系统中,线程锁无法解决并发问题,因为分布式系统中的线程锁只能锁住当前进程,无法锁住其他进程。 在 .NET 中,我们可以使用 lock 关键字来实现线程锁。 https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/statements/lock private static readonly object _lock = new object(); public void DoSomething() { lock (_lock) { // 业务逻辑 } } C# 13 引入了新的线程同步类型 System.Threading.Lock,它通过作用域管理的方式简化了锁的使用,使代码更加清晰可靠。 using System.Threading.Lock; private static readonly Lock _lock = new Lock(); public void DoSomething() { using (_lock.EnterScope()) { // 业务逻辑 } } 开源分布式锁的实现 DistributedLock 是一个 .NET 库,它基于各种底层技术提供强大且易于使用的分布式互斥锁、读写器锁和信号量。 https://github.com/madelson/DistributedLock 零度框架中的分布式锁 零度框架中提供分布式锁的基本抽象,并基于 Dapr 实现了分布式锁。 https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview Redis 分布式锁原理 Redis 分布式锁的实现原理是通过 SETNX 命令,SETNX 是 Redis 的一个原子性操作,它会在键不存在时设置键的值,如果键已经存在,则不做任何操作。

2026年3月10日

使用缓存提高系统性能

缓存是一种常见的技术,目标是提高系统的性能和伸缩性。 为缓存数据,它会暂时会经常访问的数据复制到位置靠近应用程序的快速存储。 如果这种快速数据存储比原始源更靠近应用程序,则缓存可以通过更快速提供数据,大幅改善客户端应用程序的响应时间。 缓存类型 私有专用缓存 专用缓存是指缓存服务运行在应用程序的同一台服务器上,它是应用程序的一部分,通常是一个库或模块。专用缓存通常是一个内存缓存,如 MemoryCache 或 ConcurrentDictionary,它是一个轻量级的缓存,适用于小型应用程序。专用缓存的优点是简单易用,缺点是无法跨服务器共享数据,不适用于大型应用程序,使用 IMemoryCache 接口可以在 .NET 中使用专用缓存。 services.AddMemoryCache(); public class MyService(IMemoryCache cache) : IService { public async Task Test() { cache.Set("key", "value"); var value = cache.Get("key"); } } 分布式共享缓存 分布式缓存是指缓存服务运行在多台服务器上,它是一个独立的服务,可以跨服务器共享数据。分布式缓存通常是一个内存缓存,如 Redis、Memcached、Garnet 等,它是一个高性能、低延迟的缓存,适用于大型应用程序。分布式缓存的优点是高性能、低延迟,支持大规模数据存储和访问,缺点是复杂度高,需要额外的服务器资源,使用 IDistributedCache 接口可以在 .NET 中使用分布式缓存。 services.AddMemoryDistributedCache(); public class MyService(IDistributedCache cache) : IService { public async Task Test() { await cache.SetStringAsync("key", "value"); var value = await cache.GetStringAsync("key"); } } 使用 Redis 分布式缓存 Redis 是一个高性能、开源的分布式缓存系统,它是一个内存数据库,支持多种数据结构,如字符串、列表、哈希表、集合等,Redis 的设计目标是提供一个高性能、低延迟的分布式缓存系统,以支持大规模的数据存储和访问,同时提供高可用性和可扩展性。Redis 采用 RESP 协议,使用 C 语言编写,支持多种语言,如 C、C++、C#、Java、Python、Node.js 等,可以在 .NET 中使用 StackExchange.Redis 开源库对缓存进行操作。 Windows 下 Redis 不再维护,可以使用 WSL2 安装 Redis,或者使用 Docker 安装 Redis。也可使用 Memurai 替代 Redis,Memurai 是一个 Windows 下的 Redis 服务,支持 Redis 的大部分功能,可以在 Windows 下运行 Redis 服务。 ...

2026年3月10日

数据库对象命名约定

不同数据库对象的命名约定不同,EF Core 为了适配不同数据库,提供了一些命名约定的配置选项。 常见的命名方法 Naming policy Original Converted PascalCase HelloShop HelloShop CamelCase HelloShop helloShop SnakeCaseLower HelloShop hello_shop SnakeCaseUpper HelloShop HELLO_SHOP KebabCaseLower HelloShop hello-shop KebabCaseUpper HelloShop HELLO-SHOP 可使用 Humanizr 库将字符串转换为不同的命名风格。 表名使用单数还是复数 EF Core 默认情况下,表名使用单数形式,可以通过约定器或者手动指定复数表名,社区对单数和复数表名的争论一直存在,没有统一的标准,但零度推荐使用单数形式。 手动指定表名和列名 表名 默认情况下,EF Core 使用实体类型的名称作为表名。可以通过重写 OnModelCreating 方法来修改表名: protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>().ToTable("blogs"); } 列名 默认情况下,EF Core 使用属性名作为列名。可以通过 HasColumnName 方法来修改列名: protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>().Property(b => b.Url).HasColumnName("blog_url"); } PostgreSQL 命名约定 PostgreSQL 的命名约定采用小写蛇形命名法,即单词之间使用下划线分隔,如 blog_url,表名使用单数形式。 使用 EFCore.NamingConventions 库 EFCore.NamingConventions 库提供了一些命名约定的配置选项,可以方便地配置表名、列名等。 安装 EFCore.NamingConventions 库 dotnet add package EFCore.NamingConventions 配置命名约定 使用 OnConfiguring 方法配置命名约定: ...

2026年3月10日

网关和服务发现

构建和设计 API 网关 API 网关是一个服务器,它是客户端和后端服务之间的中介。它接收来自客户端的请求,然后将这些请求转发到后端服务。API 网关还可以执行其他任务,例如身份验证、监视、负载平衡、缓存、请求分析和日志记录。 BFF 模式聚合多个服务 API 网关可以聚合多个服务,基于 BFF(后端用于前端)模式,当客户端请求数据时,API 网关可以调用多个服务来获取数据,然后将数据聚合到一个响应中返回给客户端,以减少客户端与后端服务之间的通信次数,从而提高性能。 常见的 API 网关 Nginx、Envoy、Ocelot、Yarp、Zuul、Kong、Traefik、Tyk、Ambassador、Gloo、AWS API Gateway、Azure API Management、Google Cloud Endpoints、Apigee、MuleSoft Anypoint API Gateway、WSO2 API Manager、TIBCO Mashery、3scale API Management、Akana、CA API Gateway、Dell Boomi、DreamFactory、IBM API Connect、Mashape、Mashery、MuleSoft Anypoint Platform、OpenLegacy、Oracle API Platform Cloud Service、Repre。 基于.NET 的开源 API 网关 Ocelot 和 Yarp 是一个基于.NET 的开源 API 网关,它可以用于构建和设计微服务架构中的 API 网关。Yarp 提供了很多功能,例如路由、负载平衡、认证、授权、限流、熔断、重试、缓存、请求转发、请求重写、请求日志、响应缓存、响应压缩、响应缓存、响应重写、响应日志、监视、跟踪、跨域、安全、性能、可扩展性、可配置性、可管理性、可监视性、可测试性、可部署性、可维护性、可扩展性、可升级。 Github 开源仓库 官方参考文档 使用 Yarp 构建和设计 API 网关 dotnet add package Yarp.ReverseProxy 使用配置文件配置 Yarp { "ReverseProxy": { "Routes": { "testserviceRoute": { "ClusterId": "testServiceCluster", "Match": { "Path": "testservice/{**remainder}" }, "Transforms": [ { "PathPattern": "{**remainder}" } ] } }, "Clusters": { "testServiceCluster": { "Destinations": { "testServiceCluster/destination1": { "Address": "http://identityservice" } } } } } } .NET 中的服务发现 服务发现是一种用于发现和定位服务的机制,它可以帮助客户端找到服务的位置和地址。服务发现可以用于构建和设计微服务架构中的 API 网关,以便客户端可以通过 API 网关访问后端服务。 ...

2026年3月10日

学习并使用 PostgreSQL 数据库

为什么说 PostgreSQL 是最先进的关系型数据库? 功能更强大:PostgreSQL具有更多高级功能,例如复杂查询、触发器和多版本并发控制等,这使得它更适合处理复杂的数据操作。 数据一致性更高:PostgreSQL使用可靠的多版本并发控制系统,能够在高并发场景下保证数据的一致性和完整性。 可扩展性更好:PostgreSQL支持更好的水平和垂直扩展,以满足各种规模的应用需求。 安全性:PostgreSQL提供了访问控制和数据加密等安全特性,保护数据免受恶意攻击。 备份和恢复:PostgreSQL具有强大的备份和恢复功能,能够恢复各种故障情况下的数据。 免费和开源:PostgreSQL是一种免费和开源的数据库系统,用户可以自由地使用、修改和分发其源代码。 安装 PostgreSQL 和 pgAdmin 安装 PostgreSQL 和 pgAdmin 的方法有很多种,这里介绍一种比较简单的方法,学习使用 pgAdmin 管理 PostgreSQL 数据库,远程连接 PostgreSQL 数据库。 在 Visual Studio Code 中连接 PostgreSQL 数据库 在 Visual Studio Code 中连接 PostgreSQL 数据库,可以使用微软开发的 PostgreSQL 插件,也可以使用第三方开发的 PostgreSQL 插件。 在 Visual Studio Code 中使用 AI 助手编写 SQL 语句 Github Copilot 是一款由 OpenAI 开发的人工智能编程助手,它可以根据上下文提示程序员编写代码,目前支持 12 种编程语言,可以轻松实现 SQL 智能生成等。 将 SQL Server 数据库迁移到 PostgreSQL SQL Server 导入导出向导可以将 SQL Server 数据库迁移到 PostgreSQL 数据库,参见微软文档: ...

2026年3月10日

用户界面和设计语言

用户体验 用户体验(User Experience,简称 UX)是用户在使用产品时的感受,是一个综合性的概念,包括用户对产品的感知、情感、态度、情绪等。用户体验设计(User Experience Design,简称 UXD)是一种以用户为中心的设计方法,目的是提高用户满意度,提高用户对产品的认知和使用。 颜色、字体、布局、交互等因素都会影响用户体验,因此在设计用户界面时需要考虑用户体验,提供简洁、直观、易用的界面,以提高用户满意度。 扁平化和拟物化 扁平化设计(Flat Design)是一种简洁、直观的设计风格,强调简单、明了的界面设计,去除了繁琐的装饰和冗余的元素,使用户更容易理解和操作。拟物化设计(Skeuomorphism)是一种仿真真实物体的设计风格,强调真实感和细节,使用户更容易理解和操作。 搜索 Flat vs Skeuomorphism 了解更多信息。 常见的设计语言 Google Material Design、Microsoft Fluent Design System、Alibaba Ant Design … Material Design 设计语言 https://material.io/design 组件库 https://github.com/MudBlazor/MudBlazor https://github.com/MudBlazor/ Fluent Design System 设计语言 https://www.microsoft.com/design/fluent 组件库 https://github.com/microsoft/fast-blazor Ant Design 设计语言 https://ant.design 组件库 https://github.com/ant-design-blazor/ant-design-blazor 商业组件库 https://github.com/radzenhq/radzen-blazor 原型工具 MasterGo 和 Figma 是两个常用的原型工具,可以用来设计和制作用户界面原型,提供了丰富的组件库和交互效果,可以帮助设计师快速制作用户界面原型。 设计令牌 设计令牌(Design Tokens)是一种用来定义设计系统的方法,包括颜色、字体、间距、阴影等设计元素,可以帮助设计师和开发者快速创建一致的设计风格,提高设计效率。 选择组件 风格统一、易用性、可定制性、性能优化、文档完善、社区活跃、维护更新、商业授权等因素都会影响组件库的选择。 互补色 互补色是指在色彩环中相对位置相反的两种颜色,当两种互补色放在一起时,会产生强烈的对比效果,使得两种颜色更加突出。互补色的组合通常会产生视觉冲击,因此在设计中需要谨慎使用,浏览器开发者工具监测对比度,以确保用户体验。 应用案例 Aspire 的仪表盘设计是基于 Fluent Design 的,采用了扁平化设计风格,简洁、直观、易用,提高了用户体验。

2026年3月10日

用于生成初始数据的提供程序

数据播种是使用一组初始数据填充数据库的过程,通常在数据库首次创建时执行,这些数据通常是静态的,不会随时间变化,数据播种通常用于填充一些基本数据,例如用户、角色、权限、商品、分类等。 通用接口设计 public interface IDataSeedingProvider { Task SeedingAsync(IServiceProvider serviceProvider); } 实现具体接口 public class DataSeedingProvider(UserManager<User> userManager) : IDataSeedingProvider { public async Task SeedingAsync(IServiceProvider ServiceProvider) { var user = await userManager.FindByNameAsync("admin"); if (user == null) { await userManager.CreateAsync(new User { UserName = "admin", Email = "admin@test.com" }, "admin"); } } } 在容器中注册 builder.Services.AddTransient<IDataSeedingProvider, DataSeedingProvider>(); 自动执行扩展 public static class DataSeedingExtensions { public static IApplicationBuilder UseDataSeedingProviders(this IApplicationBuilder app) { using var serviceScope = app.ApplicationServices.CreateScope(); var dataSeedingProviders = serviceScope.ServiceProvider.GetServices<IDataSeedingProvider>(); foreach (IDataSeedingProvider dataSeedingProvider in dataSeedingProviders) { dataSeedingProvider.SeedingAsync(serviceScope.ServiceProvider).Wait(); } return app; } } 自动注册实现 public static class DataSeedingExtensions { public static IServiceCollection AddDataSeedingProviders(this IServiceCollection services, Assembly? assembly = null) { assembly ??= Assembly.GetCallingAssembly(); var dataSeedProviders = assembly.ExportedTypes.Where(t => t.IsAssignableTo(typeof(IDataSeedingProvider)) && t.IsClass); dataSeedProviders.ToList().ForEach(t => services.AddTransient(typeof(IDataSeedingProvider), t)); return services; } } 执行顺序问题 自动注册的提供程序的执行顺序是不确定的,如果需要确定执行顺序,可以设计 Order 属性,然后在 UseDataSeedingProviders 方法中按照 Order 属性排序执行。 在微服务中使用 builder.Services.AddDataSeedingProviders(); app.UseDataSeedingProviders();

2026年3月10日

在 Aspire 中集成 PostgreSQL 数据库

在 Host 项目中添加 PostgreSQL 数据库 dotnet add package Aspire.Hosting.PostgreSQL var builder = DistributedApplication.CreateBuilder(args); var postgres = builder.AddPostgres("postgres"); var postgresdb = postgres.AddDatabase("postgresdb"); var exampleProject = builder.AddProject<Projects.ExampleProject>().WithReference(postgresdb); 添加 PostgreSQL pgAdmin 资源 var postgres = builder.AddPostgres("postgres").WithPgAdmin(); 添加 PostgreSQL pgWeb 资源 var postgres = builder.AddPostgres("postgres").WithPgWeb(); 在最终的应用中引用 PostgreSQL 数据库 dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL builder.AddNpgsqlDbContext<IdentityServiceDbContext>(connectionName: DbConstants.ConnectionStringName, configureDbContextOptions: options => { new NpgsqlDbContextOptionsBuilder(options).MigrationsHistoryTable(DbConstants.MigrationsHistoryTableName); });

2026年3月10日

在项目中添加文件头注释

文件头注释 文件头注释是一种用于说明文件版权和许可的注释。它通常包括版权声明、许可证信息、作者信息和其他相关信息。文件头注释是一种很好的实践,可以帮助开发人员了解文件的版权和许可信息。 版权申明规范 // Copyright (c) HelloShop Corporation. All rights reserved. // See the license file in the project root for more information. namespace HelloShop.AppHost { internal class Class1 { } } 关于 EditorConfig 配置文件 为跨不同编辑器和 IDE 处理同一项目的多个开发人员保持一致的编码风格。 Visual Studio 2019 及更高版本支持 EditorConfig 文件,可以在 Visual Studio 中使用 EditorConfig 文件来定义和维护代码样式设置。 版权说明模板 file_header_template = Copyright (c) HelloShop Corporation. All rights reserved.\nSee the license file in the project root for more information. 对于文件名,可以使用 {fileName} 作为占位符。

2026年3月10日