项目结构化

Lino 旨在高效简化可扩展和模块化项目的创建。它提供了结构清晰的解决方案,在各层之间有明确的职责划分,并能够随着项目需求的发展而扩展。


使用Lino创建项目时,您将生成一个遵循最佳架构和模块化实践的.NET解决方案,重点关注性能、可扩展性和易维护性。

创建新项目

命令 lino project 简化了创建 .NET 新项目的过程,既简单又高效。使用此命令,您可以配置项目结构、选择所需的依赖项,并定义语言和基础设施设置。

要创建一个新项目,请使用以下命令:

lino project new

在执行过程中,命令行界面将请求以下信息:

  • 项目命名空间:定义解决方案的主命名空间。
  • 显示名称:在界面中显示的友好名称。
  • 编程语言:目前只支持 C# (.NET)。
  • 开发堆栈:目前是 .NET 9 与 Aspire。
  • 是否使用代码分析器?选择是或否。
  • 是否使用分布式缓存?选择是或否。
  • 是否使用异步通信?选择是或否。
  • 数据语言:定义系统中实体名称和其他数据的语言。
  • 应用程序支持的语言:允许添加最多 10 种语言以支持国际化(i18n)。
  • 默认语言:定义在 API、响应消息、验证和用户界面中使用的主要语言。

确认信息后,Lino 将自动创建项目结构,如下所示:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   └── Services/
│       └── Shared/
│           ├── API/
│           │   └── MyApp.Shared.API.csproj
│           ├── Application/
│           │   └── MyApp.Shared.Application.csproj
│           ├── Domain/
│           │   └── MyApp.Shared.Domain.csproj
│           ├── Infrastructure/
│           │   └── MyApp.Shared.Infrastructure.csproj
│           └── Infrastructure.Persistence/
│               └── MyApp.Shared.Infrastructure.Persistence.csproj
└── tests/
    

代码分析器

静态代码分析器是强大的工具,有助于确保代码在开发过程中的质量和一致性。它们通过在不执行代码的情况下检查源代码,发现错误、样式问题和其他不一致之处。

当您选择在创建项目时启用代码分析器时,命令行界面将自动为您配置以下包:

  • StyleCop.Analyzers:执行代码样式检查,例如缩进、空格和命名约定。
  • SonarAnalyzer.CSharp:一组用于代码质量和安全性的规则,帮助发现常见错误和潜在的漏洞。
  • Roslynator.Analyzers:提供多种 C# 代码质量和优化规则,帮助发现重构和优化的机会。

代码分析器的好处:

  • 提高质量:帮助保持代码整洁、可读并避免常见问题。
  • 预防错误:在执行前检测到错误,帮助开发者尽早修复问题。
  • 规范化:确保所有开发人员遵循相同的样式和规则,从而提高代码一致性。
  • 重构支持:帮助进行代码重构,提供改进建议。

启用代码分析器后,您可以积极地提升代码质量,减少生产环境中失败的风险。

分布式缓存

分布式缓存是一种提高应用程序性能和可扩展性的方法,通过将频繁访问的数据存储在一个独立于数据库的外部缓存中,从而减少对数据库的访问。它使应用程序的各个实例能够有效地共享缓存数据,确保高可用性并减少响应时间。

如果在创建项目时选择启用分布式缓存,Redis 将被集成到您的 Aspire 容器中,提供一个高可用的缓存系统。

分布式缓存的好处:

  • 提高性能:减少查询响应时间,最小化数据库访问。
  • 可扩展性:允许应用程序横向扩展,因为缓存可以从多个实例中透明访问。
  • 高可用性:使用 Redis 时,即使发生故障,缓存仍然可用,确保分布式系统的可靠性。
  • 降低成本:减少对数据库和系统的负担,避免重复计算相同请求的结果。

启用分布式缓存后,您将显著提高应用程序的性能,确保用户响应速度更快,同时减轻后端服务器的负担。

异步通信

异步通信是一种允许系统和组件非阻塞地交换数据的方法,即不需要等待数据的发送或接收完成即可执行其他任务。在分布式系统和高负载情况下,这种方式尤其有用,能够提高效率和系统的韧性。

如果您选择启用异步通信,RabbitMQ 将被集成到您的项目中,MassTransit 将被配置以简化在应用程序中的异步通信。

异步通信的好处:

  • 提高性能:允许并行执行操作,而不会阻塞系统的其他任务。
  • 可扩展性:帮助系统扩展,处理大量数据和并发用户,而不降低性能。
  • 鲁棒性:在临时故障发生时,异步通信可以重试或存储消息以便稍后处理。
  • 解耦:系统可以在不依赖即时响应的情况下进行通信,从而提高灵活性和组织性。

通过集成 RabbitMQ 和使用 MassTransit,组件之间的通信将更加高效且可靠,确保您的应用程序具有良好的可扩展性和灵活性。

下一步

现在,您已使用 Lino 创建了您的 .NET 项目,请在您最喜欢的代码编辑器中打开它。您可以使用 Visual Studio、Visual Studio Code 或任何您选择的 IDE。

打开项目后,您可以开始添加和配置构成应用程序的服务。这是开发过程中的下一步。

在下一部分中,我们将展示如何在您的新项目中创建和配置这些服务,以便根据您的应用需求,以有组织且可扩展的方式进行开发。

创建和管理服务

在创建项目之后,下一步是添加服务。Lino 提供了一种简单直观的方式来创建服务,可用于单体系统或微服务架构。

要创建一个新服务,请使用以下命令:

lino service new

执行过程中,CLI 将要求提供以下信息:

  • 服务命名空间:定义服务的名称和命名空间。
  • 显示名称:在界面中显示的友好名称。
  • 服务类型:选择简单或模块化。
  • 数据库:选择 PostgreSQL 或 SQL Server。

如果选择了简单类型服务,还需提供以下信息:

  • 架构风格:目前仅支持 Clean Architecture。
  • 使用强类型 ID?选择是或否。

服务类型

简单服务:简单服务结构更精简,适合单体系统或微服务项目,每个服务具有独立的责任。

模块化服务:适用于需要更高组织性和可扩展性的大型系统,允许将服务划分为更小且专注的模块,便于维护和扩展。

无论是简单服务还是模块化服务,每个服务都将拥有独立的数据库。强类型 ID 的架构适用于简单服务,对于模块化服务,则由各模块独立决定。

Lino 的结构非常灵活,允许在同一项目中同时创建简单服务和模块化服务。

架构风格

Lino 为所有服务应用了 Clean Architecture,确保应用遵循良好的架构规范,促进职责分离,便于维护和扩展。

Clean Architecture 的优势:

  • 解耦:业务逻辑独立于技术细节,提高灵活性和可测试性。
  • 可维护性:各层之间分离,便于修改而不会影响系统的其他部分。
  • 可测试性:关注点分离,便于为各层编写单元测试和集成测试。
  • 可扩展性:组件可以轻松更换或修改而不会影响业务逻辑。

如果您选择创建一个简单服务,使用 Clean Architecture,项目将具有以下结构:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   ├── Integrations/
│   │   └── Internal/
│   │       └── MySimpleService/
│   │           └── Http/
│   │               ├── Clients/
│   │               │   └── MyApp.Integrations.MySimpleService.Http.Clients.csproj
│   │               └── Contracts/
│   │                   └── MyApp.Integrations.MySimpleService.Http.Contracts.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MySimpleService/
│           ├── API/
│           │   └── MyApp.MySimpleService.API.csproj
│           ├── Application/
│           │   └── MyApp.MySimpleService.Application.csproj
│           ├── Domain/
│           │   └── MyApp.MySimpleService.Domain.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MySimpleService.Infrastructure.csproj
│           ├── Infrastructure.Persistence/
│           │   └── MyApp.MySimpleService.Infrastructure.Persistence.csproj
│           └── IntegrationEvents/
│               └── MyApp.MySimpleService.IntegrationEvents.csproj
└── tests/
    └── Services/
        └── MySimpleService/
            ├── IntegrationTests/
            │   └── MyApp.MySimpleService.IntegrationTests.csproj
            └── UnitTests/
                └── MyApp.MySimpleService.UnitTests.csproj
    

如果您选择创建一个模块化服务,项目将采用以下结构,支持在开发过程中灵活、有序地添加新模块:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MyModularService/
│           ├── Host/
│           │   └── MyApp.MyModularService.Host.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MyModularService.Infrastructure.csproj
│           └── Modules/
└── tests/
    

强类型 ID

强类型 ID 是一种提升代码安全性和清晰性的做法,通过为标识符(ID)定义具体类型,而不是使用通用类型(如 intguid)。

使用强类型 ID,可以避免将不同类型的 ID 混淆使用,从而减少常见错误。例如,为用户 ID 定义专用类型,而不是仅使用整数。

使用强类型 ID 的好处:

  • 类型安全:确保正确使用 ID,避免不同类型 ID 混用。
  • 代码清晰:每种 ID 类型由专门的类表示,代码更具可读性。
  • 易于重构:如果 ID 类型需要更改,只需修改专用类型即可,其他代码保持安全。
  • 减少错误:避免在错误的上下文中错误使用 ID。

模块化服务的下一步

创建模块化服务后,下一步是向其中添加模块。模块可以独立组织业务逻辑和基础设施,使系统更具可扩展性和组织性。

在下一主题中,我们将学习如何在模块化服务中创建和管理模块,从而充分利用模块化服务的灵活性和可扩展性。

创建和管理模块

创建模块化服务后,下一步是向其中添加模块。模块允许独立地组织业务逻辑,为系统带来更多的可扩展性和组织性。

要创建一个新模块,请使用以下命令:

lino module new

在执行过程中,CLI 将提示输入以下信息:

  • 服务:定义新模块将创建在哪个服务中。
  • 模块命名空间:定义模块的名称和命名空间。
  • 显示名称:界面上显示的用户友好名称。
  • 架构样式:目前仅支持 Clean Architecture。
  • 使用强类型 ID?选择是或否。

最后,Lino 将在保持模块化服务结构不变的情况下生成新模块:

MyApp/
├── MyApp.sln
├── src/
│   ├── Aspire/
│   │   ├── AppHost/
│   │   │   └── MyApp.AppHost.csproj
│   │   └── ServiceDefaults/
│   │       └── MyApp.ServiceDefaults.csproj
│   ├── Integrations/
│   │   └── Internal/
│   │       └── MyModularService/
│   │           └── MyModule/
│   │               └── Http/
│   │                   ├── Clients/
│   │                   │   └── MyApp.Integrations.MyModularService.MyModule.Http.Clients.csproj
│   │                   └── Contracts/
│   │                       └── MyApp.Integrations.MyModularService.MyModule.Http.Contracts.csproj
│   └── Services/
│       ├── Shared/
│       │   ├── API/
│       │   │   └── MyApp.Shared.API.csproj
│       │   ├── Application/
│       │   │   └── MyApp.Shared.Application.csproj
│       │   ├── Domain/
│       │   │   └── MyApp.Shared.Domain.csproj
│       │   ├── Infrastructure/
│       │   │   └── MyApp.Shared.Infrastructure.csproj
│       │   └── Infrastructure.Persistence/
│       │       └── MyApp.Shared.Infrastructure.Persistence.csproj
│       └── MyModularService/
│           ├── Host/
│           │   └── MyApp.MyModularService.Host.csproj
│           ├── Infrastructure/
│           │   └── MyApp.MyModularService.Infrastructure.csproj
│           └── Modules/
│               └── MyModule/
│                   ├── API/
│                   │   └── MyApp.MyModularService.MyModule.API.csproj
│                   ├── Application/
│                   │   └── MyApp.MyModularService.MyModule.Application.csproj
│                   ├── Domain/
│                   │   └── MyApp.MyModularService.MyModule.Domain.csproj
│                   ├── Infrastructure/
│                   │   └── MyApp.MyModularService.MyModule.Infrastructure.csproj
│                   ├── Infrastructure.Persistence/
│                   │   └── MyApp.MyModularService.MyModule.Infrastructure.Persistence.csproj
│                   └── IntegrationEvents/
│                       └── MyApp.MyModularService.MyModule.IntegrationEvents.csproj
└── tests/
    └── Services/
        └── MyModularService/
            └── Modules/
                └── MyModule/
                    ├── IntegrationTests/
                    │   └── MyApp.MyModularService.MyModule.IntegrationTests.csproj
                    └── UnitTests/
                        └── MyApp.MyModularService.MyModule.UnitTests.csproj

数据库结构

需要特别注意的是,数据库与服务绑定。在一个模块化服务中,每个模块由其在关联数据库中的独立 schema 进行表示。这种方法提供了隔离和组织,无需创建多个独立的数据库。

关于模块的独立性

就像服务之间没有直接依赖关系一样,模块也作为服务内部的独立项目进行创建。

这种解耦的好处:

  • 隔离:每个模块可以独立演化,简化了维护和持续改进。
  • 组织性:应用程序变得真正模块化,尊重上下文边界(Bounded Contexts),促进了良好的软件架构实践。
  • 灵活性:可以添加、移除或重构模块,而不会直接影响服务中的其他模块。
  • 测试便捷性:每个模块都可以单独进行测试,从而提高了系统的可靠性和质量。

通过以上内容,我们完成了模块创建过程。在接下来的章节中,我们将深入了解如何构建模块内部的元素,如实体、值对象、枚举、命令、查询、API、集成等。

发生了未处理的错误。 重新加载 🗙