Showing preview only (2,287K chars total). Download the full file or copy to clipboard to get everything.
Repository: ardalis/CleanArchitecture
Branch: main
Commit: cae04fcabc9a
Files: 495
Total size: 2.1 MB
Directory structure:
gitextract_pjis_cnn/
├── .aspire/
│ └── settings.json
├── .editorconfig
├── .github/
│ ├── CONTRIBUTING.md
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-ramdisk.yml
│ ├── codeql-analysis.yml
│ ├── dotnetcore.yml
│ ├── publish-templates.yml
│ └── publish.yml
├── .gitignore
├── .runsettings
├── .template.config/
│ └── template.json
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Clean.Architecture.slnx
├── CleanArchitecture.nuspec
├── Directory.Build.props
├── Directory.Packages.props
├── LICENSE
├── MinimalClean/
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .runsettings
│ ├── .template.config/
│ │ └── template.json
│ ├── Directory.Build.props
│ ├── Directory.Packages.props
│ ├── MinimalClean.Architecture.slnx
│ ├── README.template.md
│ ├── global.json
│ └── src/
│ ├── MinimalClean.Architecture.AspireHost/
│ │ ├── AppHost.cs
│ │ ├── MinimalClean.Architecture.AspireHost.csproj
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
│ ├── MinimalClean.Architecture.ServiceDefaults/
│ │ ├── Extensions.cs
│ │ └── MinimalClean.Architecture.ServiceDefaults.csproj
│ └── MinimalClean.Architecture.Web/
│ ├── AssemblyInfo.cs
│ ├── CartFeatures/
│ │ ├── AddToCart/
│ │ │ ├── AddToCartEndpoint.cs
│ │ │ └── AddToCartHandler.cs
│ │ ├── CartDto.cs
│ │ ├── CartResponse.cs
│ │ ├── Checkout/
│ │ │ ├── CheckoutEndpoint.cs
│ │ │ └── CheckoutHandler.cs
│ │ └── GetById/
│ │ ├── GetByIdEndpoint.cs
│ │ └── GetCartHandler.cs
│ ├── Configurations/
│ │ ├── DatabaseOptions.cs
│ │ ├── LoggerConfigs.cs
│ │ ├── LoggingBehavior.cs
│ │ ├── MediatorConfig.cs
│ │ ├── MiddlewareConfig.cs
│ │ ├── OptionConfigs.cs
│ │ └── ServiceConfigs.cs
│ ├── Constants.cs
│ ├── Domain/
│ │ ├── CartAggregate/
│ │ │ ├── Cart.cs
│ │ │ ├── CartId.cs
│ │ │ ├── CartItem.cs
│ │ │ ├── CartItemId.cs
│ │ │ └── Specifications/
│ │ │ └── CartByIdSpec.cs
│ │ ├── GuestUserAggregate/
│ │ │ ├── GuestUser.cs
│ │ │ ├── GuestUserId.cs
│ │ │ └── Specifications/
│ │ │ ├── GuestUserByEmailSpec.cs
│ │ │ └── GuestUserByIdSpec.cs
│ │ ├── Interfaces/
│ │ │ └── IEmailSender.cs
│ │ ├── OrderAggregate/
│ │ │ ├── Order.cs
│ │ │ ├── OrderId.cs
│ │ │ ├── OrderItem.cs
│ │ │ ├── OrderItemId.cs
│ │ │ ├── Price.cs
│ │ │ └── Quantity.cs
│ │ └── ProductAggregate/
│ │ ├── Product.cs
│ │ ├── ProductId.cs
│ │ └── Specifications/
│ │ └── ProductByIdSpec.cs
│ ├── Extensions/
│ │ └── ResultExtensions.cs
│ ├── GlobalUsings.cs
│ ├── Infrastructure/
│ │ ├── Data/
│ │ │ ├── AppDbContext.cs
│ │ │ ├── AppDbContextExtensions.cs
│ │ │ ├── AppDbContextFactory.cs
│ │ │ ├── Config/
│ │ │ │ ├── CartConfiguration.cs
│ │ │ │ ├── CartItemConfiguration.cs
│ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ ├── GuestUserConfiguration.cs
│ │ │ │ ├── OrderConfiguration.cs
│ │ │ │ ├── OrderItemConfiguration.cs
│ │ │ │ ├── ProductConfiguration.cs
│ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ ├── VogenGuidIdValueGenerator.cs
│ │ │ │ └── VogenIntIdValueGenerator.cs
│ │ │ ├── EfRepository.cs
│ │ │ ├── EventDispatcherInterceptor.cs
│ │ │ ├── Migrations/
│ │ │ │ ├── 20251020223304_Initial.Designer.cs
│ │ │ │ ├── 20251020223304_Initial.cs
│ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs
│ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.cs
│ │ │ │ └── AppDbContextModelSnapshot.cs
│ │ │ ├── Queries/
│ │ │ │ └── ListProductsQueryService.cs
│ │ │ └── SeedData.cs
│ │ ├── Email/
│ │ │ ├── FakeEmailSender.cs
│ │ │ ├── MailserverConfiguration.cs
│ │ │ └── MimeKitEmailSender.cs
│ │ └── InfrastructureServiceExtensions.cs
│ ├── MinimalClean.Architecture.Web.csproj
│ ├── PagedResult.cs
│ ├── ProductFeatures/
│ │ ├── Create/
│ │ │ └── CreateEndpoint.cs
│ │ ├── GetById/
│ │ │ ├── GetByIdEndpoint.cs
│ │ │ └── GetProductHandler.cs
│ │ ├── List/
│ │ │ ├── IListProductsQueryService.cs
│ │ │ ├── ListEndpoint.cs
│ │ │ └── ListProductsHandler.cs
│ │ ├── ProductDto.cs
│ │ └── ProductRecord.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── api.http
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── config.nsdepcop
│ └── wwwroot/
│ └── .gitkeep
├── MinimalClean.nuspec
├── PARALLEL_TEST_EXECUTION.md
├── README.md
├── README.template.md
├── TESTCONTAINERS_IMPLEMENTATION.md
├── docs/
│ ├── architecture-decisions/
│ │ ├── README.md
│ │ └── adr-001-dotnet-di-adoption.md
│ └── minimal-clean-architecture.md
├── global.json
├── nuget.config
├── sample/
│ ├── .editorconfig
│ ├── .github/
│ │ └── copilot-instructions.md
│ ├── .runsettings
│ ├── Directory.Build.props
│ ├── Directory.Packages.props
│ ├── NimblePros.SampleToDo.slnx
│ ├── src/
│ │ ├── NimblePros.SampleToDo.AspireHost/
│ │ │ ├── NimblePros.SampleToDo.AspireHost.csproj
│ │ │ ├── Program.cs
│ │ │ ├── Properties/
│ │ │ │ └── launchSettings.json
│ │ │ ├── appsettings.Development.json
│ │ │ └── appsettings.json
│ │ ├── NimblePros.SampleToDo.Core/
│ │ │ ├── ContributorAggregate/
│ │ │ │ ├── Contributor.cs
│ │ │ │ ├── ContributorId.cs
│ │ │ │ ├── ContributorName.cs
│ │ │ │ ├── Events/
│ │ │ │ │ ├── ContributorDeletedEvent.cs
│ │ │ │ │ └── ContributorNameUpdatedEvent.cs
│ │ │ │ ├── Handlers/
│ │ │ │ │ ├── ContributorDeletedHandler.cs
│ │ │ │ │ └── ContributorNameUpdatedEventLoggingHandler.cs
│ │ │ │ └── Specifications/
│ │ │ │ └── ContributorByIdSpec.cs
│ │ │ ├── CoreServiceExtensions.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── Interfaces/
│ │ │ │ ├── IDeleteContributorService.cs
│ │ │ │ ├── IEmailSender.cs
│ │ │ │ └── IToDoItemSearchService.cs
│ │ │ ├── Localization.cs
│ │ │ ├── NimblePros.SampleToDo.Core.csproj
│ │ │ ├── ProjectAggregate/
│ │ │ │ ├── Events/
│ │ │ │ │ ├── ContributorAddedToItemEvent.cs
│ │ │ │ │ ├── NewItemAddedEvent.cs
│ │ │ │ │ └── ToDoItemCompletedEvent.cs
│ │ │ │ ├── Handlers/
│ │ │ │ │ ├── ContributorAddedToItemLoggingHandler.cs
│ │ │ │ │ ├── ItemCompletedEmailNotificationHandler.cs
│ │ │ │ │ └── NewItemAddedLoggingHandler.cs
│ │ │ │ ├── Priority.cs
│ │ │ │ ├── Project.cs
│ │ │ │ ├── ProjectErrorMessages.cs
│ │ │ │ ├── ProjectId.cs
│ │ │ │ ├── ProjectName.cs
│ │ │ │ ├── ProjectStatus.cs
│ │ │ │ ├── Specifications/
│ │ │ │ │ ├── IncompleteItemsSearchSpec.cs
│ │ │ │ │ ├── IncompleteItemsSpec.cs
│ │ │ │ │ ├── ProjectByIdWithItemsSpec.cs
│ │ │ │ │ └── ProjectsWithItemsByContributorId.cs
│ │ │ │ ├── ToDoItem.cs
│ │ │ │ ├── ToDoItemDescription.cs
│ │ │ │ ├── ToDoItemId.cs
│ │ │ │ └── ToDoItemTitle.cs
│ │ │ └── Services/
│ │ │ ├── DeleteContributorService.cs
│ │ │ └── ToDoItemSearchService.cs
│ │ ├── NimblePros.SampleToDo.Infrastructure/
│ │ │ ├── Data/
│ │ │ │ ├── AppDbContext.cs
│ │ │ │ ├── Config/
│ │ │ │ │ ├── ContributorConfiguration.cs
│ │ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ │ ├── ProjectConfiguration.cs
│ │ │ │ │ ├── ToDoItemConfiguration.cs
│ │ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ │ └── VogenIdValueGenerator.cs
│ │ │ │ ├── EfRepository.cs
│ │ │ │ ├── EventDispatchInterceptor.cs
│ │ │ │ └── Queries/
│ │ │ │ ├── FakeListContributorsQueryService.cs
│ │ │ │ ├── FakeListIncompleteItemsQueryService.cs
│ │ │ │ ├── FakeListProjectsShallowQueryService.cs
│ │ │ │ ├── ListContributorsQueryService.cs
│ │ │ │ ├── ListIncompleteItemsQueryService.cs
│ │ │ │ └── ListProjectsShallowQueryService.cs
│ │ │ ├── Email/
│ │ │ │ ├── FakeEmailSender.cs
│ │ │ │ ├── MailserverConfiguration.cs
│ │ │ │ ├── MimeKitEmailSender.cs
│ │ │ │ └── SmtpEmailSender.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── InfrastructureServiceExtensions.cs
│ │ │ └── NimblePros.SampleToDo.Infrastructure.csproj
│ │ ├── NimblePros.SampleToDo.ServiceDefaults/
│ │ │ ├── Extensions.cs
│ │ │ └── NimblePros.SampleToDo.ServiceDefaults.csproj
│ │ ├── NimblePros.SampleToDo.UseCases/
│ │ │ ├── Constants.cs
│ │ │ ├── Contributors/
│ │ │ │ ├── Commands/
│ │ │ │ │ ├── Create/
│ │ │ │ │ │ ├── CreateContributorCommand.cs
│ │ │ │ │ │ └── CreateContributorHandler.cs
│ │ │ │ │ ├── Delete/
│ │ │ │ │ │ ├── DeleteContributorCommand.cs
│ │ │ │ │ │ └── DeleteContributorHandler.cs
│ │ │ │ │ └── Update/
│ │ │ │ │ ├── UpdateContributorCommand.cs
│ │ │ │ │ └── UpdateContributorHandler.cs
│ │ │ │ ├── ContributorDTO.cs
│ │ │ │ └── Queries/
│ │ │ │ ├── Get/
│ │ │ │ │ ├── GetContributorHandler.cs
│ │ │ │ │ └── GetContributorQuery.cs
│ │ │ │ └── List/
│ │ │ │ ├── IListContributorsQueryService.cs
│ │ │ │ ├── ListContributorsHandler.cs
│ │ │ │ └── ListContributorsQuery.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── ICacheable.cs
│ │ │ ├── NimblePros.SampleToDo.UseCases.csproj
│ │ │ ├── PagedResult.cs
│ │ │ ├── Projects/
│ │ │ │ ├── AddToDoItem/
│ │ │ │ │ ├── AddToDoItemCommand.cs
│ │ │ │ │ └── AddToDoItemHandler.cs
│ │ │ │ ├── Create/
│ │ │ │ │ ├── CreateProjectCommand.cs
│ │ │ │ │ └── CreateProjectHandler.cs
│ │ │ │ ├── Delete/
│ │ │ │ │ ├── DeleteProjectCommand.cs
│ │ │ │ │ └── DeleteProjectHandler.cs
│ │ │ │ ├── GetWithAllItems/
│ │ │ │ │ ├── GetProjectWithAllItemsHandler.cs
│ │ │ │ │ └── GetProjectWithAllItemsQuery.cs
│ │ │ │ ├── ListIncompleteItems/
│ │ │ │ │ ├── IListIncompleteItemsQueryService.cs
│ │ │ │ │ ├── ListIncompleteItemsByProjectHandler.cs
│ │ │ │ │ └── ListIncompleteItemsByProjectQuery.cs
│ │ │ │ ├── ListShallow/
│ │ │ │ │ ├── IListProjectsShallowQueryService.cs
│ │ │ │ │ ├── ListProjectsShallowHandler.cs
│ │ │ │ │ └── ListProjectsShallowQuery.cs
│ │ │ │ ├── MarkToDoItemComplete/
│ │ │ │ │ ├── MarkToDoItemCompleteCommand.cs
│ │ │ │ │ └── MarkToDoItemCompleteHandler.cs
│ │ │ │ ├── ProjectDTO.cs
│ │ │ │ ├── ProjectWithAllItemsDTO.cs
│ │ │ │ ├── ToDoItemDTO.cs
│ │ │ │ └── Update/
│ │ │ │ ├── UpdateProjectCommand.cs
│ │ │ │ └── UpdateProjectHandler.cs
│ │ │ └── README.md
│ │ └── NimblePros.SampleToDo.Web/
│ │ ├── CachingBehavior.cs
│ │ ├── Configurations/
│ │ │ ├── CachingOptions.cs
│ │ │ ├── CachingProfile.cs
│ │ │ ├── GlobalExceptionHandler.cs
│ │ │ ├── LoggerConfig.cs
│ │ │ ├── MediatorConfig.cs
│ │ │ ├── MiddlewareConfig.cs
│ │ │ ├── OptionConfigs.cs
│ │ │ └── ServiceConfigs.cs
│ │ ├── Contributors/
│ │ │ ├── ContributorRecord.cs
│ │ │ ├── Create.cs
│ │ │ ├── Delete.DeleteContributorRequest.cs
│ │ │ ├── Delete.DeleteContributorValidator.cs
│ │ │ ├── Delete.cs
│ │ │ ├── GetById.GetContributorByIdMapper.cs
│ │ │ ├── GetById.GetContributorByIdRequest.cs
│ │ │ ├── GetById.GetContributorValidator.cs
│ │ │ ├── GetById.cs
│ │ │ ├── List.ContributorListResponse.cs
│ │ │ ├── List.cs
│ │ │ ├── Update.UpdateContributorRequest.cs
│ │ │ ├── Update.UpdateContributorResponse.cs
│ │ │ ├── Update.UpdateContributorValidator.cs
│ │ │ └── Update.cs
│ │ ├── Extensions/
│ │ │ └── ResultExtensions.cs
│ │ ├── GlobalUsings.cs
│ │ ├── LoggingBehavior.cs
│ │ ├── NimblePros.SampleToDo.Web.csproj
│ │ ├── Program.cs
│ │ ├── Projects/
│ │ │ ├── Create.CreateProjectRequest.cs
│ │ │ ├── Create.CreateProjectResponse.cs
│ │ │ ├── Create.CreateProjectValidator.cs
│ │ │ ├── Create.cs
│ │ │ ├── CreateToDoItem.CreateToDoItemRequest.cs
│ │ │ ├── CreateToDoItem.CreateToDoItemValidator.cs
│ │ │ ├── CreateToDoItem.cs
│ │ │ ├── Delete.DeleteProjectRequest.cs
│ │ │ ├── Delete.DeleteProjectValidator.cs
│ │ │ ├── Delete.cs
│ │ │ ├── GetById.GetProjectByIdRequest.cs
│ │ │ ├── GetById.GetProjectByIdResponse.cs
│ │ │ ├── GetById.GetProjectByIdValidator.cs
│ │ │ ├── GetById.cs
│ │ │ ├── List.ProjectListResponse.cs
│ │ │ ├── List.cs
│ │ │ ├── ListIncompleteItems.ListIncompleteItemsRequest.cs
│ │ │ ├── ListIncompleteItems.ListIncompleteItemsResponse.cs
│ │ │ ├── ListIncompleteItems.cs
│ │ │ ├── MarkItemComplete.MarkItemCompleteRequest.cs
│ │ │ ├── MarkItemComplete.cs
│ │ │ ├── ProjectRecord.cs
│ │ │ ├── ToDoItemRecord.cs
│ │ │ ├── Update.UpdateProjectRequest.cs
│ │ │ ├── Update.UpdateProjectRequestValidator.cs
│ │ │ ├── Update.UpdateProjectResponse.cs
│ │ │ └── Update.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── SeedData.cs
│ │ ├── api.http
│ │ ├── appsettings.json
│ │ ├── i18n/
│ │ │ ├── en/
│ │ │ │ └── Project.json
│ │ │ ├── fa/
│ │ │ │ └── Project.json
│ │ │ └── fr/
│ │ │ └── Project.json
│ │ └── wwwroot/
│ │ ├── css/
│ │ │ └── site.css
│ │ ├── js/
│ │ │ └── site.js
│ │ └── lib/
│ │ ├── bootstrap/
│ │ │ ├── LICENSE
│ │ │ └── dist/
│ │ │ ├── css/
│ │ │ │ ├── bootstrap-grid.css
│ │ │ │ ├── bootstrap-grid.rtl.css
│ │ │ │ ├── bootstrap-reboot.css
│ │ │ │ ├── bootstrap-reboot.rtl.css
│ │ │ │ ├── bootstrap-utilities.css
│ │ │ │ ├── bootstrap-utilities.rtl.css
│ │ │ │ ├── bootstrap.css
│ │ │ │ └── bootstrap.rtl.css
│ │ │ └── js/
│ │ │ ├── bootstrap.bundle.js
│ │ │ ├── bootstrap.esm.js
│ │ │ └── bootstrap.js
│ │ ├── jquery/
│ │ │ ├── LICENSE.txt
│ │ │ └── dist/
│ │ │ └── jquery.js
│ │ ├── jquery-validation/
│ │ │ ├── LICENSE.md
│ │ │ └── dist/
│ │ │ ├── additional-methods.js
│ │ │ └── jquery.validate.js
│ │ └── jquery-validation-unobtrusive/
│ │ ├── LICENSE.txt
│ │ └── jquery.validate.unobtrusive.js
│ └── tests/
│ ├── NimblePros.SampleToDo.FunctionalTests/
│ │ ├── Contributors/
│ │ │ ├── ContributorCreate.cs
│ │ │ ├── ContributorDelete.cs
│ │ │ ├── ContributorGetById.cs
│ │ │ ├── ContributorList.cs
│ │ │ └── ContributorUpdate.cs
│ │ ├── CustomWebApplicationFactory.cs
│ │ ├── Fixtures/
│ │ │ └── SmtpServerFixture.cs
│ │ ├── GlobalUsings.cs
│ │ ├── NimblePros.SampleToDo.FunctionalTests.csproj
│ │ ├── Projects/
│ │ │ ├── CreateToDoItemRequestBuilder.cs
│ │ │ ├── ProjectAddToDoItem.cs
│ │ │ ├── ProjectCreate.cs
│ │ │ ├── ProjectGetById.cs
│ │ │ ├── ProjectItemMarkComplete.cs
│ │ │ └── ProjectList.cs
│ │ ├── TestBase.cs
│ │ └── xunit.runner.json
│ ├── NimblePros.SampleToDo.IntegrationTests/
│ │ ├── Data/
│ │ │ ├── BaseEfRepoTestFixture.cs
│ │ │ ├── EfRepositoryAdd.cs
│ │ │ ├── EfRepositoryDelete.cs
│ │ │ └── EfRepositoryUpdate.cs
│ │ ├── GlobalUsings.cs
│ │ └── NimblePros.SampleToDo.IntegrationTests.csproj
│ └── NimblePros.SampleToDo.UnitTests/
│ ├── Core/
│ │ ├── ContributorAggregate/
│ │ │ ├── ContributorConstructor.cs
│ │ │ └── ContributorIdFrom.cs
│ │ ├── Handlers/
│ │ │ └── ItemCompletedEmailNotificationHandlerHandle.cs
│ │ ├── ProjectAggregate/
│ │ │ ├── ProjectConstructor.cs
│ │ │ ├── ProjectNameFrom.cs
│ │ │ ├── Project_AddItem.cs
│ │ │ ├── ToDoItemConstructor.cs
│ │ │ └── ToDoItemMarkComplete.cs
│ │ ├── Services/
│ │ │ ├── DeleteContributorSevice_DeleteContributor.cs
│ │ │ ├── ToDoItemSearchServiceTests.cs
│ │ │ ├── ToDoItemSearchService_GetAllIncompleteItems.cs
│ │ │ └── ToDoItemSearchService_GetNextIncompleteItem.cs
│ │ └── Specifications/
│ │ └── IncompleteItemSpecificationsConstructor.cs
│ ├── GlobalUsings.cs
│ ├── NimblePros.SampleToDo.UnitTests.csproj
│ ├── NoOpMediator.cs
│ ├── ToDoItemBuilder.cs
│ ├── UseCases/
│ │ └── Contributors/
│ │ ├── CreateContributorHandlerHandle.cs
│ │ ├── GetContributorHandlerHandle.cs
│ │ └── UpdateContributorHandlerHandle.cs
│ └── xunit.runner.json
├── src/
│ ├── Clean.Architecture.AspireHost/
│ │ ├── AppHost.cs
│ │ ├── Clean.Architecture.AspireHost.csproj
│ │ ├── GlobalUsings.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── README.md
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
│ ├── Clean.Architecture.Core/
│ │ ├── Clean.Architecture.Core.csproj
│ │ ├── Clean.Architecture.Core.sln
│ │ ├── ContributorAggregate/
│ │ │ ├── Contributor.cs
│ │ │ ├── ContributorId.cs
│ │ │ ├── ContributorName.cs
│ │ │ ├── ContributorStatus.cs
│ │ │ ├── Events/
│ │ │ │ ├── ContributorDeletedEvent.cs
│ │ │ │ └── ContributorNameUpdatedEvent.cs
│ │ │ ├── Handlers/
│ │ │ │ ├── ContributorDeletedHandler.cs
│ │ │ │ └── ContributorNameUpdatedEmailNotificationHandler.cs
│ │ │ ├── PhoneNumber.cs
│ │ │ └── Specifications/
│ │ │ └── ContributorByIdSpec.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Interfaces/
│ │ │ ├── IDeleteContributorService.cs
│ │ │ └── IEmailSender.cs
│ │ ├── README.md
│ │ └── Services/
│ │ └── DeleteContributorService.cs
│ ├── Clean.Architecture.Infrastructure/
│ │ ├── Clean.Architecture.Infrastructure.csproj
│ │ ├── Data/
│ │ │ ├── AppDbContext.cs
│ │ │ ├── AppDbContextExtensions.cs
│ │ │ ├── Config/
│ │ │ │ ├── ContributorConfiguration.cs
│ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ └── VogenIdValueGenerator.cs
│ │ │ ├── EfRepository.cs
│ │ │ ├── EventDispatcherInterceptor.cs
│ │ │ ├── Migrations/
│ │ │ │ ├── 20231218143922_PhoneNumber.Designer.cs
│ │ │ │ ├── 20231218143922_PhoneNumber.cs
│ │ │ │ ├── 20251113164108_UpdateForNet10.Designer.cs
│ │ │ │ ├── 20251113164108_UpdateForNet10.cs
│ │ │ │ └── AppDbContextModelSnapshot.cs
│ │ │ ├── Queries/
│ │ │ │ ├── FakeListContributorsQueryService.cs
│ │ │ │ └── ListContributorsQueryService.cs
│ │ │ └── SeedData.cs
│ │ ├── Email/
│ │ │ ├── FakeEmailSender.cs
│ │ │ ├── MailserverConfiguration.cs
│ │ │ └── MimeKitEmailSender.cs
│ │ ├── GlobalUsings.cs
│ │ ├── InfrastructureServiceExtensions.cs
│ │ └── README.md
│ ├── Clean.Architecture.ServiceDefaults/
│ │ ├── Clean.Architecture.ServiceDefaults.csproj
│ │ └── Extensions.cs
│ ├── Clean.Architecture.UseCases/
│ │ ├── Clean.Architecture.UseCases.csproj
│ │ ├── Constants.cs
│ │ ├── Contributors/
│ │ │ ├── ContributorDTO.cs
│ │ │ ├── Create/
│ │ │ │ ├── CreateContributorCommand.cs
│ │ │ │ └── CreateContributorHandler.cs
│ │ │ ├── Delete/
│ │ │ │ ├── DeleteContributorCommand.cs
│ │ │ │ └── DeleteContributorHandler.cs
│ │ │ ├── Get/
│ │ │ │ ├── GetContributorHandler.cs
│ │ │ │ └── GetContributorQuery.cs
│ │ │ ├── List/
│ │ │ │ ├── IListContributorsQueryService.cs
│ │ │ │ ├── ListContributorsHandler.cs
│ │ │ │ └── ListContributorsQuery.cs
│ │ │ └── Update/
│ │ │ ├── UpdateContributorCommand.cs
│ │ │ └── UpdateContributorHandler.cs
│ │ ├── GlobalUsings.cs
│ │ ├── PagedResult.cs
│ │ └── README.md
│ └── Clean.Architecture.Web/
│ ├── Clean.Architecture.Web.csproj
│ ├── Configurations/
│ │ ├── LoggerConfigs.cs
│ │ ├── MediatorConfig.cs
│ │ ├── MiddlewareConfig.cs
│ │ ├── OptionConfigs.cs
│ │ └── ServiceConfigs.cs
│ ├── Contributors/
│ │ ├── ContributorRecord.cs
│ │ ├── Create.cs
│ │ ├── Delete.DeleteContributorRequest.cs
│ │ ├── Delete.DeleteContributorValidator.cs
│ │ ├── Delete.cs
│ │ ├── GetById.GetContributorByIdRequest.cs
│ │ ├── GetById.GetContributorValidator.cs
│ │ ├── GetById.cs
│ │ ├── List.cs
│ │ ├── Update.UpdateContributorRequest.cs
│ │ ├── Update.UpdateContributorResponse.cs
│ │ ├── Update.UpdateContributorValidator.cs
│ │ └── Update.cs
│ ├── Extensions/
│ │ └── ResultExtensions.cs
│ ├── GlobalUsings.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── api.http
│ ├── appsettings.Development.json
│ ├── appsettings.Testing.json
│ ├── appsettings.json
│ └── wwwroot/
│ └── .gitkeep
└── tests/
├── Clean.Architecture.AspireTests/
│ ├── AspireIntegrationTests.cs
│ └── Clean.Architecture.AspireTests.csproj
├── Clean.Architecture.FunctionalTests/
│ ├── ApiEndpoints/
│ │ ├── ContributorGetById.cs
│ │ └── ContributorList.cs
│ ├── Clean.Architecture.FunctionalTests.csproj
│ ├── CustomWebApplicationFactory.cs
│ ├── DockerAvailabilityTests.cs
│ ├── GlobalUsings.cs
│ └── xunit.runner.json
├── Clean.Architecture.IntegrationTests/
│ ├── Clean.Architecture.IntegrationTests.csproj
│ ├── Data/
│ │ ├── BaseEfRepoTestFixture.cs
│ │ ├── EfRepositoryAdd.cs
│ │ ├── EfRepositoryDelete.cs
│ │ └── EfRepositoryUpdate.cs
│ ├── GlobalUsings.cs
│ └── xunit.runner.json
└── Clean.Architecture.UnitTests/
├── Clean.Architecture.UnitTests.csproj
├── Core/
│ ├── ContributorAggregate/
│ │ ├── ContributorConstructor.cs
│ │ ├── ContributorIdFrom.cs
│ │ ├── ContributorNameFrom.cs
│ │ └── ContributorUpdateName.cs
│ └── Services/
│ ├── DeleteContributorSevice_DeleteContributor.cs
│ ├── ToDoItemSearchService_GetAllIncompleteItems.cs
│ └── ToDoItemSearchService_GetNextIncompleteItem.cs
├── GlobalUsings.cs
├── NoOpMediator.cs
├── UseCases/
│ └── Contributors/
│ └── CreateContributorHandlerHandle.cs
└── xunit.runner.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .aspire/settings.json
================================================
{
"appHostPath": "../src/Clean.Architecture.AspireHost/Clean.Architecture.AspireHost.csproj"
}
================================================
FILE: .editorconfig
================================================
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 2
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
tab_width= 2
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
dotnet_style_operator_placement_when_wrapping = beginning_of_line
end_of_line = crlf
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Namespaces
csharp_style_namespace_declarations = file_scoped:warning
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
csharp_using_directive_placement = outside_namespace:suggestion
csharp_prefer_simple_using_statement = true:suggestion
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to CleanArchitecture
**First:** if you're unsure or afraid of _anything_, just ask or submit the
issue or pull request anyways. You won't be yelled at for giving your best
effort. The worst that can happen is that you'll be politely asked to change
something. We appreciate any sort of contributions, and don't want a wall of
rules to get in the way of that.
However, for those individuals who want a bit more guidance on the best way to
contribute to the project, read on. This document will cover what we're looking
for. By addressing all the points we're looking for, it raises the chances we
can quickly merge or address your contributions.
## Issues
### Reporting an Issue
* Make sure you test against the latest released version. It is possible we
already fixed the bug you're experiencing.
* If you can, check and see if there is an existing open issue that is already
reporting the problem. Feel free to upvote this issue or comment on it to
describe your specific scenario (assuming it's the same underlying issue).
* Provide a reproducible test case. If a contributor can't reproduce an issue,
then it dramatically lowers the chances it'll get fixed. And in some cases,
the issue will eventually be closed.
* Respond promptly to any questions made by the maintainers about your issue. Stale
issues will be closed (eventually).
## Pull Requests
* Pull requests are welcome but are most likely to be accepted when they address
an existing issue. A common workflow is to create an issue describing the problem
your PR would solve, and then volunteer to submit a PR addressing the issue as an
initial comment on the issue.
* As much as possible, pull requests should follow the existing coding conventions
used by the project. This is generally true for any project. The only exception to
this would be a pull request whose purpose is to adjust the coding conventions used
by the project.
* When possible, issues will be marked with a `help wanted` tag if community contributions
are particularly welcome for them. This will often be the case for relatively simple
fixes that would make good initial contributions.
* If your PR addresses an issue, please include "Fixes #NNN" in the summary for the PR
so that the issue is linked to the PR (and vice versa) and if/when the PR is merged,
the issue is automatically closed.
Thank you for reading this and for considering contributing to this project!
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [ardalis]
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
---
<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠️ -->
<!-- 🔎 Search existing issues to avoid creating duplicates. -->
- .NET SDK Version:
Steps to Reproduce:
1.
2.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Question
url: https://stackoverflow.com/questions/tagged/ardalis-cleanarchitecture
about: Please ask and answer questions on Stack Overflow.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
---
<!-- ⚠️⚠️ Do Not Delete This! feature_request_template ⚠️⚠️ -->
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Describe the feature you'd like. -->
================================================
FILE: .github/copilot-instructions.md
================================================
# GitHub Copilot Instructions for Clean Architecture Template
## Project Overview
This is a **Clean Architecture template** for .NET 9 that demonstrates Domain-Driven Design (DDD) patterns. It's a starter template, not a reference application - delete sample code once you understand the patterns.
## Architecture & Project Structure
### C# Conventions
- Use standard Microsoft naming conventions
- Use `PascalCase` for types and methods, `camelCase` for parameters and private fields
- Use `I` prefix for interfaces (e.g., `IRepository`)
- Use `Async` suffix for async methods (e.g., `GetByIdAsync`)
- Prefix private fields with `_` (e.g., `_repository`)
- Always use {} for blocks except single-line exits (e.g. `return`, `throw`)
- Always keep single line blocks on one line (e.g., `if (x) return y;`)
- Prefer primary constructors for required dependencies
- Never use primary constructor parameters directly - always assign to private fields for clarity and testability
### Core Dependencies Flow
- **Core** ← UseCases ← Infrastructure
- **Core** ← UseCases ← Web
- Never allow Core to depend on outer layers
### Key Projects
- **Core**: Domain entities, aggregates, value objects, specifications, interfaces
- **UseCases**: Commands/queries (CQRS), Mediator handlers, application logic
- **Infrastructure**: EF Core, external services, email, file access
- **Web**: FastEndpoints API, REPR pattern, validation
## Development Patterns
### API Endpoints (FastEndpoints + REPR)
- One endpoint per file: `Create.cs`, `Update.cs`, `Delete.cs`, `GetById.cs`
- Separate request/response/validator files: `Create.CreateRequest.cs`, `Create.CreateValidator.cs`
- Use `Endpoint<TRequest, TResponse>` base class
- Example: `src/Clean.Architecture.Web/Contributors/Create.cs`
### Domain Model (Core)
- Entities use encapsulation - minimize public setters
- Group related entities into Aggregates
- Use Value Objects (e.g., `ContributorName.From()`)
- Domain Events for cross-aggregate communication
- Repository interfaces defined in Core, implemented in Infrastructure
### Use Cases (CQRS)
- Commands for mutations, Queries for reads
- Queries can bypass repository pattern for performance
- Use Mediator (source generator) for command/query handling
- Chain of responsibility for cross-cutting concerns (logging, validation)
### Validation Strategy
- **API Level**: FluentValidation on request DTOs (FastEndpoints integration)
- **Use Case Level**: Validate commands/queries (defensive coding)
- **Domain Level**: Business invariants throw exceptions, assume pre-validated input
## Essential Commands
### Build & Test
```bash
dotnet build Clean.Architecture.slnx
dotnet test Clean.Architecture.slnx
```
### Entity Framework Migrations
```bash
# From Web project directory
dotnet ef migrations add MigrationName -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj -o Data/Migrations
dotnet ef database update -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj
```
### Template Installation & Usage
```bash
dotnet new install Ardalis.CleanArchitecture.Template
dotnet new clean-arch -o Your.ProjectName
```
## Key Dependencies & Patterns
### Primary Libraries
- **FastEndpoints**: API endpoints (replaced Controllers/Minimal APIs)
- **Mediator**: Command/query handling in UseCases
- **EF Core**: Data access (SQLite default, easily changed to SQL Server)
- **Ardalis.Specification**: Repository query specifications
- **Ardalis.Result**: Error handling pattern
- **Serilog**: Structured logging
### Central Package Management
- All package versions in `Directory.Packages.props`
- Use `<PackageReference Include="..." />` without Version attribute
### Test Organization
- **UnitTests**: Core business logic, use cases
- **IntegrationTests**: Database, infrastructure components
- **FunctionalTests**: API endpoints (subcutaneous testing)
- Use `Microsoft.AspNetCore.Mvc.Testing` for API tests
## File Organization Conventions
### Web Project Structure
```
Contributors/
Create.cs # Endpoint
Create.CreateRequest.cs # Request DTO
Create.CreateResponse.cs # Response DTO
Create.CreateValidator.cs # FluentValidation
Update.cs, Delete.cs, etc.
```
### Sample vs Template
- `/sample` folder: Complete working example (NimblePros.SampleToDo)
- `/src` folder: Clean template ready for your project
- Study sample for patterns, use src for new projects
## Common Gotchas
- Don't include hyphens in project names (template limitation)
- Replace `Ardalis.SharedKernel` with your own shared kernel
- Database path in `appsettings.json` for SQLite
- Use absolute paths in EF migration commands
- FastEndpoints uses different validation approach than Controller-based APIs
## VS Code Tasks
Use the predefined tasks: `build`, `publish`, `watch` instead of manual `dotnet` commands when possible.
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: nuget
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
================================================
FILE: .github/workflows/build-ramdisk.yml
================================================
name: Build and Test with Ramdisk
on:
push:
branches:
- main
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout the repository
- name: Checkout Code
uses: actions/checkout@v3
# Step 2: Set up .NET environment
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
# Step 3: Prepare a directory in /dev/shm
- name: Set up Ramdisk Directory
run: |
mkdir -p /dev/shm/ramdisk/project
# Step 4: Copy source code to the ramdisk
- name: Copy Code to Ramdisk
run: |
cp -r $GITHUB_WORKSPACE/* /dev/shm/ramdisk/project
# Step 5: Debug Directory Contents
- name: Debug Directory
run: |
ls -R /dev/shm/ramdisk/project
# Step 6: Build and Test from the ramdisk
- name: Build and Test
run: |
cd /dev/shm/ramdisk/project
dotnet build Clean.Architecture.slnx --configuration Debug
dotnet test Clean.Architecture.slnx --
================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
name: CodeQL Analysis
on:
push:
branches: [ main ]
pull_request:
schedule:
- cron: '0 8 * * *'
jobs:
analyze:
name: CodeQL Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout repository
id: checkout_repo
uses: actions/checkout@v4
- name: Initialize CodeQL
id: init_codeql
uses: github/codeql-action/init@v3
with:
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
id: analyze_codeql
uses: github/codeql-action/analyze@v3
# Built with ❤ by [Pipeline Foundation](https://pipeline.foundation)
================================================
FILE: .github/workflows/dotnetcore.yml
================================================
name: .NET Core
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
- name: Build Full Template
run: dotnet build ./Clean.Architecture.slnx -c Release
- name: Test Full Template
run: dotnet test ./Clean.Architecture.slnx -c Release --no-build --verbosity normal
- name: Build MinimalClean Template
run: dotnet build ./MinimalClean/MinimalClean.Architecture.slnx -c Release
================================================
FILE: .github/workflows/publish-templates.yml
================================================
name: Publish Templates to NuGet
on:
workflow_dispatch:
inputs:
publish-full:
description: 'Publish Full Clean Architecture Template'
required: true
type: boolean
default: false
publish-minimal:
description: 'Publish Minimal Clean Architecture Template'
required: true
type: boolean
default: false
push:
tags:
- 'v*'
release:
types: [published]
env:
DOTNET_VERSION: '10.0.x'
PACK_OUTPUT: artifacts/packages
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Build Full Template Solution
run: dotnet build ./Clean.Architecture.slnx -c Release
- name: Test Full Template
run: dotnet test ./Clean.Architecture.slnx -c Release --no-build --verbosity normal
- name: Build MinimalClean Template Solution
run: dotnet build ./MinimalClean/MinimalClean.Architecture.slnx -c Release
- name: Test Template Installations
shell: pwsh
run: |
# Test Full Template
# Write-Host "Testing Full Clean Architecture Template..."
# dotnet new install .
# dotnet new clean-arch -o TestFullTemplate
# dotnet build TestFullTemplate/TestFullTemplate.slnx
# dotnet new uninstall Ardalis.CleanArchitecture.Template
# Remove-Item -Recurse -Force TestFullTemplate
# Test Minimal Template
# Write-Host "Testing Minimal Clean Architecture Template..."
# dotnet new install ./MinimalClean
# dotnet new min-clean -o TestMinimalTemplate
# dotnet build TestMinimalTemplate/TestMinimalTemplate.slnx
# dotnet new uninstall Ardalis.MinimalClean.Template
# Remove-Item -Recurse -Force TestMinimalTemplate
package:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup NuGet
uses: nuget/setup-nuget@v2
with:
nuget-version: 'latest'
- name: Install Mono
run: sudo apt-get update && sudo apt-get install -y mono-complete
- name: Create output directory
run: mkdir -p ${{ env.PACK_OUTPUT }}
- name: Pack Full Template
if: ${{ github.event_name == 'release' || github.event.inputs.publish-full == 'true' }}
run: nuget pack CleanArchitecture.nuspec -OutputDirectory ${{ env.PACK_OUTPUT }} -NoDefaultExcludes
- name: Pack Minimal Template
if: ${{ github.event_name == 'release' || github.event.inputs.publish-minimal == 'true' }}
run: nuget pack MinimalClean.nuspec -OutputDirectory ${{ env.PACK_OUTPUT }} -NoDefaultExcludes
- name: Upload packages as artifacts
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: ${{ env.PACK_OUTPUT }}/*.nupkg
publish:
needs: package
runs-on: ubuntu-latest
#if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
permissions:
contents: read
id-token: write
steps:
- name: Download packages
uses: actions/download-artifact@v4
with:
name: nuget-packages
path: ${{ env.PACK_OUTPUT }}
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: NuGet login (OIDC)
uses: NuGet/login@v1
id: login
with:
user: ${{ secrets.NUGET_USER }}
- name: Push packages to NuGet
shell: pwsh
run: |
Get-ChildItem "${{ env.PACK_OUTPUT }}" -Filter *.nupkg | ForEach-Object {
Write-Host "Publishing $($_.Name)..."
dotnet nuget push $_.FullName `
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}" `
--source https://api.nuget.org/v3/index.json `
--skip-duplicate
}
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish to Nuget
on:
workflow_dispatch:
push:
tags:
- 'v*'
release:
types: [published]
env:
SOLUTION_FILE: Clean.Architecture.slnx
NUSPEC_FILE: CleanArchitecture.nuspec
PACK_OUTPUT: artifacts/package/release
jobs:
build:
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Build
run: dotnet build "${{ env.SOLUTION_FILE }}" --configuration Release
- name: Test
run: dotnet test "${{ env.SOLUTION_FILE }}" --configuration Release --no-build --no-restore
- uses: nuget/setup-nuget@v2
name: Setup NuGet
with:
nuget-version: 'latest'
- name: Install Mono
run: sudo apt-get update && sudo apt-get install -y mono-complete
- name: Pack (nuspec)
run: nuget pack "${{ env.NUSPEC_FILE }}" -OutputDirectory "${{ env.PACK_OUTPUT }}" -NoDefaultExcludes
- name: NuGet login (OIDC -> temp API key)
uses: NuGet/login@v1
id: login
with:
user: ${{ secrets.NUGET_USER }}
- name: Push to NuGet
#if: ${{ github.event_name == 'release' && github.event.action == 'published' && github.event.release.tag_name != '' }}
shell: pwsh
run: |
Get-ChildItem "${{ env.PACK_OUTPUT }}" -Filter *.nupkg | ForEach-Object {
dotnet nuget push $_.FullName `
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}" `
--source https://api.nuget.org/v3/index.json
}
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
*.sqlite
*.sqlite-shm
*.sqlite-wal
# Nuget files
DeploymentSettings.props
Packages.props
#Local Log Files
log*.txt
/sample/src/NimblePros.SampleToDo.Web/appsettings.Development.json
================================================
FILE: .runsettings
================================================
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<RunConfiguration>
<!-- Enable parallel test execution at the assembly level -->
<MaxCpuCount>0</MaxCpuCount>
<!-- 0 means use all available processors -->
<DisableParallelization>false</DisableParallelization>
</RunConfiguration>
<xUnit>
<!-- Configure xUnit-specific settings -->
<ParallelizeAssembly>true</ParallelizeAssembly>
<ParallelizeTestCollections>true</ParallelizeTestCollections>
<MaxParallelThreads>0</MaxParallelThreads>
<!-- 0 means use default algorithm (processors * 2) -->
</xUnit>
</RunSettings>
================================================
FILE: .template.config/template.json
================================================
{
"$schema": "http://json.schemastore.org/template",
"author": "ardalis (Steve Smith)",
"classifications": [
"Web",
"ASP.NET",
"Clean Architecture"
],
"tags": {
"language": "C#",
"type": "project"
},
"identity": "Ardalis.CleanArchitecture.Template",
"name": "ASP.NET Clean Architecture Solution",
"shortName": "clean-arch",
"sourceName": "Clean.Architecture",
"templateFileExtensions": [ ".cs", ".csproj", ".slnx" ],
"preferNameDirectory": true,
"sources": [
{
"include": [
"**/*"
],
"exclude": [
".vs/**",
".vscode/**",
".git/**",
".github/**",
".idea/**",
".template.config/**",
"docs/**",
"sample/**"
],
"modifiers": [
{
"condition": "true",
"copyOnly": [ "*.dll", "*.png", "*.ico", "*.jpg", "*.jpeg", "*.ps1" ]
},
{
"rename": {
"README.template.md": "README.md"
}
}
]
}
]
}
================================================
FILE: .vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md.
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Clean.Architecture.Web/bin/Debug/net8.0/Clean.Architecture.Web.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Clean.Architecture.Web",
"stopAtEntry": false,
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#6b9a8e",
"activityBar.background": "#6b9a8e",
"activityBar.foreground": "#15202b",
"activityBar.inactiveForeground": "#15202b99",
"activityBarBadge.background": "#684e72",
"activityBarBadge.foreground": "#e7e7e7",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#6b9a8e",
"statusBar.background": "#557d73",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#6b9a8e",
"statusBarItem.remoteBackground": "#557d73",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#557d73",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#557d7399",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#557d73"
}
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Clean.Architecture.slnx",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Clean.Architecture.slnx",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/Clean.Architecture.slnx"
],
"problemMatcher": "$msCompile"
}
]
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant
to clarify expected behavior in our community.
For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Ardalis.CleanArchitecture
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
## We Develop with GitHub
Obviously...
## We Use Pull Requests
Mostly. But pretty much exclusively for non-maintainers. You'll need to fork the repo in order to submit a pull request. Here are the basic steps:
1. Fork the repo and create your branch from `main`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
6. Issue that pull request!
- [Pull Request Check List](https://ardalis.com/github-pull-request-checklist/)
- [Resync your fork with this upstream repo](https://ardalis.com/syncing-a-fork-of-a-github-repository-with-upstream/)
## Ask before adding a pull request
You can just add a pull request out of the blue if you want, but it's much better etiquette (and more likely to be accepted) if you open a new issue or comment in an existing issue stating you'd like to make a pull request.
## Getting Started
Look for [issues marked with 'help wanted'](https://github.com/ardalis/CleanArchitecture/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) to find good places to start contributing.
## Any contributions you make will be under the MIT Software License
In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers this project.
## Report bugs using Github's [issues](https://github.com/ardalis/CleanArchitecture/issues)
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/ardalis/CleanArchitecture/issues/new/choose); it's that easy!
## Sponsor us
If you don't have the time or expertise to contribute code, you can still support us by [sponsoring](https://github.com/sponsors/ardalis).
================================================
FILE: Clean.Architecture.slnx
================================================
<Solution>
<Configurations>
<Platform Name="Any CPU" />
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path=".template.config/template.json" />
<File Path="CleanArchitecture.nuspec" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
</Folder>
<Folder Name="/src/">
<Project Path="src/Clean.Architecture.Core/Clean.Architecture.Core.csproj" />
<Project Path="src/Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj" />
<Project Path="src/Clean.Architecture.UseCases/Clean.Architecture.UseCases.csproj" />
<Project Path="src/Clean.Architecture.Web/Clean.Architecture.Web.csproj" />
</Folder>
<Folder Name="/src/_aspire/">
<Project Path="src/Clean.Architecture.AspireHost/Clean.Architecture.AspireHost.csproj" />
<Project Path="src/Clean.Architecture.ServiceDefaults/Clean.Architecture.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/Clean.Architecture.FunctionalTests/Clean.Architecture.FunctionalTests.csproj">
<BuildDependency Project="src/Clean.Architecture.Web/Clean.Architecture.Web.csproj" />
</Project>
<Project Path="tests/Clean.Architecture.IntegrationTests/Clean.Architecture.IntegrationTests.csproj">
<BuildDependency Project="src/Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj" />
</Project>
<Project Path="tests/Clean.Architecture.UnitTests/Clean.Architecture.UnitTests.csproj" />
</Folder>
</Solution>
================================================
FILE: CleanArchitecture.nuspec
================================================
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Ardalis.CleanArchitecture.Template</id>
<title>ASP.NET Core Clean Architecture Solution</title>
<version>11.0.1</version>
<authors>Steve Smith</authors>
<description>
The Clean Architecture Solution Template popularized by Steve @ardalis Smith. Provides a great starting point for modern and/or DDD solutions built with .NET 10.
Features zero tight coupling to database or data access technology.
</description>
<language>en-US</language>
<license type="expression">MIT</license>
<projectUrl>https://github.com/ardalis/CleanArchitecture</projectUrl>
<releaseNotes>
* Update dependencies.
</releaseNotes>
<packageTypes>
<packageType name="Template" />
</packageTypes>
<tags>Web ASP.NET "Clean Architecture" ddd domain-driven-design clean-architecture clean architecture ardalis SOLID</tags>
<icon>./content/icon.png</icon>
<readme>README.md</readme>
</metadata>
<files>
<file src=".\**" target="content" exclude="**\bin\**;**\obj\**;**\.git\**;**\.github\**;**\*.user;**\.vs\**;**\.vscode\**;**\.gitignore;**\sample\**" />
<file src="README.md" />
</files>
</package>
================================================
FILE: Directory.Build.props
================================================
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<NoWarn>1591</NoWarn> <!-- Remove this to turn on warnings for missing XML Comments -->
</PropertyGroup>
</Project>
================================================
FILE: Directory.Packages.props
================================================
<Project>
<ItemGroup>
<PackageVersion Include="Ardalis.GuardClauses" Version="5.0.0" />
<PackageVersion Include="Ardalis.HttpClientTestExtensions" Version="4.2.0" />
<PackageVersion Include="Ardalis.ListStartupServices" Version="1.1.4" />
<PackageVersion Include="Ardalis.Result" Version="10.1.0" />
<PackageVersion Include="Ardalis.Result.AspNetCore" Version="10.1.0" />
<PackageVersion Include="Ardalis.SharedKernel" Version="5.0.0" />
<PackageVersion Include="Ardalis.SmartEnum" Version="8.2.0" />
<PackageVersion Include="Ardalis.Specification" Version="9.3.1" />
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="FastEndpoints" Version="7.1.1" />
<PackageVersion Include="FastEndpoints.ApiExplorer" Version="2.2.0" />
<PackageVersion Include="FastEndpoints.Swagger" Version="7.1.1" />
<PackageVersion Include="MailKit" Version="4.15.1" />
<PackageVersion Include="Mediator.Abstractions" Version="3.0.1" />
<PackageVersion Include="Mediator.SourceGenerator" Version="3.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="NimblePros.Metronome" Version="0.4.1" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="ReportGenerator" Version="5.5.0" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.10.3" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="SQLite" Version="3.13.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="Testcontainers" Version="4.3.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.3.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.0.0" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="13.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.0.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.13.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.13.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.13.0" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="9.5.1" />
<PackageVersion Include="Vogen" Version="8.0.2" />
</ItemGroup>
</Project>
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2016 Steve Smith
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MinimalClean/.editorconfig
================================================
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 2
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
tab_width= 2
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
dotnet_style_operator_placement_when_wrapping = beginning_of_line
end_of_line = crlf
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Namespaces
csharp_style_namespace_declarations = file_scoped:warning
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
csharp_using_directive_placement = outside_namespace:suggestion
csharp_prefer_simple_using_statement = true:suggestion
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
================================================
FILE: MinimalClean/.gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015/2017/2019/2022 cache/options directory
.vs/
.vscode/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# Database files
*.db
*.db-shm
*.db-wal
*.sqlite
*.sqlite3
# Entity Framework Core migrations (keep migrations folder, ignore db files)
**/Migrations/*.db
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac desktop service store files
.DS_Store
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
================================================
FILE: MinimalClean/.runsettings
================================================
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<RunConfiguration>
<!-- Enable parallel test execution at the assembly level -->
<MaxCpuCount>0</MaxCpuCount>
<!-- 0 means use all available processors -->
<DisableParallelization>false</DisableParallelization>
</RunConfiguration>
<xUnit>
<!-- Configure xUnit-specific settings -->
<ParallelizeAssembly>true</ParallelizeAssembly>
<ParallelizeTestCollections>true</ParallelizeTestCollections>
<MaxParallelThreads>0</MaxParallelThreads>
<!-- 0 means use default algorithm (processors * 2) -->
</xUnit>
</RunSettings>
================================================
FILE: MinimalClean/.template.config/template.json
================================================
{
"$schema": "http://json.schemastore.org/template",
"author": "ardalis (Steve Smith)",
"classifications": [
"Web",
"ASP.NET",
"Clean Architecture",
"Minimal"
],
"tags": {
"language": "C#",
"type": "project"
},
"identity": "Ardalis.MinimalClean.Template",
"name": "ASP.NET Minimal Clean Architecture Solution",
"shortName": "min-clean",
"sourceName": "MinimalClean.Architecture",
"templateFileExtensions": [ ".cs", ".csproj", ".slnx" ],
"preferNameDirectory": true,
"sources": [
{
"include": [
"**/*"
],
"exclude": [
".vs/**",
".vscode/**",
".git/**",
".github/**",
".idea/**",
".template.config/**",
"**/bin/**",
"**/obj/**",
"**/.vs/**"
],
"modifiers": [
{
"condition": "true",
"copyOnly": [ "*.dll", "*.png", "*.ico", "*.jpg", "*.jpeg", "*.ps1" ]
},
{
"rename": {
"README.template.md": "README.md"
}
}
]
}
]
}
================================================
FILE: MinimalClean/Directory.Build.props
================================================
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<NoWarn>1591</NoWarn> <!-- Remove this to turn on warnings for missing XML Comments -->
</PropertyGroup>
</Project>
================================================
FILE: MinimalClean/Directory.Packages.props
================================================
<Project>
<ItemGroup>
<PackageVersion Include="Ardalis.GuardClauses" Version="5.0.0" />
<PackageVersion Include="Ardalis.HttpClientTestExtensions" Version="4.2.0" />
<PackageVersion Include="Ardalis.ListStartupServices" Version="1.1.4" />
<PackageVersion Include="Ardalis.Result" Version="10.1.0" />
<PackageVersion Include="Ardalis.Result.AspNetCore" Version="10.1.0" />
<PackageVersion Include="Ardalis.SharedKernel" Version="5.0.0" />
<PackageVersion Include="Ardalis.SmartEnum" Version="8.2.0" />
<PackageVersion Include="Ardalis.Specification" Version="9.3.1" />
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="FastEndpoints" Version="7.1.1" />
<PackageVersion Include="FastEndpoints.ApiExplorer" Version="2.2.0" />
<PackageVersion Include="FastEndpoints.Swagger" Version="7.1.1" />
<PackageVersion Include="MailKit" Version="4.14.1" />
<PackageVersion Include="Mediator.Abstractions" Version="3.0.1" />
<PackageVersion Include="Mediator.SourceGenerator" Version="3.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="MimeKit" Version="4.15.1" />
<PackageVersion Include="NimblePros.Metronome" Version="0.4.1" />
<PackageVersion Include="NsDepCop" Version="2.6.0" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="ReportGenerator" Version="5.5.0" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.10.3" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="SQLite" Version="3.13.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="Testcontainers" Version="4.3.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.3.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.0.0" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="13.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.0.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.13.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.13.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.13.0" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="9.5.1" />
<PackageVersion Include="Vogen" Version="8.0.2" />
</ItemGroup>
</Project>
================================================
FILE: MinimalClean/MinimalClean.Architecture.slnx
================================================
<Solution>
<Configurations>
<Platform Name="Any CPU" />
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Folder Name="/Solution Items/">
<File Path="../MinimalClean.nuspec" />
<File Path=".editorconfig" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
</Folder>
<Folder Name="/src/">
<Project Path="src/MinimalClean.Architecture.Web/MinimalClean.Architecture.Web.csproj" />
</Folder>
<Folder Name="/src/_aspire/">
<Project Path="src/MinimalClean.Architecture.AspireHost/MinimalClean.Architecture.AspireHost.csproj" />
<Project Path="src/MinimalClean.Architecture.ServiceDefaults/MinimalClean.Architecture.ServiceDefaults.csproj" />
</Folder>
</Solution>
================================================
FILE: MinimalClean/README.template.md
================================================
# MinimalClean.Architecture
Welcome to your new project generated with the **Minimal Clean Architecture** template!
This is a streamlined, single-project Vertical Slice Architecture (VSA) that follows Clean Architecture principles without the overhead of multiple projects. Perfect for smaller applications, MVPs, or teams that want architectural guidance without complex project boundaries.
## Getting Started
### Build and Run
```powershell
# Build the solution
dotnet build
# Run the application
dotnet run --project src/MinimalClean.Architecture.Web
# Or run with Aspire (if using)
dotnet run --project src/MinimalClean.Architecture.AspireHost
```
### Database Setup
This template uses **SQL Server in a container** managed by Aspire. When you run the Aspire AppHost, it automatically starts a SQL Server container and creates the database.
#### Option 1: Run with Aspire (Recommended)
```powershell
dotnet run --project src/MinimalClean.Architecture.AspireHost
```
The SQL Server container and database are automatically provisioned and migrations are applied on startup.
#### Option 2: Run Web project directly (SQL Server LocalDB)
If running the Web project without Aspire, update `appsettings.json` to use LocalDB:
```powershell
dotnet ef database update -c AppDbContext -p src/MinimalClean.Architecture.Web -s src/MinimalClean.Architecture.Web
dotnet run --project src/MinimalClean.Architecture.Web
```
## Project Structure
This template uses a **single Web project** organized by **vertical slices** (features):
```text
src/MinimalClean.Architecture.Web/
├── Domain/ # Domain entities and aggregates
│ ├── CartAggregate/
│ ├── OrderAggregate/
│ └── ProductAggregate/
├── Infrastructure/ # Data access and external services
│ ├── Data/
│ │ ├── AppDbContext.cs
│ │ ├── Config/ # EF Core configurations
│ │ └── Migrations/
│ └── Email/ # Email services
├── Endpoints/ # API endpoints (FastEndpoints)
│ ├── Cart/
│ ├── Order/
│ └── Product/
└── Program.cs # Application startup
```
### Key Design Decisions
```text
Single project vertical slice architecture
```
- **Single Project**: All code in one Web project - simpler dependencies, faster builds
- **Vertical Slices**: Organized by feature (Cart, Order, Product) not layer
- **Domain-Driven Design**: Entities use proper encapsulation and business logic
- **FastEndpoints**: REPR pattern for clean, testable API endpoints
- **Entity Framework Core**: Simple data access with SQLite (easily switched to SQL Server)
- **Mediator Pattern**: Optional - use for cross-cutting concerns or remove for simplicity
## What's Different from Full Clean Architecture?
This minimal template simplifies the full Clean Architecture template:
| Full Template | Minimal Template |
|--------------|------------------|
| 4+ projects (Core, UseCases, Infrastructure, Web) | 1 Web project |
| Repository pattern with Specifications | Repository pattern with Specifications if needed |
| Extensive use of interfaces and abstractions | Pragmatic abstractions where needed |
| Separate Use Cases project with Mediator | Optional Mediator; logic can be in endpoints |
| Complex domain patterns (Aggregates, Value Objects, Domain Events) | Pragmatic DDD patterns (Aggregates, Value Objects) |
## When to Use This Template
**Use Minimal Clean Architecture when:**
- ✓ Building MVPs or smaller applications
- ✓ You want architectural guidance without project ceremony
- ✓ Team prefers simplicity and fast iteration
- ✓ Vertical slice architecture appeals to you
- ✓ You may grow into full Clean Architecture later
**Use Full Clean Architecture when:**
- × Building large, complex enterprise applications
- × Multiple teams working on different layers
- × Need strict separation of concerns and dependencies
- × Domain complexity requires extensive DDD patterns
- × Long-term maintenance and evolution expected
## Technology Stack
- **.NET 10**: Latest LTS framework
- **FastEndpoints**: REPR pattern for API endpoints
- **Entity Framework Core**: Data access with migrations
- **SQL Server**: Containerized database via Aspire (easily switched to PostgreSQL, SQLite, etc.)
- **Aspire**: Cloud-ready orchestration and observability
- **Serilog**: Structured logging
- **FluentValidation**: Request validation
## Common Tasks
### Adding a New Feature (Vertical Slice)
1. **Create Domain Entity**: Add to `Domain/YourFeatureAggregate/`
2. **Add EF Configuration**: Create config in `Infrastructure/Data/Config/`
3. **Create Migration**: `dotnet ef migrations add AddYourFeature`
4. **Create Endpoints**: Add FastEndpoints in `Endpoints/YourFeature/`
### Switching to SQL Server
Update `appsettings.json`:
```json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=YourDb;Trusted_Connection=true;"
}
}
```
### Running Tests
```powershell
dotnet test
```
## Migration Path to Full Clean Architecture
As your application grows, you can migrate to the full Clean Architecture template:
1. **Extract Core**: Move Domain entities to separate Core project
2. **Extract UseCases**: Move business logic to UseCases project with Mediator
3. **Extract Infrastructure**: Move data access to Infrastructure project
4. **Update Dependencies**: Set up proper dependency flow (Core ← UseCases ← Infrastructure)
Learn more: [Clean Architecture Template](https://github.com/ardalis/CleanArchitecture)
## Resources
- [Clean Architecture Template Repository](https://github.com/ardalis/CleanArchitecture)
- [Vertical Slice Architecture](https://jimmybogard.com/vertical-slice-architecture/)
- [FastEndpoints Documentation](https://fast-endpoints.com/)
- [Ardalis on YouTube](https://www.youtube.com/@Ardalis)
## Need Help?
- Report issues: [GitHub Issues](https://github.com/ardalis/CleanArchitecture/issues)
- Ask questions: [Discussions](https://github.com/ardalis/CleanArchitecture/discussions)
- Follow updates: [@ardalis](https://twitter.com/ardalis)
---
**Happy Coding!** 🚀
================================================
FILE: MinimalClean/global.json
================================================
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestMajor",
"allowPrerelease": true
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/AppHost.cs
================================================
using System.Net.Sockets;
var builder = DistributedApplication.CreateBuilder(args);
// Add SQL Server container
var sqlServer = builder.AddSqlServer("sqlserver")
.WithLifetime(ContainerLifetime.Persistent);
// Add the database
var appDb = sqlServer.AddDatabase("AppDb");
// Papercut SMTP container for email testing
var papercut = builder.AddContainer("papercut", "jijiechen/papercut", "latest")
.WithEndpoint("smtp", e =>
{
e.TargetPort = 25; // container port
e.Port = 25; // host port
e.Protocol = ProtocolType.Tcp;
e.UriScheme = "smtp";
})
.WithEndpoint("ui", e =>
{
e.TargetPort = 37408;
e.Port = 37408;
e.UriScheme = "http";
});
// register the API project and link the DB
builder.AddProject<Projects.MinimalClean_Architecture_Web>("web")
.WithEnvironment("ASPNETCORE_ENVIRONMENT", builder.Environment.EnvironmentName)
.WithReference(appDb)
.WaitFor(papercut)
.WaitFor(appDb)
.WithUrl("https://localhost:57379"); // Match launchSettings
builder.Build().Run();
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/MinimalClean.Architecture.AspireHost.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="13.0.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<UserSecretsId>47f99468-f41d-48b8-ae3f-69682954d973</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
<PackageReference Include="Aspire.Hosting.SqlServer" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
</ItemGroup>
<ItemGroup>
<!-- The IsAspireProjectResource attribute tells .NET Aspire to treat this
reference as a standard project reference and not attempt to generate
a metadata file -->
<ProjectReference Include="..\MinimalClean.Architecture.ServiceDefaults\MinimalClean.Architecture.ServiceDefaults.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\MinimalClean.Architecture.Web\MinimalClean.Architecture.Web.csproj" />
</ItemGroup>
</Project>
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/Properties/launchSettings.json
================================================
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17143;http://localhost:15258",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21007",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22245"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15258",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19187",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20134"
}
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.Development.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/Extensions.cs
================================================
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ServiceDiscovery;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.Hosting;
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
// This project should be referenced by each service project in your solution.
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
public static class Extensions
{
private const string HealthEndpointPath = "/health";
private const string AlivenessEndpointPath = "/alive";
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
// Turn on resilience by default
http.AddStandardResilienceHandler();
// Turn on service discovery by default
http.AddServiceDiscovery();
});
// Uncomment the following to restrict the allowed schemes for service discovery.
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
// {
// options.AllowedSchemes = ["https"];
// });
return builder;
}
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddSource(builder.Environment.ApplicationName)
.AddAspNetCoreInstrumentation(tracing =>
// Exclude health check requests from tracing
tracing.Filter = context =>
!context.Request.Path.StartsWithSegments(HealthEndpointPath)
&& !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
)
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
//.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
});
builder.AddOpenTelemetryExporters();
return builder;
}
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
if (useOtlpExporter)
{
builder.Services.AddOpenTelemetry().UseOtlpExporter();
}
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
//{
// builder.Services.AddOpenTelemetry()
// .UseAzureMonitor();
//}
return builder;
}
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
builder.Services.AddHealthChecks()
// Add a default liveness check to ensure app is responsive
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
return builder;
}
public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
// Adding health checks endpoints to applications in non-development environments has security implications.
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
if (app.Environment.IsDevelopment())
{
// All health checks must pass for app to be considered ready to accept traffic after starting
app.MapHealthChecks(HealthEndpointPath);
// Only health checks tagged with the "live" tag must pass for app to be considered alive
app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
}
return app;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/MinimalClean.Architecture.ServiceDefaults.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsAspireSharedProject>true</IsAspireSharedProject>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
</ItemGroup>
</Project>
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/AssemblyInfo.cs
================================================
using Vogen;
[assembly: VogenDefaults(
staticAbstractsGeneration: StaticAbstractsGeneration.MostCommon |
StaticAbstractsGeneration.InstanceMethodsAndProperties)]
namespace MinimalClean.Architecture.Web;
public class AssemblyInfo { }
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartEndpoint.cs
================================================
using FluentValidation;
using Microsoft.AspNetCore.Http.HttpResults;
using MinimalClean.Architecture.Web.Domain.CartAggregate;
namespace MinimalClean.Architecture.Web.CartFeatures.AddToCart;
public sealed class AddToCartRequest
{
public const string Route = "/cart";
public Guid? CartId { get; init; }
public int ProductId { get; init; }
public int Quantity { get; init; }
}
public class AddToCartEndpoint(IMediator mediator)
: FastEndpoints.Endpoint<AddToCartRequest,
Results<Ok<CartResponse>,
NotFound,
ValidationProblem,
ProblemHttpResult>,
AddToCartMapper>
{
public override void Configure()
{
Post(AddToCartRequest.Route);
AllowAnonymous();
Summary(s =>
{
s.Summary = "Add item to cart";
s.Description = "Adds a product to an existing cart or creates a new cart if CartId is not provided. Returns the updated cart with all items.";
s.ExampleRequest = new AddToCartRequest
{
CartId = null, // null creates new cart
ProductId = 1,
Quantity = 2
};
s.ResponseExamples[200] = new CartResponse(
Guid.Empty,
new List<CartItemResponse>
{
new(1, 2, 999.99m, 1999.98m)
},
1999.98m);
// Document possible responses
s.Responses[200] = "Item added to cart successfully";
s.Responses[404] = "Product or Cart not found";
s.Responses[400] = "Invalid request data";
});
// Add tags for API grouping
Tags("Cart");
// Add additional metadata
Description(builder => builder
.Accepts<AddToCartRequest>("application/json")
.Produces<CartResponse>(200, "application/json")
.ProducesProblem(404)
.ProducesProblem(400));
}
public override async Task<Results<Ok<CartResponse>, NotFound, ValidationProblem, ProblemHttpResult>>
ExecuteAsync(AddToCartRequest request, CancellationToken ct)
{
var cartId = request.CartId.HasValue ? CartId.From(request.CartId.Value) : (CartId?)null;
var command = new AddToCartCommand(cartId, request.ProductId, request.Quantity);
var result = await mediator.Send(command, ct);
if (result.Status == ResultStatus.NotFound)
{
return TypedResults.NotFound();
}
if (!result.IsSuccess)
{
return TypedResults.Problem(result.Errors.FirstOrDefault() ?? "An error occurred");
}
var response = Map.FromEntity(result.Value);
return TypedResults.Ok(response);
}
}
public sealed class AddToCartValidator : FastEndpoints.Validator<AddToCartRequest>
{
public AddToCartValidator()
{
RuleFor(x => x.ProductId)
.GreaterThan(0)
.WithMessage("Product ID must be greater than 0");
RuleFor(x => x.Quantity)
.GreaterThan(0)
.WithMessage("Quantity must be greater than 0");
}
}
public sealed class AddToCartMapper
: FastEndpoints.Mapper<AddToCartRequest, CartResponse, CartDto>
{
public override CartResponse FromEntity(CartDto e)
{
var items = e.Items.Select(i => new CartItemResponse(
i.ProductId,
i.Quantity,
i.UnitPrice,
i.TotalPrice
)).ToList();
return new CartResponse(e.Id.Value, items, e.Total);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartHandler.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications;
namespace MinimalClean.Architecture.Web.CartFeatures.AddToCart;
public record AddToCartCommand(CartId? CartId, int ProductId, int Quantity) : ICommand<Result<CartDto>>;
public class AddToCartHandler(
IRepository<Cart> cartRepository,
IReadRepository<Product> productRepository)
: ICommandHandler<AddToCartCommand, Result<CartDto>>
{
public async ValueTask<Result<CartDto>> Handle(AddToCartCommand request, CancellationToken cancellationToken)
{
// Validate product exists
var productSpec = new ProductByIdSpec(ProductId.From(request.ProductId));
var product = await productRepository.FirstOrDefaultAsync(productSpec, cancellationToken);
if (product == null)
{
return Result.NotFound("Product not found");
}
// Get or create cart
Cart cart;
if (request.CartId.HasValue)
{
var cartSpec = new CartByIdSpec(request.CartId.Value);
var existingCart = await cartRepository.FirstOrDefaultAsync(cartSpec, cancellationToken);
if (existingCart == null)
{
return Result.NotFound("Cart not found");
}
cart = existingCart;
}
else
{
// Create new cart - AddAsync saves by default
cart = new Cart();
cart = await cartRepository.AddAsync(cart, cancellationToken);
}
// Add item to cart
cart.AddItem(request.ProductId, request.Quantity, product.UnitPrice);
// Update the cart with the new items
await cartRepository.UpdateAsync(cart, cancellationToken);
// Map to DTO
var items = cart.Items.Select(i => new CartItemDto(
i.ProductId,
i.Quantity,
i.UnitPrice,
i.Quantity * i.UnitPrice
)).ToList();
var total = items.Sum(i => i.TotalPrice);
return new CartDto(cart.Id, items, total);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartDto.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
namespace MinimalClean.Architecture.Web.CartFeatures;
public record CartDto(CartId Id, IReadOnlyList<CartItemDto> Items, decimal Total);
public record CartItemDto(int ProductId, int Quantity, decimal UnitPrice, decimal TotalPrice);
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartResponse.cs
================================================
namespace MinimalClean.Architecture.Web.CartFeatures;
public record CartResponse(Guid CartId, IReadOnlyList<CartItemResponse> Items, decimal Total);
public record CartItemResponse(int ProductId, int Quantity, decimal UnitPrice, decimal TotalPrice);
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutEndpoint.cs
================================================
using FastEndpoints;
using FluentValidation;
using Microsoft.AspNetCore.Http.HttpResults;
using MinimalClean.Architecture.Web.Domain.CartAggregate;
namespace MinimalClean.Architecture.Web.CartFeatures.Checkout;
public sealed class CheckoutRequest
{
public const string Route = "/cart/{CartId}/checkout";
public Guid CartId { get; init; }
public string Email { get; init; } = string.Empty;
}
public record CheckoutResponse(Guid OrderId);
public class CheckoutEndpoint(IMediator mediator)
: Endpoint<CheckoutRequest,
Results<Ok<CheckoutResponse>,
NotFound,
ValidationProblem,
ProblemHttpResult>,
CheckoutMapper>
{
public override void Configure()
{
Post(CheckoutRequest.Route);
AllowAnonymous();
Summary(s =>
{
s.Summary = "Checkout cart";
s.Description = "Processes checkout for a cart, creating an order and marking the cart as completed. Requires a guest email address.";
s.ExampleRequest = new CheckoutRequest
{
CartId = Guid.Parse("12345678-1234-1234-1234-123456789012"),
Email = "guest@example.com"
};
s.ResponseExamples[200] = new CheckoutResponse(
Guid.Parse("87654321-4321-4321-4321-210987654321"));
// Document possible responses
s.Responses[200] = "Checkout completed successfully";
s.Responses[404] = "Cart not found";
s.Responses[400] = "Invalid request data or empty cart";
});
// Add tags for API grouping
Tags("Cart");
// Add additional metadata
Description(builder => builder
.Accepts<CheckoutRequest>("application/json")
.Produces<CheckoutResponse>(200, "application/json")
.ProducesProblem(404)
.ProducesProblem(400));
}
public override async Task<Results<Ok<CheckoutResponse>, NotFound, ValidationProblem, ProblemHttpResult>>
ExecuteAsync(CheckoutRequest request, CancellationToken ct)
{
var cartId = CartId.From(request.CartId);
var command = new CheckoutCommand(cartId, request.Email);
var result = await mediator.Send(command, ct);
if (result.Status == ResultStatus.NotFound)
{
return TypedResults.NotFound();
}
if (result.Status == ResultStatus.Invalid)
{
return TypedResults.ValidationProblem(result.ValidationErrors.ToDictionary(e => e.Identifier, e => new[] { e.ErrorMessage }));
}
if (!result.IsSuccess)
{
return TypedResults.Problem(result.Errors.FirstOrDefault() ?? "An error occurred during checkout");
}
var response = Map.FromEntity(result.Value);
return TypedResults.Ok(response);
}
}
public sealed class CheckoutValidator : Validator<CheckoutRequest>
{
public CheckoutValidator()
{
RuleFor(x => x.CartId)
.NotEqual(Guid.Empty)
.WithMessage("Cart ID is required");
RuleFor(x => x.Email)
.NotEmpty()
.WithMessage("Email is required")
.EmailAddress()
.WithMessage("Email must be a valid email address");
}
}
public sealed class CheckoutMapper
: Mapper<CheckoutRequest, CheckoutResponse, CheckoutResult>
{
public override CheckoutResponse FromEntity(CheckoutResult e) => new CheckoutResponse(e.OrderId.Value);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutHandler.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications;
using MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
using MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications;
using MinimalClean.Architecture.Web.Domain.OrderAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.CartFeatures.Checkout;
public record CheckoutCommand(CartId CartId, string Email) : ICommand<Result<CheckoutResult>>;
public record CheckoutResult(OrderId OrderId);
public class CheckoutHandler(
IRepository<Domain.CartAggregate.Cart> cartRepository,
IRepository<GuestUser> guestUserRepository,
IRepository<Order> orderRepository)
: ICommandHandler<CheckoutCommand, Result<CheckoutResult>>
{
public async ValueTask<Result<CheckoutResult>> Handle(CheckoutCommand request, CancellationToken cancellationToken)
{
// Find the cart with its items
var cartSpec = new CartByIdSpec(request.CartId);
var cart = await cartRepository.FirstOrDefaultAsync(cartSpec, cancellationToken);
if (cart == null) return Result.NotFound("Cart not found");
if (!cart.Items.Any()) return Result.Invalid(new ValidationError("Cart is empty"));
// Get or create guest user
var guestUserSpec = new GuestUserByEmailSpec(request.Email);
var guestUser = await guestUserRepository.FirstOrDefaultAsync(guestUserSpec, cancellationToken);
if (guestUser == null)
{
var guestUserId = GuestUserId.From(Guid.NewGuid());
guestUser = new GuestUser(guestUserId, request.Email);
guestUser = await guestUserRepository.AddAsync(guestUser, cancellationToken);
}
// Create new order
var orderId = OrderId.From(Guid.NewGuid());
var order = new Order(orderId, guestUser.Id.Value);
// Add items from cart to order
foreach (var cartItem in cart.Items)
{
order.AddItem(
ProductId.From(cartItem.ProductId),
Quantity.From(cartItem.Quantity),
Price.From(cartItem.UnitPrice));
}
await orderRepository.AddAsync(order, cancellationToken);
cart.MarkAsDeleted();
await cartRepository.UpdateAsync(cart, cancellationToken);
return new CheckoutResult(order.Id);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetByIdEndpoint.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Extensions;
using Microsoft.AspNetCore.Http.HttpResults;
using FastEndpoints;
namespace MinimalClean.Architecture.Web.CartFeatures.GetById;
public sealed class GetCartRequest
{
public const string Route = "/cart/{CartId}";
public Guid CartId { get; init; }
}
public class GetByIdEndpoint(IMediator mediator)
: Endpoint<GetCartRequest,
Results<Ok<CartResponse>,
NotFound,
ProblemHttpResult>,
GetCartMapper>
{
public override void Configure()
{
Get(GetCartRequest.Route);
AllowAnonymous();
Summary(s =>
{
s.Summary = "Get cart by ID";
s.Description = "Retrieves a cart and all its items by cart ID.";
s.ExampleRequest = new GetCartRequest
{
CartId = Guid.Parse("12345678-1234-1234-1234-123456789012")
};
s.ResponseExamples[200] = new CartResponse(
Guid.Parse("12345678-1234-1234-1234-123456789012"),
new List<CartItemResponse>
{
new(1, 2, 999.99m, 1999.98m)
},
1999.98m);
// Document possible responses
s.Responses[200] = "Cart retrieved successfully";
s.Responses[404] = "Cart not found";
});
// Add tags for API grouping
Tags("Cart");
// Add additional metadata
Description(builder => builder
.Produces<CartResponse>(200, "application/json")
.ProducesProblem(404));
}
public override async Task<Results<Ok<CartResponse>, NotFound, ProblemHttpResult>>
ExecuteAsync(GetCartRequest request, CancellationToken ct)
{
var cartId = CartId.From(request.CartId);
var query = new GetCartQuery(cartId);
var result = await mediator.Send(query, ct);
return result.ToGetByIdResult(Map.FromEntity);
}
}
public sealed class GetCartMapper
: Mapper<GetCartRequest, CartResponse, CartDto>
{
public override CartResponse FromEntity(CartDto e)
{
var items = e.Items.Select(i => new CartItemResponse(
i.ProductId,
i.Quantity,
i.UnitPrice,
i.TotalPrice
)).ToList();
return new CartResponse(e.Id.Value, items, e.Total);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetCartHandler.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications;
namespace MinimalClean.Architecture.Web.CartFeatures.GetById;
public record GetCartQuery(CartId CartId) : IQuery<Result<CartDto>>;
public class GetCartHandler(IReadRepository<Domain.CartAggregate.Cart> repository)
: IQueryHandler<GetCartQuery, Result<CartDto>>
{
public async ValueTask<Result<CartDto>> Handle(GetCartQuery request, CancellationToken cancellationToken)
{
var spec = new CartByIdSpec(request.CartId);
var cart = await repository.FirstOrDefaultAsync(spec, cancellationToken);
if (cart == null)
{
return Result.NotFound("Cart not found");
}
// Map to DTO
var items = cart.Items.Select(i => new CartItemDto(
i.ProductId,
i.Quantity,
i.UnitPrice,
i.Quantity * i.UnitPrice
)).ToList();
var total = items.Sum(i => i.TotalPrice);
return new CartDto(cart.Id, items, total);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/DatabaseOptions.cs
================================================
namespace MinimalClean.Architecture.Web.Configurations;
/// <summary>
/// Configuration options for database management
/// </summary>
public class DatabaseOptions
{
/// <summary>
/// If true, drops and recreates the database on startup in Development environment.
/// WARNING: This will delete all existing data!
/// </summary>
public bool RecreateOnStartup { get; set; } = false;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggerConfigs.cs
================================================
using Serilog;
namespace MinimalClean.Architecture.Web.Configurations;
public static class LoggerConfigs
{
public static WebApplicationBuilder AddLoggerConfigs(this WebApplicationBuilder builder)
{
// Add Serilog as an additional logging provider alongside OpenTelemetry
// This allows both Serilog (for console/file) and OpenTelemetry (for Aspire) to work together
builder.Logging.AddSerilog(new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", builder.Environment.ApplicationName)
.WriteTo.Console()
.CreateLogger());
return builder;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggingBehavior.cs
================================================
using System.Diagnostics;
namespace Nimble.Modulith.Web;
public class LoggingBehavior<TRequest, TResponse>(ILogger<LoggingBehavior<TRequest, TResponse>> logger) : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull, IMessage
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger = logger;
public async ValueTask<TResponse> Handle(
TRequest request,
MessageHandlerDelegate<TRequest, TResponse> next,
CancellationToken cancellationToken)
{
if (_logger.IsEnabled(LogLevel.Information))
{
// Use structured logging with the whole object instead of reflection
_logger.LogInformation("Handling {RequestName}: {@Request}",
typeof(TRequest).Name, request);
}
var sw = Stopwatch.StartNew();
var response = await next(request, cancellationToken);
_logger.LogInformation(
"Handled {RequestName} with {Response} in {Ms} ms",
typeof(TRequest).Name,
response,
sw.ElapsedMilliseconds);
sw.Stop();
return response;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MediatorConfig.cs
================================================
namespace MinimalClean.Architecture.Web.Configurations;
public static class MediatorConfig
{
// Should be called from ServiceConfigs.cs, not Program.cs
public static IServiceCollection AddMediatorSourceGen(this IServiceCollection services,
ILogger logger)
{
logger.LogInformation("Registering Mediator SourceGen and Behaviors");
services.AddMediator(options =>
{
// Lifetime: Singleton is fastest per docs; Scoped/Transient also supported.
options.ServiceLifetime = ServiceLifetime.Scoped;
// Supply any TYPE from each assembly you want scanned (the generator finds the assembly from the type)
options.Assemblies =
[
typeof(MediatorConfig) // Web
];
// Register AOT pipeline behaviors here (order matters)
options.PipelineBehaviors =
[
typeof(Nimble.Modulith.Web.LoggingBehavior<,>)
];
// If you have stream behaviors:
// options.StreamPipelineBehaviors = [ typeof(YourStreamBehavior<,>) ];
});
return services;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MiddlewareConfig.cs
================================================
using Ardalis.ListStartupServices;
using FastEndpoints;
using FastEndpoints.Swagger;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using MinimalClean.Architecture.Web.Infrastructure.Data;
using Scalar.AspNetCore;
namespace MinimalClean.Architecture.Web.Configurations;
public static class MiddlewareConfig
{
public static async Task<IApplicationBuilder> UseAppMiddlewareAndSeedDatabase(this WebApplication app)
{
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseShowAllServicesMiddleware(); // see https://github.com/ardalis/AspNetCoreStartupServices
}
else
{
app.UseDefaultExceptionHandler(); // from FastEndpoints
app.UseHsts();
}
app.UseFastEndpoints();
if (app.Environment.IsDevelopment())
{
app.UseSwaggerGen(options =>
{
options.Path = "/openapi/{documentName}.json";
});
app.MapScalarApiReference();
}
app.UseHttpsRedirection(); // Note this will drop Authorization headers
await SeedDatabase(app);
return app;
}
static async Task SeedDatabase(WebApplication app)
{
using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<Program>>();
try
{
var context = services.GetRequiredService<AppDbContext>();
var dbOptions = services.GetService<IOptions<DatabaseOptions>>()?.Value;
// Drop and recreate database in development if configured
if (app.Environment.IsDevelopment() && dbOptions?.RecreateOnStartup == true)
{
logger.LogWarning("DROPPING database for fresh start (DatabaseOptions:RecreateOnStartup = true)...");
await context.Database.EnsureDeletedAsync();
logger.LogInformation("Database dropped.");
}
// Apply all pending migrations
logger.LogInformation("Applying database migrations...");
await context.Database.MigrateAsync();
logger.LogInformation("Database migrations applied successfully.");
// Seed data
await SeedData.InitializeAsync(context, logger);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred seeding the DB. {exceptionMessage}", ex.Message);
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/OptionConfigs.cs
================================================
using Ardalis.ListStartupServices;
using MinimalClean.Architecture.Web.Infrastructure.Email;
namespace MinimalClean.Architecture.Web.Configurations;
public static class OptionConfigs
{
public static IServiceCollection AddOptionConfigs(this IServiceCollection services,
IConfiguration configuration,
Microsoft.Extensions.Logging.ILogger logger,
WebApplicationBuilder builder)
{
services.Configure<MailserverConfiguration>(configuration.GetSection("Mailserver"))
.Configure<DatabaseOptions>(configuration.GetSection("DatabaseOptions"))
// Configure Web Behavior
.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
if (builder.Environment.IsDevelopment())
{
// add list services for diagnostic purposes - see https://github.com/ardalis/AspNetCoreStartupServices
services.Configure<ServiceConfig>(config =>
{
config.Services = new List<ServiceDescriptor>(builder.Services);
// optional - default path to view services is /listallservices - recommended to choose your own path
config.Path = "/listservices";
});
}
logger.LogInformation("{Project} were configured", "Options");
return services;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/ServiceConfigs.cs
================================================
using MinimalClean.Architecture.Web.Domain.Interfaces;
using MinimalClean.Architecture.Web.Infrastructure;
using MinimalClean.Architecture.Web.Infrastructure.Email;
namespace MinimalClean.Architecture.Web.Configurations;
public static class ServiceConfigs
{
public static IServiceCollection AddServiceConfigs(this IServiceCollection services, Microsoft.Extensions.Logging.ILogger logger, WebApplicationBuilder builder)
{
services.AddInfrastructureServices(builder.Configuration, logger)
.AddMediatorSourceGen(logger);
if (builder.Environment.IsDevelopment())
{
// Use a local test email server
// See: https://ardalis.com/configuring-a-local-test-email-server/
services.AddScoped<IEmailSender, MimeKitEmailSender>();
// Otherwise use this:
//builder.Services.AddScoped<IEmailSender, FakeEmailSender>();
}
else
{
services.AddScoped<IEmailSender, MimeKitEmailSender>();
}
logger.LogInformation("{Project} services registered", "Mediator and Email Sender");
return services;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Constants.cs
================================================
namespace MinimalClean.Architecture.Web;
public class Constants
{
public const int DEFAULT_PAGE_SIZE = 10;
public const int MAX_PAGE_SIZE = 100;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Cart.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.CartAggregate;
public class Cart : EntityBase<Cart, CartId>, IAggregateRoot
{
private readonly List<CartItem> _items = new();
public DateTime CreatedOn { get; private set; } = DateTime.UtcNow;
public bool Deleted { get; private set; } = false;
public IReadOnlyList<CartItem> Items => _items.AsReadOnly();
public void AddItem(int productId, int quantity, decimal unitPrice)
{
var item = new CartItem(productId, quantity, unitPrice);
_items.Add(item);
}
public void MarkAsDeleted() => Deleted = true;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.CartAggregate;
[ValueObject<Guid>]
public readonly partial struct CartId
{
private static Validation Validate(Guid value)
=> value != Guid.Empty ? Validation.Ok : Validation.Invalid("CartId must set to non-default value.");
}
[ValueObject<int>]
public readonly partial struct TestId { }
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItem.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.CartAggregate;
public class CartItem : EntityBase<CartItem, CartItemId>
{
// Private constructor for EF Core
private CartItem() { }
public CartItem(int productId, int quantity, decimal unitPrice)
{
ProductId = productId;
Quantity = quantity;
UnitPrice = unitPrice;
}
public int ProductId { get; private set; }
public int Quantity { get; private set; }
public decimal UnitPrice { get; private set; }
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItemId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.CartAggregate;
[ValueObject<Guid>]
public readonly partial struct CartItemId
{
private static Validation Validate(Guid value)
=> value != Guid.Empty ? Validation.Ok : Validation.Invalid("CartItemId must set to non-default value.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Specifications/CartByIdSpec.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications;
public class CartByIdSpec : Specification<Cart>
{
public CartByIdSpec(CartId cartId) =>
Query
.Include(c => c.Items)
.Where(cart => cart.Id == cartId && !cart.Deleted);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUser.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
public class GuestUser : EntityBase<GuestUser, GuestUserId>, IAggregateRoot
{
public GuestUser(GuestUserId id, string email)
{
Id = id;
Email = email;
}
public string Email { get; private set; }
public GuestUser UpdateEmail(string newEmail)
{
Email = newEmail;
return this;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUserId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
[ValueObject<Guid>]
public readonly partial struct GuestUserId
{
private static Validation Validate(Guid value)
=> value != Guid.Empty ? Validation.Ok : Validation.Invalid("GuestUserId cannot be empty.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByEmailSpec.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications;
public class GuestUserByEmailSpec : Specification<GuestUser>
{
public GuestUserByEmailSpec(string email) =>
Query.Where(g => g.Email == email);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByIdSpec.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications;
public class GuestUserByIdSpec : Specification<GuestUser>
{
public GuestUserByIdSpec(GuestUserId guestUserId) =>
Query.Where(g => g.Id == guestUserId);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/Interfaces/IEmailSender.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.Interfaces;
public interface IEmailSender
{
Task SendEmailAsync(string to, string from, string subject, string body);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Order.cs
================================================
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using MinimalClean.Architecture.Web.Infrastructure.Data;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
public class Order : EntityBase<Order, OrderId>, IAggregateRoot
{
private readonly List<OrderItem> _items = new();
public Order(OrderId id, Guid guestUserId)
{
Id = id;
GuestUserId = guestUserId;
}
public DateTimeOffset CreatedOn { get; private set; } = DateTimeOffset.UtcNow;
public Guid GuestUserId { get; private set; }
public DateTimeOffset? DatePaid { get; private set; }
public string PaymentReference { get; private set; } = string.Empty;
public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();
public decimal Total => _items.Sum(i => i.UnitPrice.Value * i.Quantity.Value);
public void AddItem(ProductId productId, Quantity quantity, Price unitPrice)
{
var item = new OrderItem(Id, productId, quantity, unitPrice);
if(Items.Any(i => i.ProductId == productId))
{
var existingItem = Items.First(i => i.ProductId == productId);
existingItem.IncreaseQuantity(quantity);
return;
}
_items.Add(item);
}
public void ConfirmPayment(DateTimeOffset datePaid, string paymentReference)
{
DatePaid = datePaid;
PaymentReference = paymentReference;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
[ValueObject<Guid>]
public readonly partial struct OrderId
{
private static Validation Validate(Guid value)
=> value != Guid.Empty ? Validation.Ok : Validation.Invalid("OrderId cannot be empty.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItem.cs
================================================
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
public class OrderItem(OrderId orderId, ProductId productId, Quantity quantity, Price unitPrice)
: EntityBase<OrderItem, OrderItemId>
{
public OrderId OrderId { get; private set; } = orderId;
public ProductId ProductId { get; private set; } = productId;
public Quantity Quantity { get; private set; } = quantity;
public Price UnitPrice { get; private set; } = unitPrice;
internal void IncreaseQuantity(Quantity quantity) => Quantity += quantity;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItemId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
[ValueObject<Guid>]
public readonly partial struct OrderItemId
{
private static Validation Validate(Guid value)
=> value != Guid.Empty ? Validation.Ok : Validation.Invalid("OrderItemId cannot be empty.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Price.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
[ValueObject<decimal>]
public readonly partial struct Price
{
private static Validation Validate(decimal value)
=> value > 0 ? Validation.Ok : Validation.Invalid("Price must be greater than zero.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Quantity.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.OrderAggregate;
[ValueObject<int>]
public readonly partial struct Quantity
{
private static Validation Validate(int value)
=> value > 0 ? Validation.Ok : Validation.Invalid("Quantity must be greater than zero.");
public static Quantity operator +(Quantity left, Quantity right) => From(left.Value + right.Value);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Product.cs
================================================
using Ardalis.GuardClauses;
namespace MinimalClean.Architecture.Web.Domain.ProductAggregate;
public class Product : EntityBase<Product, ProductId>, IAggregateRoot
{
// Private constructor for EF Core
private Product() { }
public Product(ProductId id, string name, decimal unitPrice)
{
Guard.Against.InvalidInput(id, nameof(id), (id) => id == ProductId.New,
"Use Product.Create() to create new products instead of passing ProductId.New to the constructor.");
Id = id;
Name = name;
UnitPrice = unitPrice;
}
// Factory method for creating new products (before persistence)
public static Product Create(string name, decimal unitPrice) => new Product(ProductId.New, name, unitPrice);
public string Name { get; private set; } = string.Empty;
public decimal UnitPrice { get; private set; }
public Product UpdateName(string newName)
{
Name = newName;
return this;
}
public Product UpdatePrice(decimal newPrice)
{
UnitPrice = newPrice;
return this;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/ProductId.cs
================================================
using Vogen;
namespace MinimalClean.Architecture.Web.Domain.ProductAggregate;
[ValueObject<int>]
public readonly partial struct ProductId
{
/// <summary>
/// Represents a new Product that has not yet been persisted to the database.
/// EF Core will assign the actual identity value on SaveChanges.
/// </summary>
public static ProductId New => From(0);
private static Validation Validate(int value)
=> value >= 0 ? Validation.Ok : Validation.Invalid("ProductId must be non-negative.");
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Specifications/ProductByIdSpec.cs
================================================
namespace MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications;
public class ProductByIdSpec : Specification<Product>
{
public ProductByIdSpec(ProductId productId) =>
Query
.Where(product => product.Id == productId);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Extensions/ResultExtensions.cs
================================================
using Microsoft.AspNetCore.Http.HttpResults;
namespace MinimalClean.Architecture.Web.Extensions;
public static class ResultExtensions
{
/// <summary>
/// Maps Result to TypedResults for endpoints that return Created, ValidationProblem, or ProblemHttpResult
/// </summary>
public static Results<Created<TResponse>, ValidationProblem, ProblemHttpResult> ToCreatedResult<TValue, TResponse>(
this Result<TValue> result,
Func<TValue, string> locationBuilder,
Func<TValue, TResponse> mapResponse)
{
return result.Status switch
{
ResultStatus.Ok => TypedResults.Created(locationBuilder(result.Value), mapResponse(result.Value)),
ResultStatus.Invalid => TypedResults.ValidationProblem(
result.ValidationErrors
.GroupBy(e => e.Identifier ?? string.Empty)
.ToDictionary(
g => g.Key,
g => g.Select(e => e.ErrorMessage).ToArray()
)
),
_ => TypedResults.Problem(
title: "Create failed",
detail: string.Join("; ", result.Errors),
statusCode: StatusCodes.Status400BadRequest)
};
}
/// <summary>
/// Maps Result to TypedResults for GetById endpoints that return Ok, NotFound, or ProblemHttpResult
/// </summary>
public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToGetByIdResult<TValue, TResponse>(
this Result<TValue> result,
Func<TValue, TResponse> mapResponse) => ToOkOrNotFoundResult(result, mapResponse, "Get");
/// <summary>
/// Maps Result to TypedResults for Update endpoints that return Ok, NotFound, or ProblemHttpResult
/// </summary>
public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToUpdateResult<TValue, TResponse>(
this Result<TValue> result,
Func<TValue, TResponse> mapResponse) => ToOkOrNotFoundResult(result, mapResponse, "Update");
/// <summary>
/// Maps Result to TypedResults for Delete endpoints that return NoContent, NotFound, or ProblemHttpResult
/// </summary>
public static Results<NoContent, NotFound, ProblemHttpResult> ToDeleteResult(
this Result result) => result.Status switch
{
ResultStatus.Ok => TypedResults.NoContent(),
ResultStatus.NotFound => TypedResults.NotFound(),
_ => TypedResults.Problem(
title: "Delete failed",
detail: string.Join("; ", result.Errors),
statusCode: StatusCodes.Status400BadRequest)
};
/// <summary>
/// Private helper method for Ok/NotFound result patterns
/// </summary>
private static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToOkOrNotFoundResult<TValue, TResponse>(
Result<TValue> result,
Func<TValue, TResponse> mapResponse,
string operationName) => result.Status switch
{
ResultStatus.Ok => TypedResults.Ok(mapResponse(result.Value)),
ResultStatus.NotFound => TypedResults.NotFound(),
_ => TypedResults.Problem(
title: $"{operationName} failed",
detail: string.Join("; ", result.Errors),
statusCode: StatusCodes.Status400BadRequest)
};
/// <summary>
/// Maps Result to TypedResults for endpoints that return Ok only (like List endpoints)
/// </summary>
public static Ok<TResponse> ToOkOnlyResult<TValue, TResponse>(
this Result<TValue> result,
Func<TValue, TResponse> mapResponse) => TypedResults.Ok(mapResponse(result.Value));
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/GlobalUsings.cs
================================================
global using Mediator;
global using Ardalis.Result;
global using Ardalis.Specification;
global using Ardalis.SharedKernel;
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContext.cs
================================================
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
using MinimalClean.Architecture.Web.Domain.OrderAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
public class AppDbContext(DbContextOptions<AppDbContext> options) :
DbContext(options)
{
public DbSet<Product> Products => Set<Product>();
public DbSet<Cart> Carts => Set<Cart>();
public DbSet<CartItem> CartItems => Set<CartItem>();
public DbSet<GuestUser> GuestUsers => Set<GuestUser>();
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
public override int SaveChanges() =>
SaveChangesAsync().GetAwaiter().GetResult();
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextExtensions.cs
================================================
using Microsoft.EntityFrameworkCore;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
public static class AppDbContextExtensions
{
public static void AddApplicationDbContext(this IServiceCollection services, string connectionString) =>
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextFactory.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
/// <summary>
/// Design-time factory for creating DbContext instances for EF Core tools.
/// This is ONLY used when CREATING migrations (e.g., 'dotnet ef migrations add').
/// It is NOT used at runtime - Aspire handles the runtime connection.
///
/// Migrations are automatically APPLIED at runtime via MigrateAsync() in MiddlewareConfig.cs.
///
/// To create migrations with SQL Server, set an environment variable:
/// PowerShell: $env:ConnectionStrings__AppDb = "Server=localhost,1433;Database=AppDb;User ID=sa;Password=YourPassword;TrustServerCertificate=true"
/// Bash: export ConnectionStrings__AppDb="Server=localhost,1433;Database=AppDb;User ID=sa;Password=YourPassword;TrustServerCertificate=true"
///
/// Always uses SQL Server for migrations.
/// </summary>
public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
// Try to get connection string from environment variable (ASP.NET Core format)
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__AppDb")
?? "Server=localhost,1433;Database=AppDb_Design;User ID=sa;Password=Your$tr0ngP@ss!;TrustServerCertificate=true"; // Default SQL Server connection for design-time
optionsBuilder.UseSqlServer(connectionString);
return new AppDbContext(optionsBuilder.Options);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.CartAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class CartConfiguration : IEntityTypeConfiguration<Cart>
{
public void Configure(EntityTypeBuilder<Cart> builder)
{
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenGuidIdValueGenerator<AppDbContext, Cart, CartId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(entity => entity.CreatedOn)
.IsRequired();
builder.Property(entity => entity.Deleted)
.IsRequired();
// CartItems relationship
builder.HasMany(c => c.Items);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartItemConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.CartAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class CartItemConfiguration : IEntityTypeConfiguration<CartItem>
{
public void Configure(EntityTypeBuilder<CartItem> builder)
{
builder.ToTable("CartItems");
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenGuidIdValueGenerator<AppDbContext, CartItem, CartItemId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(ci => ci.ProductId)
.IsRequired();
builder.Property(ci => ci.Quantity)
.IsRequired();
builder.Property(ci => ci.UnitPrice)
.HasPrecision(18, 2)
.IsRequired();
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/DataSchemaConstants.cs
================================================
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public static class DataSchemaConstants
{
public const int DEFAULT_NAME_LENGTH = 100;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/GuestUserConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class GuestUserConfiguration : IEntityTypeConfiguration<GuestUser>
{
public void Configure(EntityTypeBuilder<GuestUser> builder)
{
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenGuidIdValueGenerator<AppDbContext, GuestUser, GuestUserId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(entity => entity.Email)
.HasMaxLength(DataSchemaConstants.DEFAULT_NAME_LENGTH)
.IsRequired();
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.OrderAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenGuidIdValueGenerator<AppDbContext, Order, OrderId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(entity => entity.CreatedOn)
.IsRequired();
builder.Property(entity => entity.GuestUserId)
.IsRequired();
builder.Property(entity => entity.DatePaid)
.IsRequired(false);
builder.Property(entity => entity.PaymentReference)
.HasMaxLength(DataSchemaConstants.DEFAULT_NAME_LENGTH)
.IsRequired(false);
// OrderItems relationship
builder.HasMany(o => o.Items);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderItemConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.OrderAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class OrderItemConfiguration : IEntityTypeConfiguration<OrderItem>
{
public void Configure(EntityTypeBuilder<OrderItem> builder)
{
ArgumentNullException.ThrowIfNull(builder);
builder.ToTable("OrderItems");
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenGuidIdValueGenerator<AppDbContext, OrderItem, OrderItemId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(oi => oi.OrderId)
.HasVogenConversion()
.IsRequired();
builder.Property(oi => oi.ProductId)
.HasVogenConversion()
.IsRequired();
builder.Property(oi => oi.Quantity)
.HasVogenConversion()
.IsRequired();
builder.Property(oi => oi.UnitPrice)
.HasVogenConversion()
.HasPrecision(18, 2)
.IsRequired();
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/ProductConfiguration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.Property(entity => entity.Id)
.HasValueGenerator<VogenIntIdValueGenerator<AppDbContext, Product, ProductId>>()
.HasVogenConversion()
.IsRequired();
builder.Property(entity => entity.Name)
.HasMaxLength(100)
.IsRequired();
builder.Property(entity => entity.UnitPrice)
.HasPrecision(18, 2)
.IsRequired();
builder.HasData(
new Product(
ProductId.From(1),
"Coffee Mug",
9.99m),
new Product(
ProductId.From(2),
"T-Shirt",
19.99m),
new Product(
ProductId.From(3),
"Sticker Pack",
3.99m)
);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenEfCoreConverters.cs
================================================
using MinimalClean.Architecture.Web.Domain.CartAggregate;
using MinimalClean.Architecture.Web.Domain.GuestUserAggregate;
using MinimalClean.Architecture.Web.Domain.OrderAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using Vogen;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
[EfCoreConverter<ProductId>]
[EfCoreConverter<CartId>]
[EfCoreConverter<CartItemId>]
[EfCoreConverter<GuestUserId>]
[EfCoreConverter<OrderId>]
[EfCoreConverter<OrderItemId>]
[EfCoreConverter<Quantity>]
[EfCoreConverter<Price>]
internal partial class VogenEfCoreConverters;
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenGuidIdValueGenerator.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ValueGeneration;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
internal class VogenGuidIdValueGenerator<TContext, TEntityBase, TId> : ValueGenerator<TId>
where TContext : DbContext
where TEntityBase : EntityBase<TEntityBase, TId>
where TId : struct
{
public override TId Next(EntityEntry entry)
{
// Use reflection to call the static From method on the value object
var fromMethod = typeof(TId).GetMethod("From", new[] { typeof(Guid) });
if (fromMethod == null)
{
throw new InvalidOperationException($"Type {typeof(TId).Name} does not have a From(Guid) method");
}
return (TId)fromMethod.Invoke(null, new object[] { Guid.NewGuid() })!;
}
public override bool GeneratesTemporaryValues => false;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenIntIdValueGenerator.cs
================================================
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ValueGeneration;
using Vogen;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;
internal class VogenIntIdValueGenerator<TContext, TEntityBase, TId> : ValueGenerator<TId>
where TContext : DbContext
where TEntityBase : EntityBase<TEntityBase, TId>
where TId : IVogen<TId, int>
{
private readonly PropertyInfo _matchPropertyGetter;
public VogenIntIdValueGenerator()
{
var matchingProperties =
typeof(TContext).GetProperties()
.Where(p => p.GetGetMethod()!.IsPublic && p.PropertyType == typeof(DbSet<TEntityBase>))
.ToList();
if (matchingProperties.Count == 0)
{
throw new InvalidOperationException($"No properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}");
}
if (matchingProperties.Count > 1)
{
throw new InvalidOperationException($"Multiple properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}");
}
_matchPropertyGetter = matchingProperties[0];
}
public override TId Next(EntityEntry entry)
{
TContext ctx = (TContext)entry.Context;
DbSet<TEntityBase> entities = (DbSet<TEntityBase>)_matchPropertyGetter.GetValue(ctx)!;
var next = Math.Max(
MaxFrom(entities.Local),
MaxFrom(entities)) + 1;
return TId.From(next);
}
private static int MaxFrom(IEnumerable<TEntityBase> es)
{
if (!es.Any()) return 0;
return es.Max(e => e.Id.Value);
}
public override bool GeneratesTemporaryValues => false;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EfRepository.cs
================================================
using Ardalis.Specification.EntityFrameworkCore;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
// inherit from Ardalis.Specification type
public class EfRepository<T>(AppDbContext dbContext) :
RepositoryBase<T>(dbContext), IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EventDispatcherInterceptor.cs
================================================
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
// Intercepts SaveChanges to dispatch domain events after changes are successfully saved
public class EventDispatchInterceptor(IDomainEventDispatcher domainEventDispatcher) : SaveChangesInterceptor
{
private readonly IDomainEventDispatcher _domainEventDispatcher = domainEventDispatcher;
// Called after SaveChangesAsync has completed successfully
public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result,
CancellationToken cancellationToken = new CancellationToken())
{
var context = eventData.Context;
if (context is not AppDbContext appDbContext)
{
return await base.SavedChangesAsync(eventData, result, cancellationToken).ConfigureAwait(false);
}
// Retrieve all tracked entities that have domain events
var entitiesWithEvents = appDbContext.ChangeTracker.Entries<HasDomainEventsBase>()
.Select(e => e.Entity)
.Where(e => e.DomainEvents.Any())
.ToArray();
// Dispatch and clear domain events
await _domainEventDispatcher.DispatchAndClearEvents(entitiesWithEvents);
return await base.SavedChangesAsync(eventData, result, cancellationToken);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.Designer.cs
================================================
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MinimalClean.Architecture.Web.Infrastructure.Data;
#nullable disable
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20251020223304_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedOn")
.HasColumnType("datetime2");
b.Property<bool>("Deleted")
.HasColumnType("bit");
b.HasKey("Id");
b.ToTable("Carts");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("CartId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("CartId");
b.ToTable("CartItems", (string)null);
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.ToTable("Products");
b.HasData(
new
{
Id = 1,
Name = "Laptop",
UnitPrice = 999.99m
},
new
{
Id = 2,
Name = "Smartphone",
UnitPrice = 499.99m
},
new
{
Id = 3,
Name = "Tablet",
UnitPrice = 299.99m
});
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null)
.WithMany("Items")
.HasForeignKey("CartId");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Navigation("Items");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Carts",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreatedOn = table.Column<DateTime>(type: "datetime2", nullable: false),
Deleted = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Carts", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CartItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ProductId = table.Column<int>(type: "int", nullable: false),
Quantity = table.Column<int>(type: "int", nullable: false),
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
CartId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CartItems", x => x.Id);
table.ForeignKey(
name: "FK_CartItems_Carts_CartId",
column: x => x.CartId,
principalTable: "Carts",
principalColumn: "Id");
});
migrationBuilder.InsertData(
table: "Products",
columns: new[] { "Id", "Name", "UnitPrice" },
values: new object[,]
{
{ 1, "Laptop", 999.99m },
{ 2, "Smartphone", 499.99m },
{ 3, "Tablet", 299.99m }
});
migrationBuilder.CreateIndex(
name: "IX_CartItems_CartId",
table: "CartItems",
column: "CartId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CartItems");
migrationBuilder.DropTable(
name: "Products");
migrationBuilder.DropTable(
name: "Carts");
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs
================================================
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MinimalClean.Architecture.Web.Infrastructure.Data;
#nullable disable
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20251024232246_AddGuestUsersAndOrdersSqlServer")]
partial class AddGuestUsersAndOrdersSqlServer
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedOn")
.HasColumnType("datetime2");
b.Property<bool>("Deleted")
.HasColumnType("bit");
b.HasKey("Id");
b.ToTable("Carts");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("CartId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("CartId");
b.ToTable("CartItems", (string)null);
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.GuestUserAggregate.GuestUser", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.ToTable("GuestUsers");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("DatePaid")
.HasColumnType("datetimeoffset");
b.Property<Guid>("GuestUserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("PaymentReference")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.ToTable("Orders");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("OrderItems", (string)null);
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.ToTable("Products");
b.HasData(
new
{
Id = 1,
Name = "Coffee Mug",
UnitPrice = 9.99m
},
new
{
Id = 2,
Name = "T-Shirt",
UnitPrice = 19.99m
},
new
{
Id = 3,
Name = "Sticker Pack",
UnitPrice = 3.99m
});
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null)
.WithMany("Items")
.HasForeignKey("CartId");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b =>
{
b.HasOne("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", null)
.WithMany("Items")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b =>
{
b.Navigation("Items");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations
{
/// <inheritdoc />
public partial class AddGuestUsersAndOrdersSqlServer : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "GuestUsers",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Email = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_GuestUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Orders",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreatedOn = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false),
GuestUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
DatePaid = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
PaymentReference = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Orders", x => x.Id);
});
migrationBuilder.CreateTable(
name: "OrderItems",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ProductId = table.Column<int>(type: "int", nullable: false),
Quantity = table.Column<int>(type: "int", nullable: false),
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrderItems", x => x.Id);
table.ForeignKey(
name: "FK_OrderItems_Orders_OrderId",
column: x => x.OrderId,
principalTable: "Orders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 1,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "Coffee Mug", 9.99m });
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 2,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "T-Shirt", 19.99m });
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 3,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "Sticker Pack", 3.99m });
migrationBuilder.CreateIndex(
name: "IX_OrderItems_OrderId",
table: "OrderItems",
column: "OrderId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "GuestUsers");
migrationBuilder.DropTable(
name: "OrderItems");
migrationBuilder.DropTable(
name: "Orders");
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 1,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "Laptop", 999.99m });
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 2,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "Smartphone", 499.99m });
migrationBuilder.UpdateData(
table: "Products",
keyColumn: "Id",
keyValue: 3,
columns: new[] { "Name", "UnitPrice" },
values: new object[] { "Tablet", 299.99m });
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/AppDbContextModelSnapshot.cs
================================================
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MinimalClean.Architecture.Web.Infrastructure.Data;
#nullable disable
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations
{
[DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedOn")
.HasColumnType("datetime2");
b.Property<bool>("Deleted")
.HasColumnType("bit");
b.HasKey("Id");
b.ToTable("Carts");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("CartId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("CartId");
b.ToTable("CartItems", (string)null);
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.GuestUserAggregate.GuestUser", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.ToTable("GuestUsers");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("DatePaid")
.HasColumnType("datetimeoffset");
b.Property<Guid>("GuestUserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("PaymentReference")
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.ToTable("Orders");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("OrderItems", (string)null);
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b =>
{
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<decimal>("UnitPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.ToTable("Products");
b.HasData(
new
{
Id = 1,
Name = "Coffee Mug",
UnitPrice = 9.99m
},
new
{
Id = 2,
Name = "T-Shirt",
UnitPrice = 19.99m
},
new
{
Id = 3,
Name = "Sticker Pack",
UnitPrice = 3.99m
});
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b =>
{
b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null)
.WithMany("Items")
.HasForeignKey("CartId");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b =>
{
b.HasOne("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", null)
.WithMany("Items")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b =>
{
b.Navigation("Items");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Queries/ListProductsQueryService.cs
================================================
using Microsoft.EntityFrameworkCore;
using MinimalClean.Architecture.Web.ProductFeatures;
using MinimalClean.Architecture.Web.ProductFeatures.List;
namespace MinimalClean.Architecture.Web.Infrastructure.Data.Queries;
public class ListProductsQueryService(AppDbContext db) : IListProductsQueryService
{
private readonly AppDbContext _db = db;
public async Task<PagedResult<ProductDto>> ListAsync(int page, int perPage)
{
var items = await _db.Products
.OrderBy(p => p.Id)
.Skip((page - 1) * perPage)
.Take(perPage)
.Select(p => new ProductDto(p.Id, p.Name, p.UnitPrice))
.AsNoTracking()
.ToListAsync();
int totalCount = await _db.Products.CountAsync();
int totalPages = (int)Math.Ceiling(totalCount / (double)perPage);
var result = new PagedResult<ProductDto>(items, page, perPage, totalCount, totalPages);
return result;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/SeedData.cs
================================================
using Microsoft.EntityFrameworkCore;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using Microsoft.Extensions.Logging;
namespace MinimalClean.Architecture.Web.Infrastructure.Data;
public static class SeedData
{
public const int NUMBER_OF_PRODUCTS = 10;
public static async Task InitializeAsync(AppDbContext dbContext, ILogger logger)
{
if (await dbContext.Products.AnyAsync())
{
logger.LogInformation("DB has data - seeding not required.");
return; // DB has been seeded
}
await PopulateTestDataAsync(dbContext, logger);
}
public static async Task PopulateTestDataAsync(AppDbContext dbContext, ILogger logger)
{
logger.LogInformation("Seeding database with sample data.");
// add more products to support demonstrating paging
for (int i = 1; i <= NUMBER_OF_PRODUCTS; i++)
{
dbContext.Products.Add(new Product(ProductId.From(i), $"Product {i}", 10m + i));
}
await dbContext.SaveChangesAsync();
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/FakeEmailSender.cs
================================================
using MinimalClean.Architecture.Web.Domain.Interfaces;
namespace MinimalClean.Architecture.Web.Infrastructure.Email;
public class FakeEmailSender(ILogger<FakeEmailSender> logger) : IEmailSender
{
private readonly ILogger<FakeEmailSender> _logger = logger;
public Task SendEmailAsync(string to, string from, string subject, string body)
{
_logger.LogInformation("Not actually sending an email to {to} from {from} with subject {subject}", to, from, subject);
return Task.CompletedTask;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MailserverConfiguration.cs
================================================
namespace MinimalClean.Architecture.Web.Infrastructure.Email;
public class MailserverConfiguration()
{
public string Hostname { get; set; } = "localhost";
public int Port { get; set; } = 25;
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MimeKitEmailSender.cs
================================================
using Microsoft.Extensions.Options;
using MimeKit;
using MinimalClean.Architecture.Web.Domain.Interfaces;
namespace MinimalClean.Architecture.Web.Infrastructure.Email;
public class MimeKitEmailSender(ILogger<MimeKitEmailSender> logger,
IOptions<MailserverConfiguration> mailserverOptions) : IEmailSender
{
private readonly ILogger<MimeKitEmailSender> _logger = logger;
private readonly MailserverConfiguration _mailserverConfiguration = mailserverOptions.Value!;
public async Task SendEmailAsync(string to, string from, string subject, string body)
{
_logger.LogWarning("Sending email to {to} from {from} with subject {subject} using {type}.", to, from, subject, this.ToString());
using var client = new MailKit.Net.Smtp.SmtpClient();
await client.ConnectAsync(_mailserverConfiguration.Hostname,
_mailserverConfiguration.Port, false);
var message = new MimeMessage();
message.From.Add(new MailboxAddress(from, from));
message.To.Add(new MailboxAddress(to, to));
message.Subject = subject;
message.Body = new TextPart("plain") { Text = body };
await client.SendAsync(message);
await client.DisconnectAsync(true,
new CancellationToken(canceled: true));
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/InfrastructureServiceExtensions.cs
================================================
using Ardalis.GuardClauses;
using MinimalClean.Architecture.Web.Infrastructure.Data;
using MinimalClean.Architecture.Web.Infrastructure.Data.Queries;
using MinimalClean.Architecture.Web.ProductFeatures.List;
using Microsoft.EntityFrameworkCore;
namespace MinimalClean.Architecture.Web.Infrastructure;
public static class InfrastructureServiceExtensions
{
public static IServiceCollection AddInfrastructureServices(
this IServiceCollection services,
ConfigurationManager config,
ILogger logger)
{
// Always use SQL Server from Aspire
string? connectionString = config.GetConnectionString("AppDb");
Guard.Against.Null(connectionString, "AppDb connection string is required. Make sure the application is running with Aspire.");
services.AddScoped<EventDispatchInterceptor>();
services.AddScoped<IDomainEventDispatcher, MediatorDomainEventDispatcher>();
services.AddDbContext<AppDbContext>((provider, options) =>
{
var eventDispatchInterceptor = provider.GetRequiredService<EventDispatchInterceptor>();
options.UseSqlServer(connectionString);
options.AddInterceptors(eventDispatchInterceptor);
});
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>))
.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>))
.AddScoped<IListProductsQueryService, ListProductsQueryService>();
logger.LogInformation("{Project} services registered", "Infrastructure");
return services;
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/MinimalClean.Architecture.Web.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">
<Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />
<PropertyGroup>
<PreserveCompilationContext>true</PreserveCompilationContext>
<OutputType>Exe</OutputType>
<WebProjectMode>true</WebProjectMode>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<RootNamespace>MinimalClean.Architecture.Web</RootNamespace>
<WarningsAsErrors>NSDEPCOP01</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" />
<PackageReference Include="Ardalis.Result" />
<PackageReference Include="Ardalis.ListStartupServices" />
<PackageReference Include="Ardalis.Result.AspNetCore" />
<PackageReference Include="Ardalis.SharedKernel" />
<PackageReference Include="Ardalis.SmartEnum" />
<PackageReference Include="Ardalis.Specification" />
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="FastEndpoints" />
<PackageReference Include="FastEndpoints.Swagger" />
<PackageReference Include="Mediator.Abstractions" />
<PackageReference Include="Mediator.SourceGenerator">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MailKit" />
<PackageReference Include="MimeKit" />
<PackageReference Include="NimblePros.Metronome" />
<PackageReference Include="Scalar.AspNetCore" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Sinks.OpenTelemetry" />
<PackageReference Include="Vogen">
<IncludeAssets>compile; runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all">
<IncludeAssets>runtime; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NsDepCop">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MinimalClean.Architecture.ServiceDefaults\MinimalClean.Architecture.ServiceDefaults.csproj" />
</ItemGroup>
</Project>
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/PagedResult.cs
================================================
namespace MinimalClean.Architecture.Web;
public record PagedResult<T>(
IReadOnlyList<T> Items,
int Page,
int PerPage,
int TotalCount,
int TotalPages);
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/Create/CreateEndpoint.cs
================================================
using FastEndpoints;
using FluentValidation;
using Microsoft.AspNetCore.Http.HttpResults;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using MinimalClean.Architecture.Web.ProductFeatures;
namespace MinimalClean.Architecture.Web.ProductFeatures.Create;
public sealed class CreateProductRequest
{
public string Name { get; init; } = string.Empty;
public decimal UnitPrice { get; init; }
}
public class CreateEndpoint(IRepository<Product> repository) :
Endpoint<CreateProductRequest,
Results<Created<ProductRecord>, ValidationProblem, ProblemHttpResult>>
{
private readonly IRepository<Product> _repository = repository;
public override void Configure()
{
Post("/Products");
AllowAnonymous();
Summary(s =>
{
s.Summary = "Create a new product";
s.Description = "Creates a new product with the specified name and unit price.";
s.ExampleRequest = new CreateProductRequest { Name = "Sample Product", UnitPrice = 19.99m };
s.ResponseExamples[201] = new ProductRecord(1, "Sample Product", 19.99m);
s.Responses[201] = "Product created successfully";
s.Responses[400] = "Invalid request data";
});
Tags("Products");
Description(builder => builder
.Accepts<CreateProductRequest>()
.Produces<ProductRecord>(201, "application/json")
.ProducesProblem(400));
}
public override async Task<Results<Created<ProductRecord>, ValidationProblem, ProblemHttpResult>>
ExecuteAsync(CreateProductRequest request, CancellationToken cancellationToken)
{
var product = Product.Create(request.Name, request.UnitPrice);
await _repository.AddAsync(product, cancellationToken);
await _repository.SaveChangesAsync(cancellationToken);
var response = new ProductRecord(product.Id.Value, product.Name, product.UnitPrice);
return TypedResults.Created($"/Products/{product.Id.Value}", response);
}
}
public sealed class CreateProductValidator : Validator<CreateProductRequest>
{
public CreateProductValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.WithMessage("Product name is required")
.MaximumLength(200)
.WithMessage("Product name must not exceed 200 characters");
RuleFor(x => x.UnitPrice)
.GreaterThan(0)
.WithMessage("Unit price must be greater than zero");
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetByIdEndpoint.cs
================================================
using FastEndpoints;
using FluentValidation;
using Microsoft.AspNetCore.Http.HttpResults;
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using MinimalClean.Architecture.Web.Extensions;
namespace MinimalClean.Architecture.Web.ProductFeatures.GetById;
public sealed class GetProductByIdRequest
{
public const string Route = "/Products/{ProductId}";
public int ProductId { get; init; }
}
public class GetByIdEndpoint(IMediator mediator)
: Endpoint<GetProductByIdRequest,
Results<Ok<ProductRecord>,
NotFound,
ProblemHttpResult>,
GetProductByIdMapper>
{
public override void Configure()
{
Get(GetProductByIdRequest.Route);
AllowAnonymous();
Summary(s =>
{
s.Summary = "Get a product by ID";
s.Description = "Retrieves a specific product by its unique identifier. Returns detailed product information including ID, name, and unit price.";
s.ExampleRequest = new GetProductByIdRequest { ProductId = 1 };
s.ResponseExamples[200] = new ProductRecord(1, "Laptop", 999.99m);
// Document possible responses
s.Responses[200] = "Product found and returned successfully";
s.Responses[404] = "Product with specified ID not found";
});
// Add tags for API grouping
Tags("Products");
// Add additional metadata
Description(builder => builder
.Accepts<GetProductByIdRequest>()
.Produces<ProductRecord>(200, "application/json")
.ProducesProblem(404));
}
public override async Task<Results<Ok<ProductRecord>, NotFound, ProblemHttpResult>>
ExecuteAsync(GetProductByIdRequest request, CancellationToken ct)
{
var result = await mediator.Send(new GetProductQuery(ProductId.From(request.ProductId)), ct);
return result.ToGetByIdResult(Map.FromEntity);
}
}
public sealed class GetProductByIdValidator : Validator<GetProductByIdRequest>
{
public GetProductByIdValidator()
{
RuleFor(x => x.ProductId)
.GreaterThan(0)
.WithMessage("Product ID must be greater than 0");
}
}
public sealed class GetProductByIdMapper
: Mapper<GetProductByIdRequest, ProductRecord, ProductDto>
{
public override ProductRecord FromEntity(ProductDto e)
=> new(e.Id.Value, e.Name, e.UnitPrice);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetProductHandler.cs
================================================
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
using MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications;
namespace MinimalClean.Architecture.Web.ProductFeatures.GetById;
public record GetProductQuery(ProductId ProductId) : IQuery<Result<ProductDto>>;
public class GetProductHandler(IReadRepository<Product> _repository)
: IQueryHandler<GetProductQuery, Result<ProductDto>>
{
public async ValueTask<Result<ProductDto>> Handle(GetProductQuery request, CancellationToken cancellationToken)
{
var spec = new ProductByIdSpec(request.ProductId);
var entity = await _repository.FirstOrDefaultAsync(spec, cancellationToken);
if (entity == null) return Result.NotFound();
return new ProductDto(entity.Id, entity.Name, entity.UnitPrice);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/IListProductsQueryService.cs
================================================
namespace MinimalClean.Architecture.Web.ProductFeatures.List;
/// <summary>
/// Represents a service that will actually fetch the necessary data
/// Typically implemented in Infrastructure
/// </summary>
public interface IListProductsQueryService
{
Task<PagedResult<ProductDto>> ListAsync(int page, int perPage);
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListEndpoint.cs
================================================
using FastEndpoints;
using FluentValidation;
using MinimalClean.Architecture.Web.ProductFeatures;
namespace MinimalClean.Architecture.Web.ProductFeatures.List;
public sealed class ListProductsRequest
{
[BindFrom("page")]
public int Page { get; init; } = 1;
[BindFrom("per_page")]
public int PerPage { get; init; } = Constants.DEFAULT_PAGE_SIZE;
}
public record ProductListResponse : PagedResult<ProductRecord>
{
public ProductListResponse(IReadOnlyList<ProductRecord> Items, int Page, int PerPage, int TotalCount, int TotalPages)
: base(Items, Page, PerPage, TotalCount, TotalPages)
{
}
}
public class ListEndpoint(IMediator mediator) : Endpoint<ListProductsRequest, ProductListResponse, ListProductsMapper>
{
private readonly IMediator _mediator = mediator;
public override void Configure()
{
Get("/Products");
AllowAnonymous();
Summary(s =>
{
s.Summary = "List products with pagination";
s.Description = "Retrieves a paginated list of all products. Supports GitHub-style pagination with 1-based page indexing and configurable page size.";
s.ExampleRequest = new ListProductsRequest { Page = 1, PerPage = 10 };
s.ResponseExamples[200] = new ProductListResponse(
new List<ProductRecord>
{
new(1, "Sample Product 1", 9.99m),
new(2, "Sample Product 2", 19.99m)
},
1, 10, 2, 1);
s.Params["page"] = "1-based page index (default 1)";
s.Params["per_page"] = $"Page size 1–{Constants.MAX_PAGE_SIZE} (default {Constants.DEFAULT_PAGE_SIZE})";
s.Responses[200] = "Paginated list of products returned successfully";
s.Responses[400] = "Invalid pagination parameters";
});
Tags("Products");
Description(builder => builder
.Accepts<ListProductsRequest>()
.Produces<ProductListResponse>(200, "application/json")
.ProducesProblem(400));
}
public override async Task HandleAsync(ListProductsRequest request, CancellationToken cancellationToken)
{
var result = await _mediator.Send(new ListProductsQuery(request.Page, request.PerPage));
if (!result.IsSuccess)
{
await Send.ErrorsAsync(statusCode: 400, cancellationToken);
return;
}
var pagedResult = result.Value;
AddLinkHeader(pagedResult.Page, pagedResult.PerPage, pagedResult.TotalPages);
var response = Map.FromEntity(pagedResult);
await Send.OkAsync(response, cancellationToken);
}
private void AddLinkHeader(int page, int perPage, int totalPages)
{
var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}";
string Link(string rel, int p) => $"<{baseUrl}?page={p}&per_page={perPage}>; rel=\"{rel}\"";
var parts = new List<string>();
if (page > 1)
{
parts.Add(Link("first", 1));
parts.Add(Link("prev", page - 1));
}
if (page < totalPages)
{
parts.Add(Link("next", page + 1));
parts.Add(Link("last", totalPages));
}
if (parts.Count > 0)
HttpContext.Response.Headers["Link"] = string.Join(", ", parts);
}
}
public sealed class ListProductsValidator : Validator<ListProductsRequest>
{
public ListProductsValidator()
{
RuleFor(x => x.Page)
.GreaterThanOrEqualTo(1)
.WithMessage("page must be >= 1");
RuleFor(x => x.PerPage)
.InclusiveBetween(1, Constants.MAX_PAGE_SIZE)
.WithMessage($"per_page must be between 1 and {Constants.MAX_PAGE_SIZE}");
}
}
public sealed class ListProductsMapper
: Mapper<ListProductsRequest, ProductListResponse, PagedResult<ProductDto>>
{
public override ProductListResponse FromEntity(PagedResult<ProductDto> e)
{
var items = e.Items
.Select(p => new ProductRecord(p.Id.Value, p.Name, p.UnitPrice))
.ToList();
return new ProductListResponse(items, e.Page, e.PerPage, e.TotalCount, e.TotalPages);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListProductsHandler.cs
================================================
namespace MinimalClean.Architecture.Web.ProductFeatures.List;
public record ListProductsQuery(int? Page = 1,
int? PerPage = Constants.DEFAULT_PAGE_SIZE)
: IQuery<Result<PagedResult<ProductDto>>>;
public class ListProductsHandler(IListProductsQueryService query) : IQueryHandler<ListProductsQuery, Result<PagedResult<ProductDto>>>
{
private readonly IListProductsQueryService _query = query;
public async ValueTask<Result<PagedResult<ProductDto>>> Handle(ListProductsQuery request,
CancellationToken cancellationToken)
{
var result = await _query.ListAsync(request.Page ?? 1, request.PerPage ?? Constants.DEFAULT_PAGE_SIZE);
return Result.Success(result);
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductDto.cs
================================================
using MinimalClean.Architecture.Web.Domain.ProductAggregate;
namespace MinimalClean.Architecture.Web.ProductFeatures;
public record ProductDto(ProductId Id, string Name, decimal UnitPrice);
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductRecord.cs
================================================
namespace MinimalClean.Architecture.Web.ProductFeatures;
public record ProductRecord(int Id, string Name, decimal UnitPrice);
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Program.cs
================================================
using FastEndpoints;
using FastEndpoints.Swagger;
using MinimalClean.Architecture.Web.Configurations;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults() // This sets up OpenTelemetry logging
.AddLoggerConfigs(); // This adds Serilog for console formatting
using var loggerFactory = LoggerFactory.Create(config => config.AddConsole());
var startupLogger = loggerFactory.CreateLogger<Program>();
startupLogger.LogInformation("Starting web host");
builder.Services.AddOptionConfigs(builder.Configuration, startupLogger, builder);
builder.Services.AddServiceConfigs(startupLogger, builder);
builder.Services.AddFastEndpoints()
.SwaggerDocument(o =>
{
o.ShortSchemaNames = true;
});
var app = builder.Build();
await app.UseAppMiddlewareAndSeedDatabase();
app.MapDefaultEndpoints(); // Aspire health checks and metrics
app.Run();
// Make the implicit Program.cs class public, so integration tests can reference the correct assembly for host building
public partial class Program { }
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Properties/launchSettings.json
================================================
{
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchUrl": "scalar",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:57379/"
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/api.http
================================================
@MinimalClean_HostAddress = https://localhost:57379
@MinimalClean_CartId = 68fe4cfd-84bb-4b8a-bb4e-528c26325c72
### List Products
GET {{MinimalClean_HostAddress}}/products
Accept: application/json
### Get Product By ID
GET {{MinimalClean_HostAddress}}/products/1
Accept: application/json
### Create Product
POST {{MinimalClean_HostAddress}}/products
Content-Type: application/json
{
"name": "New Product",
"unitPrice": 29.99
}
### Add to Cart (Anonymous User - creates cart)
POST {{MinimalClean_HostAddress}}/cart
Content-Type: application/json
{
"productId": 1,
"quantity": 2
}
### Add to Cart (Anonymous User - existing cart)
POST {{MinimalClean_HostAddress}}/cart
Content-Type: application/json
{
"cartId": "{{MinimalClean_CartId}}",
"productId": 2,
"quantity": 3
}
### View Cart
GET {{MinimalClean_HostAddress}}/cart/{{MinimalClean_CartId}}
Accept: application/json
### Checkout
POST {{MinimalClean_HostAddress}}/cart/{{MinimalClean_CartId}}/checkout
Content-Type: application/json
{
"email": "guest@example.com"
}
### Note: Get order ID from response for future use
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/appsettings.Development.json
================================================
{
"DatabaseOptions": {
"RecreateOnStartup": true
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/appsettings.json
================================================
{
"ConnectionStrings": {
"AppDb": "Server=(localdb)\\mssqllocaldb;Database=MinimalCleanArchitecture;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore": "Warning",
"System": "Warning"
}
},
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
}
}
]
},
"Mailserver": {
"Server": "localhost",
"Port": 25
}
}
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/config.nsdepcop
================================================
<?xml version="1.0" encoding="utf-8"?>
<NsDepCopConfig>
<Allowed From="*" To="*" />
<Disallowed From="MinimalClean.Architecture.Web.Domain.*"
To="MinimalClean.Architecture.Web.Infrastructure.*" />
<Disallowed From="MinimalClean.Architecture.Web.CartFeatures.*"
To="MinimalClean.Architecture.Web.Infrastructure.*" />
<Disallowed From="MinimalClean.Architecture.Web.ProductFeatures.*"
To="MinimalClean.Architecture.Web.Infrastructure.*" />
<Disallowed From="MinimalClean.Architecture.Web.Domain.OrderAggregate.*"
To="MinimalClean.Architecture.Web.Domain.CartAggregate.*" />
<AnalyzerConfig>
<IssueKind Name="IllegalDependency" Severity="Error" />
</AnalyzerConfig>
</NsDepCopConfig>
================================================
FILE: MinimalClean/src/MinimalClean.Architecture.Web/wwwroot/.gitkeep
================================================
================================================
FILE: MinimalClean.nuspec
================================================
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Ardalis.MinimalClean.Template</id>
<title>ASP.NET Minimal Clean Architecture Solution</title>
<version>1.0.1</version>
<authors>Steve Smith</authors>
<description>
A simplified Clean Architecture template using vertical slice architecture in a single project.
Perfect for MVPs, smaller applications, or teams wanting architectural guidance without multi-project complexity.
Features Domain-Driven Design patterns, FastEndpoints, Entity Framework Core, and optional Aspire support.
Built with .NET 10 and C#.
</description>
<language>en-US</language>
<license type="expression">MIT</license>
<projectUrl>https://github.com/ardalis/CleanArchitecture</projectUrl>
<releaseNotes>
* Initial release of Minimal Clean Architecture template
* Single-project vertical slice architecture
* Built with .NET 10 and C#.
* FastEndpoints for REPR pattern
* Pragmatic DDD with simplified patterns
* Aspire support
* 1.0.1 fixes a minor bug
</releaseNotes>
<packageTypes>
<packageType name="Template" />
</packageTypes>
<tags>Web ASP.NET "Clean Architecture" "Vertical Slice" minimal ddd domain-driven-design clean-architecture ardalis FastEndpoints</tags>
<icon>./content/icon.png</icon>
<readme>README.md</readme>
</metadata>
<files>
<file src="MinimalClean\**" target="content" exclude="**\bin\**;**\obj\**;**\.git\**;**\.vs\**;**\.vscode\**;**\*.user" />
<file src="README.md" />
<file src="icon.png" target="content" />
</files>
</package>
================================================
FILE: PARALLEL_TEST_EXECUTION.md
================================================
# Parallel Test Execution Configuration
This workspace is configured to run all three test projects in parallel in Visual Studio Test Explorer.
## Configuration Files
### `.runsettings` (Solution Root)
- Enables parallel test execution at the assembly level
- `MaxCpuCount=0` uses all available processors to run test assemblies in parallel
- `DisableParallelization=false` ensures parallelization is enabled
### `xunit.runner.json` (In Each Test Project)
Each test project contains an `xunit.runner.json` file with:
- `parallelizeAssembly: true` - Allows tests from this assembly to run in parallel with other assemblies
- `parallelizeTestCollections: true` - Runs test collections within the assembly in parallel
- `maxParallelThreads: 0` - Uses xUnit's default algorithm (processors 2)
## How to Use in Visual Studio
### Option 1: Configure via Test Explorer Settings
1. Open **Test Explorer** (Test ? Test Explorer)
2. Click the settings icon (??) in the toolbar
gitextract_pjis_cnn/
├── .aspire/
│ └── settings.json
├── .editorconfig
├── .github/
│ ├── CONTRIBUTING.md
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-ramdisk.yml
│ ├── codeql-analysis.yml
│ ├── dotnetcore.yml
│ ├── publish-templates.yml
│ └── publish.yml
├── .gitignore
├── .runsettings
├── .template.config/
│ └── template.json
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Clean.Architecture.slnx
├── CleanArchitecture.nuspec
├── Directory.Build.props
├── Directory.Packages.props
├── LICENSE
├── MinimalClean/
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .runsettings
│ ├── .template.config/
│ │ └── template.json
│ ├── Directory.Build.props
│ ├── Directory.Packages.props
│ ├── MinimalClean.Architecture.slnx
│ ├── README.template.md
│ ├── global.json
│ └── src/
│ ├── MinimalClean.Architecture.AspireHost/
│ │ ├── AppHost.cs
│ │ ├── MinimalClean.Architecture.AspireHost.csproj
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
│ ├── MinimalClean.Architecture.ServiceDefaults/
│ │ ├── Extensions.cs
│ │ └── MinimalClean.Architecture.ServiceDefaults.csproj
│ └── MinimalClean.Architecture.Web/
│ ├── AssemblyInfo.cs
│ ├── CartFeatures/
│ │ ├── AddToCart/
│ │ │ ├── AddToCartEndpoint.cs
│ │ │ └── AddToCartHandler.cs
│ │ ├── CartDto.cs
│ │ ├── CartResponse.cs
│ │ ├── Checkout/
│ │ │ ├── CheckoutEndpoint.cs
│ │ │ └── CheckoutHandler.cs
│ │ └── GetById/
│ │ ├── GetByIdEndpoint.cs
│ │ └── GetCartHandler.cs
│ ├── Configurations/
│ │ ├── DatabaseOptions.cs
│ │ ├── LoggerConfigs.cs
│ │ ├── LoggingBehavior.cs
│ │ ├── MediatorConfig.cs
│ │ ├── MiddlewareConfig.cs
│ │ ├── OptionConfigs.cs
│ │ └── ServiceConfigs.cs
│ ├── Constants.cs
│ ├── Domain/
│ │ ├── CartAggregate/
│ │ │ ├── Cart.cs
│ │ │ ├── CartId.cs
│ │ │ ├── CartItem.cs
│ │ │ ├── CartItemId.cs
│ │ │ └── Specifications/
│ │ │ └── CartByIdSpec.cs
│ │ ├── GuestUserAggregate/
│ │ │ ├── GuestUser.cs
│ │ │ ├── GuestUserId.cs
│ │ │ └── Specifications/
│ │ │ ├── GuestUserByEmailSpec.cs
│ │ │ └── GuestUserByIdSpec.cs
│ │ ├── Interfaces/
│ │ │ └── IEmailSender.cs
│ │ ├── OrderAggregate/
│ │ │ ├── Order.cs
│ │ │ ├── OrderId.cs
│ │ │ ├── OrderItem.cs
│ │ │ ├── OrderItemId.cs
│ │ │ ├── Price.cs
│ │ │ └── Quantity.cs
│ │ └── ProductAggregate/
│ │ ├── Product.cs
│ │ ├── ProductId.cs
│ │ └── Specifications/
│ │ └── ProductByIdSpec.cs
│ ├── Extensions/
│ │ └── ResultExtensions.cs
│ ├── GlobalUsings.cs
│ ├── Infrastructure/
│ │ ├── Data/
│ │ │ ├── AppDbContext.cs
│ │ │ ├── AppDbContextExtensions.cs
│ │ │ ├── AppDbContextFactory.cs
│ │ │ ├── Config/
│ │ │ │ ├── CartConfiguration.cs
│ │ │ │ ├── CartItemConfiguration.cs
│ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ ├── GuestUserConfiguration.cs
│ │ │ │ ├── OrderConfiguration.cs
│ │ │ │ ├── OrderItemConfiguration.cs
│ │ │ │ ├── ProductConfiguration.cs
│ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ ├── VogenGuidIdValueGenerator.cs
│ │ │ │ └── VogenIntIdValueGenerator.cs
│ │ │ ├── EfRepository.cs
│ │ │ ├── EventDispatcherInterceptor.cs
│ │ │ ├── Migrations/
│ │ │ │ ├── 20251020223304_Initial.Designer.cs
│ │ │ │ ├── 20251020223304_Initial.cs
│ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs
│ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.cs
│ │ │ │ └── AppDbContextModelSnapshot.cs
│ │ │ ├── Queries/
│ │ │ │ └── ListProductsQueryService.cs
│ │ │ └── SeedData.cs
│ │ ├── Email/
│ │ │ ├── FakeEmailSender.cs
│ │ │ ├── MailserverConfiguration.cs
│ │ │ └── MimeKitEmailSender.cs
│ │ └── InfrastructureServiceExtensions.cs
│ ├── MinimalClean.Architecture.Web.csproj
│ ├── PagedResult.cs
│ ├── ProductFeatures/
│ │ ├── Create/
│ │ │ └── CreateEndpoint.cs
│ │ ├── GetById/
│ │ │ ├── GetByIdEndpoint.cs
│ │ │ └── GetProductHandler.cs
│ │ ├── List/
│ │ │ ├── IListProductsQueryService.cs
│ │ │ ├── ListEndpoint.cs
│ │ │ └── ListProductsHandler.cs
│ │ ├── ProductDto.cs
│ │ └── ProductRecord.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── api.http
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── config.nsdepcop
│ └── wwwroot/
│ └── .gitkeep
├── MinimalClean.nuspec
├── PARALLEL_TEST_EXECUTION.md
├── README.md
├── README.template.md
├── TESTCONTAINERS_IMPLEMENTATION.md
├── docs/
│ ├── architecture-decisions/
│ │ ├── README.md
│ │ └── adr-001-dotnet-di-adoption.md
│ └── minimal-clean-architecture.md
├── global.json
├── nuget.config
├── sample/
│ ├── .editorconfig
│ ├── .github/
│ │ └── copilot-instructions.md
│ ├── .runsettings
│ ├── Directory.Build.props
│ ├── Directory.Packages.props
│ ├── NimblePros.SampleToDo.slnx
│ ├── src/
│ │ ├── NimblePros.SampleToDo.AspireHost/
│ │ │ ├── NimblePros.SampleToDo.AspireHost.csproj
│ │ │ ├── Program.cs
│ │ │ ├── Properties/
│ │ │ │ └── launchSettings.json
│ │ │ ├── appsettings.Development.json
│ │ │ └── appsettings.json
│ │ ├── NimblePros.SampleToDo.Core/
│ │ │ ├── ContributorAggregate/
│ │ │ │ ├── Contributor.cs
│ │ │ │ ├── ContributorId.cs
│ │ │ │ ├── ContributorName.cs
│ │ │ │ ├── Events/
│ │ │ │ │ ├── ContributorDeletedEvent.cs
│ │ │ │ │ └── ContributorNameUpdatedEvent.cs
│ │ │ │ ├── Handlers/
│ │ │ │ │ ├── ContributorDeletedHandler.cs
│ │ │ │ │ └── ContributorNameUpdatedEventLoggingHandler.cs
│ │ │ │ └── Specifications/
│ │ │ │ └── ContributorByIdSpec.cs
│ │ │ ├── CoreServiceExtensions.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── Interfaces/
│ │ │ │ ├── IDeleteContributorService.cs
│ │ │ │ ├── IEmailSender.cs
│ │ │ │ └── IToDoItemSearchService.cs
│ │ │ ├── Localization.cs
│ │ │ ├── NimblePros.SampleToDo.Core.csproj
│ │ │ ├── ProjectAggregate/
│ │ │ │ ├── Events/
│ │ │ │ │ ├── ContributorAddedToItemEvent.cs
│ │ │ │ │ ├── NewItemAddedEvent.cs
│ │ │ │ │ └── ToDoItemCompletedEvent.cs
│ │ │ │ ├── Handlers/
│ │ │ │ │ ├── ContributorAddedToItemLoggingHandler.cs
│ │ │ │ │ ├── ItemCompletedEmailNotificationHandler.cs
│ │ │ │ │ └── NewItemAddedLoggingHandler.cs
│ │ │ │ ├── Priority.cs
│ │ │ │ ├── Project.cs
│ │ │ │ ├── ProjectErrorMessages.cs
│ │ │ │ ├── ProjectId.cs
│ │ │ │ ├── ProjectName.cs
│ │ │ │ ├── ProjectStatus.cs
│ │ │ │ ├── Specifications/
│ │ │ │ │ ├── IncompleteItemsSearchSpec.cs
│ │ │ │ │ ├── IncompleteItemsSpec.cs
│ │ │ │ │ ├── ProjectByIdWithItemsSpec.cs
│ │ │ │ │ └── ProjectsWithItemsByContributorId.cs
│ │ │ │ ├── ToDoItem.cs
│ │ │ │ ├── ToDoItemDescription.cs
│ │ │ │ ├── ToDoItemId.cs
│ │ │ │ └── ToDoItemTitle.cs
│ │ │ └── Services/
│ │ │ ├── DeleteContributorService.cs
│ │ │ └── ToDoItemSearchService.cs
│ │ ├── NimblePros.SampleToDo.Infrastructure/
│ │ │ ├── Data/
│ │ │ │ ├── AppDbContext.cs
│ │ │ │ ├── Config/
│ │ │ │ │ ├── ContributorConfiguration.cs
│ │ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ │ ├── ProjectConfiguration.cs
│ │ │ │ │ ├── ToDoItemConfiguration.cs
│ │ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ │ └── VogenIdValueGenerator.cs
│ │ │ │ ├── EfRepository.cs
│ │ │ │ ├── EventDispatchInterceptor.cs
│ │ │ │ └── Queries/
│ │ │ │ ├── FakeListContributorsQueryService.cs
│ │ │ │ ├── FakeListIncompleteItemsQueryService.cs
│ │ │ │ ├── FakeListProjectsShallowQueryService.cs
│ │ │ │ ├── ListContributorsQueryService.cs
│ │ │ │ ├── ListIncompleteItemsQueryService.cs
│ │ │ │ └── ListProjectsShallowQueryService.cs
│ │ │ ├── Email/
│ │ │ │ ├── FakeEmailSender.cs
│ │ │ │ ├── MailserverConfiguration.cs
│ │ │ │ ├── MimeKitEmailSender.cs
│ │ │ │ └── SmtpEmailSender.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── InfrastructureServiceExtensions.cs
│ │ │ └── NimblePros.SampleToDo.Infrastructure.csproj
│ │ ├── NimblePros.SampleToDo.ServiceDefaults/
│ │ │ ├── Extensions.cs
│ │ │ └── NimblePros.SampleToDo.ServiceDefaults.csproj
│ │ ├── NimblePros.SampleToDo.UseCases/
│ │ │ ├── Constants.cs
│ │ │ ├── Contributors/
│ │ │ │ ├── Commands/
│ │ │ │ │ ├── Create/
│ │ │ │ │ │ ├── CreateContributorCommand.cs
│ │ │ │ │ │ └── CreateContributorHandler.cs
│ │ │ │ │ ├── Delete/
│ │ │ │ │ │ ├── DeleteContributorCommand.cs
│ │ │ │ │ │ └── DeleteContributorHandler.cs
│ │ │ │ │ └── Update/
│ │ │ │ │ ├── UpdateContributorCommand.cs
│ │ │ │ │ └── UpdateContributorHandler.cs
│ │ │ │ ├── ContributorDTO.cs
│ │ │ │ └── Queries/
│ │ │ │ ├── Get/
│ │ │ │ │ ├── GetContributorHandler.cs
│ │ │ │ │ └── GetContributorQuery.cs
│ │ │ │ └── List/
│ │ │ │ ├── IListContributorsQueryService.cs
│ │ │ │ ├── ListContributorsHandler.cs
│ │ │ │ └── ListContributorsQuery.cs
│ │ │ ├── GlobalUsings.cs
│ │ │ ├── ICacheable.cs
│ │ │ ├── NimblePros.SampleToDo.UseCases.csproj
│ │ │ ├── PagedResult.cs
│ │ │ ├── Projects/
│ │ │ │ ├── AddToDoItem/
│ │ │ │ │ ├── AddToDoItemCommand.cs
│ │ │ │ │ └── AddToDoItemHandler.cs
│ │ │ │ ├── Create/
│ │ │ │ │ ├── CreateProjectCommand.cs
│ │ │ │ │ └── CreateProjectHandler.cs
│ │ │ │ ├── Delete/
│ │ │ │ │ ├── DeleteProjectCommand.cs
│ │ │ │ │ └── DeleteProjectHandler.cs
│ │ │ │ ├── GetWithAllItems/
│ │ │ │ │ ├── GetProjectWithAllItemsHandler.cs
│ │ │ │ │ └── GetProjectWithAllItemsQuery.cs
│ │ │ │ ├── ListIncompleteItems/
│ │ │ │ │ ├── IListIncompleteItemsQueryService.cs
│ │ │ │ │ ├── ListIncompleteItemsByProjectHandler.cs
│ │ │ │ │ └── ListIncompleteItemsByProjectQuery.cs
│ │ │ │ ├── ListShallow/
│ │ │ │ │ ├── IListProjectsShallowQueryService.cs
│ │ │ │ │ ├── ListProjectsShallowHandler.cs
│ │ │ │ │ └── ListProjectsShallowQuery.cs
│ │ │ │ ├── MarkToDoItemComplete/
│ │ │ │ │ ├── MarkToDoItemCompleteCommand.cs
│ │ │ │ │ └── MarkToDoItemCompleteHandler.cs
│ │ │ │ ├── ProjectDTO.cs
│ │ │ │ ├── ProjectWithAllItemsDTO.cs
│ │ │ │ ├── ToDoItemDTO.cs
│ │ │ │ └── Update/
│ │ │ │ ├── UpdateProjectCommand.cs
│ │ │ │ └── UpdateProjectHandler.cs
│ │ │ └── README.md
│ │ └── NimblePros.SampleToDo.Web/
│ │ ├── CachingBehavior.cs
│ │ ├── Configurations/
│ │ │ ├── CachingOptions.cs
│ │ │ ├── CachingProfile.cs
│ │ │ ├── GlobalExceptionHandler.cs
│ │ │ ├── LoggerConfig.cs
│ │ │ ├── MediatorConfig.cs
│ │ │ ├── MiddlewareConfig.cs
│ │ │ ├── OptionConfigs.cs
│ │ │ └── ServiceConfigs.cs
│ │ ├── Contributors/
│ │ │ ├── ContributorRecord.cs
│ │ │ ├── Create.cs
│ │ │ ├── Delete.DeleteContributorRequest.cs
│ │ │ ├── Delete.DeleteContributorValidator.cs
│ │ │ ├── Delete.cs
│ │ │ ├── GetById.GetContributorByIdMapper.cs
│ │ │ ├── GetById.GetContributorByIdRequest.cs
│ │ │ ├── GetById.GetContributorValidator.cs
│ │ │ ├── GetById.cs
│ │ │ ├── List.ContributorListResponse.cs
│ │ │ ├── List.cs
│ │ │ ├── Update.UpdateContributorRequest.cs
│ │ │ ├── Update.UpdateContributorResponse.cs
│ │ │ ├── Update.UpdateContributorValidator.cs
│ │ │ └── Update.cs
│ │ ├── Extensions/
│ │ │ └── ResultExtensions.cs
│ │ ├── GlobalUsings.cs
│ │ ├── LoggingBehavior.cs
│ │ ├── NimblePros.SampleToDo.Web.csproj
│ │ ├── Program.cs
│ │ ├── Projects/
│ │ │ ├── Create.CreateProjectRequest.cs
│ │ │ ├── Create.CreateProjectResponse.cs
│ │ │ ├── Create.CreateProjectValidator.cs
│ │ │ ├── Create.cs
│ │ │ ├── CreateToDoItem.CreateToDoItemRequest.cs
│ │ │ ├── CreateToDoItem.CreateToDoItemValidator.cs
│ │ │ ├── CreateToDoItem.cs
│ │ │ ├── Delete.DeleteProjectRequest.cs
│ │ │ ├── Delete.DeleteProjectValidator.cs
│ │ │ ├── Delete.cs
│ │ │ ├── GetById.GetProjectByIdRequest.cs
│ │ │ ├── GetById.GetProjectByIdResponse.cs
│ │ │ ├── GetById.GetProjectByIdValidator.cs
│ │ │ ├── GetById.cs
│ │ │ ├── List.ProjectListResponse.cs
│ │ │ ├── List.cs
│ │ │ ├── ListIncompleteItems.ListIncompleteItemsRequest.cs
│ │ │ ├── ListIncompleteItems.ListIncompleteItemsResponse.cs
│ │ │ ├── ListIncompleteItems.cs
│ │ │ ├── MarkItemComplete.MarkItemCompleteRequest.cs
│ │ │ ├── MarkItemComplete.cs
│ │ │ ├── ProjectRecord.cs
│ │ │ ├── ToDoItemRecord.cs
│ │ │ ├── Update.UpdateProjectRequest.cs
│ │ │ ├── Update.UpdateProjectRequestValidator.cs
│ │ │ ├── Update.UpdateProjectResponse.cs
│ │ │ └── Update.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── SeedData.cs
│ │ ├── api.http
│ │ ├── appsettings.json
│ │ ├── i18n/
│ │ │ ├── en/
│ │ │ │ └── Project.json
│ │ │ ├── fa/
│ │ │ │ └── Project.json
│ │ │ └── fr/
│ │ │ └── Project.json
│ │ └── wwwroot/
│ │ ├── css/
│ │ │ └── site.css
│ │ ├── js/
│ │ │ └── site.js
│ │ └── lib/
│ │ ├── bootstrap/
│ │ │ ├── LICENSE
│ │ │ └── dist/
│ │ │ ├── css/
│ │ │ │ ├── bootstrap-grid.css
│ │ │ │ ├── bootstrap-grid.rtl.css
│ │ │ │ ├── bootstrap-reboot.css
│ │ │ │ ├── bootstrap-reboot.rtl.css
│ │ │ │ ├── bootstrap-utilities.css
│ │ │ │ ├── bootstrap-utilities.rtl.css
│ │ │ │ ├── bootstrap.css
│ │ │ │ └── bootstrap.rtl.css
│ │ │ └── js/
│ │ │ ├── bootstrap.bundle.js
│ │ │ ├── bootstrap.esm.js
│ │ │ └── bootstrap.js
│ │ ├── jquery/
│ │ │ ├── LICENSE.txt
│ │ │ └── dist/
│ │ │ └── jquery.js
│ │ ├── jquery-validation/
│ │ │ ├── LICENSE.md
│ │ │ └── dist/
│ │ │ ├── additional-methods.js
│ │ │ └── jquery.validate.js
│ │ └── jquery-validation-unobtrusive/
│ │ ├── LICENSE.txt
│ │ └── jquery.validate.unobtrusive.js
│ └── tests/
│ ├── NimblePros.SampleToDo.FunctionalTests/
│ │ ├── Contributors/
│ │ │ ├── ContributorCreate.cs
│ │ │ ├── ContributorDelete.cs
│ │ │ ├── ContributorGetById.cs
│ │ │ ├── ContributorList.cs
│ │ │ └── ContributorUpdate.cs
│ │ ├── CustomWebApplicationFactory.cs
│ │ ├── Fixtures/
│ │ │ └── SmtpServerFixture.cs
│ │ ├── GlobalUsings.cs
│ │ ├── NimblePros.SampleToDo.FunctionalTests.csproj
│ │ ├── Projects/
│ │ │ ├── CreateToDoItemRequestBuilder.cs
│ │ │ ├── ProjectAddToDoItem.cs
│ │ │ ├── ProjectCreate.cs
│ │ │ ├── ProjectGetById.cs
│ │ │ ├── ProjectItemMarkComplete.cs
│ │ │ └── ProjectList.cs
│ │ ├── TestBase.cs
│ │ └── xunit.runner.json
│ ├── NimblePros.SampleToDo.IntegrationTests/
│ │ ├── Data/
│ │ │ ├── BaseEfRepoTestFixture.cs
│ │ │ ├── EfRepositoryAdd.cs
│ │ │ ├── EfRepositoryDelete.cs
│ │ │ └── EfRepositoryUpdate.cs
│ │ ├── GlobalUsings.cs
│ │ └── NimblePros.SampleToDo.IntegrationTests.csproj
│ └── NimblePros.SampleToDo.UnitTests/
│ ├── Core/
│ │ ├── ContributorAggregate/
│ │ │ ├── ContributorConstructor.cs
│ │ │ └── ContributorIdFrom.cs
│ │ ├── Handlers/
│ │ │ └── ItemCompletedEmailNotificationHandlerHandle.cs
│ │ ├── ProjectAggregate/
│ │ │ ├── ProjectConstructor.cs
│ │ │ ├── ProjectNameFrom.cs
│ │ │ ├── Project_AddItem.cs
│ │ │ ├── ToDoItemConstructor.cs
│ │ │ └── ToDoItemMarkComplete.cs
│ │ ├── Services/
│ │ │ ├── DeleteContributorSevice_DeleteContributor.cs
│ │ │ ├── ToDoItemSearchServiceTests.cs
│ │ │ ├── ToDoItemSearchService_GetAllIncompleteItems.cs
│ │ │ └── ToDoItemSearchService_GetNextIncompleteItem.cs
│ │ └── Specifications/
│ │ └── IncompleteItemSpecificationsConstructor.cs
│ ├── GlobalUsings.cs
│ ├── NimblePros.SampleToDo.UnitTests.csproj
│ ├── NoOpMediator.cs
│ ├── ToDoItemBuilder.cs
│ ├── UseCases/
│ │ └── Contributors/
│ │ ├── CreateContributorHandlerHandle.cs
│ │ ├── GetContributorHandlerHandle.cs
│ │ └── UpdateContributorHandlerHandle.cs
│ └── xunit.runner.json
├── src/
│ ├── Clean.Architecture.AspireHost/
│ │ ├── AppHost.cs
│ │ ├── Clean.Architecture.AspireHost.csproj
│ │ ├── GlobalUsings.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── README.md
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
│ ├── Clean.Architecture.Core/
│ │ ├── Clean.Architecture.Core.csproj
│ │ ├── Clean.Architecture.Core.sln
│ │ ├── ContributorAggregate/
│ │ │ ├── Contributor.cs
│ │ │ ├── ContributorId.cs
│ │ │ ├── ContributorName.cs
│ │ │ ├── ContributorStatus.cs
│ │ │ ├── Events/
│ │ │ │ ├── ContributorDeletedEvent.cs
│ │ │ │ └── ContributorNameUpdatedEvent.cs
│ │ │ ├── Handlers/
│ │ │ │ ├── ContributorDeletedHandler.cs
│ │ │ │ └── ContributorNameUpdatedEmailNotificationHandler.cs
│ │ │ ├── PhoneNumber.cs
│ │ │ └── Specifications/
│ │ │ └── ContributorByIdSpec.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Interfaces/
│ │ │ ├── IDeleteContributorService.cs
│ │ │ └── IEmailSender.cs
│ │ ├── README.md
│ │ └── Services/
│ │ └── DeleteContributorService.cs
│ ├── Clean.Architecture.Infrastructure/
│ │ ├── Clean.Architecture.Infrastructure.csproj
│ │ ├── Data/
│ │ │ ├── AppDbContext.cs
│ │ │ ├── AppDbContextExtensions.cs
│ │ │ ├── Config/
│ │ │ │ ├── ContributorConfiguration.cs
│ │ │ │ ├── DataSchemaConstants.cs
│ │ │ │ ├── VogenEfCoreConverters.cs
│ │ │ │ └── VogenIdValueGenerator.cs
│ │ │ ├── EfRepository.cs
│ │ │ ├── EventDispatcherInterceptor.cs
│ │ │ ├── Migrations/
│ │ │ │ ├── 20231218143922_PhoneNumber.Designer.cs
│ │ │ │ ├── 20231218143922_PhoneNumber.cs
│ │ │ │ ├── 20251113164108_UpdateForNet10.Designer.cs
│ │ │ │ ├── 20251113164108_UpdateForNet10.cs
│ │ │ │ └── AppDbContextModelSnapshot.cs
│ │ │ ├── Queries/
│ │ │ │ ├── FakeListContributorsQueryService.cs
│ │ │ │ └── ListContributorsQueryService.cs
│ │ │ └── SeedData.cs
│ │ ├── Email/
│ │ │ ├── FakeEmailSender.cs
│ │ │ ├── MailserverConfiguration.cs
│ │ │ └── MimeKitEmailSender.cs
│ │ ├── GlobalUsings.cs
│ │ ├── InfrastructureServiceExtensions.cs
│ │ └── README.md
│ ├── Clean.Architecture.ServiceDefaults/
│ │ ├── Clean.Architecture.ServiceDefaults.csproj
│ │ └── Extensions.cs
│ ├── Clean.Architecture.UseCases/
│ │ ├── Clean.Architecture.UseCases.csproj
│ │ ├── Constants.cs
│ │ ├── Contributors/
│ │ │ ├── ContributorDTO.cs
│ │ │ ├── Create/
│ │ │ │ ├── CreateContributorCommand.cs
│ │ │ │ └── CreateContributorHandler.cs
│ │ │ ├── Delete/
│ │ │ │ ├── DeleteContributorCommand.cs
│ │ │ │ └── DeleteContributorHandler.cs
│ │ │ ├── Get/
│ │ │ │ ├── GetContributorHandler.cs
│ │ │ │ └── GetContributorQuery.cs
│ │ │ ├── List/
│ │ │ │ ├── IListContributorsQueryService.cs
│ │ │ │ ├── ListContributorsHandler.cs
│ │ │ │ └── ListContributorsQuery.cs
│ │ │ └── Update/
│ │ │ ├── UpdateContributorCommand.cs
│ │ │ └── UpdateContributorHandler.cs
│ │ ├── GlobalUsings.cs
│ │ ├── PagedResult.cs
│ │ └── README.md
│ └── Clean.Architecture.Web/
│ ├── Clean.Architecture.Web.csproj
│ ├── Configurations/
│ │ ├── LoggerConfigs.cs
│ │ ├── MediatorConfig.cs
│ │ ├── MiddlewareConfig.cs
│ │ ├── OptionConfigs.cs
│ │ └── ServiceConfigs.cs
│ ├── Contributors/
│ │ ├── ContributorRecord.cs
│ │ ├── Create.cs
│ │ ├── Delete.DeleteContributorRequest.cs
│ │ ├── Delete.DeleteContributorValidator.cs
│ │ ├── Delete.cs
│ │ ├── GetById.GetContributorByIdRequest.cs
│ │ ├── GetById.GetContributorValidator.cs
│ │ ├── GetById.cs
│ │ ├── List.cs
│ │ ├── Update.UpdateContributorRequest.cs
│ │ ├── Update.UpdateContributorResponse.cs
│ │ ├── Update.UpdateContributorValidator.cs
│ │ └── Update.cs
│ ├── Extensions/
│ │ └── ResultExtensions.cs
│ ├── GlobalUsings.cs
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── api.http
│ ├── appsettings.Development.json
│ ├── appsettings.Testing.json
│ ├── appsettings.json
│ └── wwwroot/
│ └── .gitkeep
└── tests/
├── Clean.Architecture.AspireTests/
│ ├── AspireIntegrationTests.cs
│ └── Clean.Architecture.AspireTests.csproj
├── Clean.Architecture.FunctionalTests/
│ ├── ApiEndpoints/
│ │ ├── ContributorGetById.cs
│ │ └── ContributorList.cs
│ ├── Clean.Architecture.FunctionalTests.csproj
│ ├── CustomWebApplicationFactory.cs
│ ├── DockerAvailabilityTests.cs
│ ├── GlobalUsings.cs
│ └── xunit.runner.json
├── Clean.Architecture.IntegrationTests/
│ ├── Clean.Architecture.IntegrationTests.csproj
│ ├── Data/
│ │ ├── BaseEfRepoTestFixture.cs
│ │ ├── EfRepositoryAdd.cs
│ │ ├── EfRepositoryDelete.cs
│ │ └── EfRepositoryUpdate.cs
│ ├── GlobalUsings.cs
│ └── xunit.runner.json
└── Clean.Architecture.UnitTests/
├── Clean.Architecture.UnitTests.csproj
├── Core/
│ ├── ContributorAggregate/
│ │ ├── ContributorConstructor.cs
│ │ ├── ContributorIdFrom.cs
│ │ ├── ContributorNameFrom.cs
│ │ └── ContributorUpdateName.cs
│ └── Services/
│ ├── DeleteContributorSevice_DeleteContributor.cs
│ ├── ToDoItemSearchService_GetAllIncompleteItems.cs
│ └── ToDoItemSearchService_GetNextIncompleteItem.cs
├── GlobalUsings.cs
├── NoOpMediator.cs
├── UseCases/
│ └── Contributors/
│ └── CreateContributorHandlerHandle.cs
└── xunit.runner.json
SYMBOL INDEX (2016 symbols across 345 files)
FILE: MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/Extensions.cs
class Extensions (line 16) | public static class Extensions
method AddServiceDefaults (line 21) | public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder buil...
method ConfigureOpenTelemetry (line 47) | public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder ...
method AddOpenTelemetryExporters (line 81) | private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuil...
method AddDefaultHealthChecks (line 100) | public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder ...
method MapDefaultEndpoints (line 109) | public static WebApplication MapDefaultEndpoints(this WebApplication app)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/AssemblyInfo.cs
class AssemblyInfo (line 7) | public class AssemblyInfo { }
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartEndpoint.cs
class AddToCartRequest (line 7) | public sealed class AddToCartRequest
class AddToCartEndpoint (line 17) | public class AddToCartEndpoint(IMediator mediator)
method Configure (line 25) | public override void Configure()
method ExecuteAsync (line 65) | public override async Task<Results<Ok<CartResponse>, NotFound, Validat...
class AddToCartValidator (line 87) | public sealed class AddToCartValidator : FastEndpoints.Validator<AddToCa...
method AddToCartValidator (line 89) | public AddToCartValidator()
class AddToCartMapper (line 102) | public sealed class AddToCartMapper
method FromEntity (line 105) | public override CartResponse FromEntity(CartDto e)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartHandler.cs
type AddToCartCommand (line 8) | public record AddToCartCommand(CartId? CartId, int ProductId, int Quanti...
class AddToCartHandler (line 10) | public class AddToCartHandler(
method Handle (line 15) | public async ValueTask<Result<CartDto>> Handle(AddToCartCommand reques...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartDto.cs
type CartDto (line 5) | public record CartDto(CartId Id, IReadOnlyList<CartItemDto> Items, decim...
type CartItemDto (line 7) | public record CartItemDto(int ProductId, int Quantity, decimal UnitPrice...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartResponse.cs
type CartResponse (line 3) | public record CartResponse(Guid CartId, IReadOnlyList<CartItemResponse> ...
type CartItemResponse (line 5) | public record CartItemResponse(int ProductId, int Quantity, decimal Unit...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutEndpoint.cs
class CheckoutRequest (line 8) | public sealed class CheckoutRequest
type CheckoutResponse (line 16) | public record CheckoutResponse(Guid OrderId);
class CheckoutEndpoint (line 18) | public class CheckoutEndpoint(IMediator mediator)
method Configure (line 26) | public override void Configure()
method ExecuteAsync (line 60) | public override async Task<Results<Ok<CheckoutResponse>, NotFound, Val...
class CheckoutValidator (line 87) | public sealed class CheckoutValidator : Validator<CheckoutRequest>
method CheckoutValidator (line 89) | public CheckoutValidator()
class CheckoutMapper (line 103) | public sealed class CheckoutMapper
method FromEntity (line 106) | public override CheckoutResponse FromEntity(CheckoutResult e) => new C...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutHandler.cs
type CheckoutCommand (line 10) | public record CheckoutCommand(CartId CartId, string Email) : ICommand<Re...
type CheckoutResult (line 12) | public record CheckoutResult(OrderId OrderId);
class CheckoutHandler (line 14) | public class CheckoutHandler(
method Handle (line 20) | public async ValueTask<Result<CheckoutResult>> Handle(CheckoutCommand ...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetByIdEndpoint.cs
class GetCartRequest (line 8) | public sealed class GetCartRequest
class GetByIdEndpoint (line 15) | public class GetByIdEndpoint(IMediator mediator)
method Configure (line 22) | public override void Configure()
method ExecuteAsync (line 57) | public override async Task<Results<Ok<CartResponse>, NotFound, Problem...
class GetCartMapper (line 68) | public sealed class GetCartMapper
method FromEntity (line 71) | public override CartResponse FromEntity(CartDto e)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetCartHandler.cs
type GetCartQuery (line 6) | public record GetCartQuery(CartId CartId) : IQuery<Result<CartDto>>;
class GetCartHandler (line 7) | public class GetCartHandler(IReadRepository<Domain.CartAggregate.Cart> r...
method Handle (line 10) | public async ValueTask<Result<CartDto>> Handle(GetCartQuery request, C...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/DatabaseOptions.cs
class DatabaseOptions (line 6) | public class DatabaseOptions
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggerConfigs.cs
class LoggerConfigs (line 5) | public static class LoggerConfigs
method AddLoggerConfigs (line 7) | public static WebApplicationBuilder AddLoggerConfigs(this WebApplicati...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggingBehavior.cs
class LoggingBehavior (line 5) | public class LoggingBehavior<TRequest, TResponse>(ILogger<LoggingBehavio...
method Handle (line 10) | public async ValueTask<TResponse> Handle(
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MediatorConfig.cs
class MediatorConfig (line 3) | public static class MediatorConfig
method AddMediatorSourceGen (line 6) | public static IServiceCollection AddMediatorSourceGen(this IServiceCol...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MiddlewareConfig.cs
class MiddlewareConfig (line 11) | public static class MiddlewareConfig
method UseAppMiddlewareAndSeedDatabase (line 13) | public static async Task<IApplicationBuilder> UseAppMiddlewareAndSeedD...
method SeedDatabase (line 44) | static async Task SeedDatabase(WebApplication app)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/OptionConfigs.cs
class OptionConfigs (line 6) | public static class OptionConfigs
method AddOptionConfigs (line 8) | public static IServiceCollection AddOptionConfigs(this IServiceCollect...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/ServiceConfigs.cs
class ServiceConfigs (line 7) | public static class ServiceConfigs
method AddServiceConfigs (line 9) | public static IServiceCollection AddServiceConfigs(this IServiceCollec...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Constants.cs
class Constants (line 3) | public class Constants
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Cart.cs
class Cart (line 3) | public class Cart : EntityBase<Cart, CartId>, IAggregateRoot
method AddItem (line 11) | public void AddItem(int productId, int quantity, decimal unitPrice)
method MarkAsDeleted (line 17) | public void MarkAsDeleted() => Deleted = true;
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartId.cs
type CartId (line 5) | [ValueObject<Guid>]
method Validate (line 8) | private static Validation Validate(Guid value)
type TestId (line 11) | [ValueObject<int>]
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItem.cs
class CartItem (line 3) | public class CartItem : EntityBase<CartItem, CartItemId>
method CartItem (line 6) | private CartItem() { }
method CartItem (line 8) | public CartItem(int productId, int quantity, decimal unitPrice)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItemId.cs
type CartItemId (line 5) | [ValueObject<Guid>]
method Validate (line 8) | private static Validation Validate(Guid value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Specifications/CartByIdSpec.cs
class CartByIdSpec (line 3) | public class CartByIdSpec : Specification<Cart>
method CartByIdSpec (line 5) | public CartByIdSpec(CartId cartId) =>
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUser.cs
class GuestUser (line 3) | public class GuestUser : EntityBase<GuestUser, GuestUserId>, IAggregateRoot
method GuestUser (line 5) | public GuestUser(GuestUserId id, string email)
method UpdateEmail (line 13) | public GuestUser UpdateEmail(string newEmail)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUserId.cs
type GuestUserId (line 5) | [ValueObject<Guid>]
method Validate (line 8) | private static Validation Validate(Guid value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByEmailSpec.cs
class GuestUserByEmailSpec (line 3) | public class GuestUserByEmailSpec : Specification<GuestUser>
method GuestUserByEmailSpec (line 5) | public GuestUserByEmailSpec(string email) =>
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByIdSpec.cs
class GuestUserByIdSpec (line 3) | public class GuestUserByIdSpec : Specification<GuestUser>
method GuestUserByIdSpec (line 5) | public GuestUserByIdSpec(GuestUserId guestUserId) =>
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/Interfaces/IEmailSender.cs
type IEmailSender (line 3) | public interface IEmailSender
method SendEmailAsync (line 5) | Task SendEmailAsync(string to, string from, string subject, string body);
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Order.cs
class Order (line 6) | public class Order : EntityBase<Order, OrderId>, IAggregateRoot
method Order (line 10) | public Order(OrderId id, Guid guestUserId)
method AddItem (line 25) | public void AddItem(ProductId productId, Quantity quantity, Price unit...
method ConfirmPayment (line 38) | public void ConfirmPayment(DateTimeOffset datePaid, string paymentRefe...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderId.cs
type OrderId (line 5) | [ValueObject<Guid>]
method Validate (line 8) | private static Validation Validate(Guid value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItem.cs
class OrderItem (line 6) | public class OrderItem(OrderId orderId, ProductId productId, Quantity qu...
method IncreaseQuantity (line 14) | internal void IncreaseQuantity(Quantity quantity) => Quantity += quant...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItemId.cs
type OrderItemId (line 5) | [ValueObject<Guid>]
method Validate (line 8) | private static Validation Validate(Guid value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Price.cs
type Price (line 5) | [ValueObject<decimal>]
method Validate (line 8) | private static Validation Validate(decimal value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Quantity.cs
type Quantity (line 5) | [ValueObject<int>]
method Validate (line 8) | private static Validation Validate(int value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Product.cs
class Product (line 5) | public class Product : EntityBase<Product, ProductId>, IAggregateRoot
method Product (line 8) | private Product() { }
method Product (line 10) | public Product(ProductId id, string name, decimal unitPrice)
method Create (line 20) | public static Product Create(string name, decimal unitPrice) => new Pr...
method UpdateName (line 25) | public Product UpdateName(string newName)
method UpdatePrice (line 31) | public Product UpdatePrice(decimal newPrice)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/ProductId.cs
type ProductId (line 5) | [ValueObject<int>]
method Validate (line 14) | private static Validation Validate(int value)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Specifications/ProductByIdSpec.cs
class ProductByIdSpec (line 3) | public class ProductByIdSpec : Specification<Product>
method ProductByIdSpec (line 5) | public ProductByIdSpec(ProductId productId) =>
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Extensions/ResultExtensions.cs
class ResultExtensions (line 5) | public static class ResultExtensions
method ToCreatedResult (line 10) | public static Results<Created<TResponse>, ValidationProblem, ProblemHt...
method ToGetByIdResult (line 36) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToGe...
method ToUpdateResult (line 43) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToUp...
method ToDeleteResult (line 50) | public static Results<NoContent, NotFound, ProblemHttpResult> ToDelete...
method ToOkOrNotFoundResult (line 64) | private static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToO...
method ToOkOnlyResult (line 80) | public static Ok<TResponse> ToOkOnlyResult<TValue, TResponse>(
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContext.cs
class AppDbContext (line 9) | public class AppDbContext(DbContextOptions<AppDbContext> options) :
method OnModelCreating (line 19) | protected override void OnModelCreating(ModelBuilder modelBuilder)
method SaveChanges (line 25) | public override int SaveChanges() =>
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextExtensions.cs
class AppDbContextExtensions (line 5) | public static class AppDbContextExtensions
method AddApplicationDbContext (line 7) | public static void AddApplicationDbContext(this IServiceCollection ser...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextFactory.cs
class AppDbContextFactory (line 19) | public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbCont...
method CreateDbContext (line 21) | public AppDbContext CreateDbContext(string[] args)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartConfiguration.cs
class CartConfiguration (line 7) | public class CartConfiguration : IEntityTypeConfiguration<Cart>
method Configure (line 9) | public void Configure(EntityTypeBuilder<Cart> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartItemConfiguration.cs
class CartItemConfiguration (line 7) | public class CartItemConfiguration : IEntityTypeConfiguration<CartItem>
method Configure (line 9) | public void Configure(EntityTypeBuilder<CartItem> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/DataSchemaConstants.cs
class DataSchemaConstants (line 3) | public static class DataSchemaConstants
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/GuestUserConfiguration.cs
class GuestUserConfiguration (line 7) | public class GuestUserConfiguration : IEntityTypeConfiguration<GuestUser>
method Configure (line 9) | public void Configure(EntityTypeBuilder<GuestUser> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderConfiguration.cs
class OrderConfiguration (line 7) | public class OrderConfiguration : IEntityTypeConfiguration<Order>
method Configure (line 9) | public void Configure(EntityTypeBuilder<Order> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderItemConfiguration.cs
class OrderItemConfiguration (line 8) | public class OrderItemConfiguration : IEntityTypeConfiguration<OrderItem>
method Configure (line 10) | public void Configure(EntityTypeBuilder<OrderItem> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/ProductConfiguration.cs
class ProductConfiguration (line 7) | public class ProductConfiguration : IEntityTypeConfiguration<Product>
method Configure (line 9) | public void Configure(EntityTypeBuilder<Product> builder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenGuidIdValueGenerator.cs
class VogenGuidIdValueGenerator (line 7) | internal class VogenGuidIdValueGenerator<TContext, TEntityBase, TId> : V...
method Next (line 12) | public override TId Next(EntityEntry entry)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenIntIdValueGenerator.cs
class VogenIntIdValueGenerator (line 9) | internal class VogenIntIdValueGenerator<TContext, TEntityBase, TId> : Va...
method VogenIntIdValueGenerator (line 16) | public VogenIntIdValueGenerator()
method Next (line 36) | public override TId Next(EntityEntry entry)
method MaxFrom (line 49) | private static int MaxFrom(IEnumerable<TEntityBase> es)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EfRepository.cs
class EfRepository (line 6) | public class EfRepository<T>(AppDbContext dbContext) :
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EventDispatcherInterceptor.cs
class EventDispatchInterceptor (line 6) | public class EventDispatchInterceptor(IDomainEventDispatcher domainEvent...
method SavedChangesAsync (line 11) | public override async ValueTask<int> SavedChangesAsync(SaveChangesComp...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.Designer.cs
class Initial (line 14) | [DbContext(typeof(AppDbContext))]
method BuildTargetModel (line 19) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.cs
class Initial (line 11) | public partial class Initial : Migration
method Up (line 14) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 79) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs
class AddGuestUsersAndOrdersSqlServer (line 14) | [DbContext(typeof(AppDbContext))]
method BuildTargetModel (line 19) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.cs
class AddGuestUsersAndOrdersSqlServer (line 9) | public partial class AddGuestUsersAndOrdersSqlServer : Migration
method Up (line 12) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 90) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/AppDbContextModelSnapshot.cs
class AppDbContextModelSnapshot (line 13) | [DbContext(typeof(AppDbContext))]
method BuildModel (line 16) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Queries/ListProductsQueryService.cs
class ListProductsQueryService (line 7) | public class ListProductsQueryService(AppDbContext db) : IListProductsQu...
method ListAsync (line 11) | public async Task<PagedResult<ProductDto>> ListAsync(int page, int per...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/SeedData.cs
class SeedData (line 7) | public static class SeedData
method InitializeAsync (line 11) | public static async Task InitializeAsync(AppDbContext dbContext, ILogg...
method PopulateTestDataAsync (line 21) | public static async Task PopulateTestDataAsync(AppDbContext dbContext,...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/FakeEmailSender.cs
class FakeEmailSender (line 5) | public class FakeEmailSender(ILogger<FakeEmailSender> logger) : IEmailSe...
method SendEmailAsync (line 8) | public Task SendEmailAsync(string to, string from, string subject, str...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MailserverConfiguration.cs
class MailserverConfiguration (line 3) | public class MailserverConfiguration()
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MimeKitEmailSender.cs
class MimeKitEmailSender (line 7) | public class MimeKitEmailSender(ILogger<MimeKitEmailSender> logger,
method SendEmailAsync (line 13) | public async Task SendEmailAsync(string to, string from, string subjec...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/InfrastructureServiceExtensions.cs
class InfrastructureServiceExtensions (line 8) | public static class InfrastructureServiceExtensions
method AddInfrastructureServices (line 10) | public static IServiceCollection AddInfrastructureServices(
FILE: MinimalClean/src/MinimalClean.Architecture.Web/PagedResult.cs
type PagedResult (line 3) | public record PagedResult<T>(
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/Create/CreateEndpoint.cs
class CreateProductRequest (line 9) | public sealed class CreateProductRequest
class CreateEndpoint (line 15) | public class CreateEndpoint(IRepository<Product> repository) :
method Configure (line 21) | public override void Configure()
method ExecuteAsync (line 45) | public override async Task<Results<Created<ProductRecord>, ValidationP...
class CreateProductValidator (line 58) | public sealed class CreateProductValidator : Validator<CreateProductRequ...
method CreateProductValidator (line 60) | public CreateProductValidator()
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetByIdEndpoint.cs
class GetProductByIdRequest (line 9) | public sealed class GetProductByIdRequest
class GetByIdEndpoint (line 15) | public class GetByIdEndpoint(IMediator mediator)
method Configure (line 22) | public override void Configure()
method ExecuteAsync (line 49) | public override async Task<Results<Ok<ProductRecord>, NotFound, Proble...
class GetProductByIdValidator (line 58) | public sealed class GetProductByIdValidator : Validator<GetProductByIdRe...
method GetProductByIdValidator (line 60) | public GetProductByIdValidator()
class GetProductByIdMapper (line 69) | public sealed class GetProductByIdMapper
method FromEntity (line 72) | public override ProductRecord FromEntity(ProductDto e)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetProductHandler.cs
type GetProductQuery (line 6) | public record GetProductQuery(ProductId ProductId) : IQuery<Result<Produ...
class GetProductHandler (line 8) | public class GetProductHandler(IReadRepository<Product> _repository)
method Handle (line 11) | public async ValueTask<Result<ProductDto>> Handle(GetProductQuery requ...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/IListProductsQueryService.cs
type IListProductsQueryService (line 7) | public interface IListProductsQueryService
method ListAsync (line 9) | Task<PagedResult<ProductDto>> ListAsync(int page, int perPage);
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListEndpoint.cs
class ListProductsRequest (line 7) | public sealed class ListProductsRequest
type ProductListResponse (line 16) | public record ProductListResponse : PagedResult<ProductRecord>
class ListEndpoint (line 25) | public class ListEndpoint(IMediator mediator) : Endpoint<ListProductsReq...
method Configure (line 29) | public override void Configure()
method HandleAsync (line 62) | public override async Task HandleAsync(ListProductsRequest request, Ca...
method AddLinkHeader (line 78) | private void AddLinkHeader(int page, int perPage, int totalPages)
class ListProductsValidator (line 100) | public sealed class ListProductsValidator : Validator<ListProductsRequest>
method ListProductsValidator (line 102) | public ListProductsValidator()
class ListProductsMapper (line 114) | public sealed class ListProductsMapper
method FromEntity (line 117) | public override ProductListResponse FromEntity(PagedResult<ProductDto> e)
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListProductsHandler.cs
type ListProductsQuery (line 3) | public record ListProductsQuery(int? Page = 1,
class ListProductsHandler (line 7) | public class ListProductsHandler(IListProductsQueryService query) : IQue...
method Handle (line 11) | public async ValueTask<Result<PagedResult<ProductDto>>> Handle(ListPro...
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductDto.cs
type ProductDto (line 4) | public record ProductDto(ProductId Id, string Name, decimal UnitPrice);
FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductRecord.cs
type ProductRecord (line 3) | public record ProductRecord(int Id, string Name, decimal UnitPrice);
FILE: MinimalClean/src/MinimalClean.Architecture.Web/Program.cs
class Program (line 34) | public partial class Program { }
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Contributor.cs
class Contributor (line 5) | public sealed class Contributor : EntityBase<Contributor, ContributorId>...
method Contributor (line 9) | public Contributor(ContributorName name)
method UpdateName (line 14) | public Contributor UpdateName(ContributorName newName)
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorId.cs
type ContributorId (line 5) | [ValueObject<int>]
method Validate (line 8) | private static Validation Validate(int value)
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorName.cs
type ContributorName (line 5) | [ValueObject<string>(conversions: Conversions.SystemTextJson)]
method Validate (line 9) | private static Validation Validate(in string name) =>
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorDeletedEvent.cs
class ContributorDeletedEvent (line 7) | public sealed class ContributorDeletedEvent(ContributorId contributorId)...
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorNameUpdatedEvent.cs
class ContributorNameUpdatedEvent (line 3) | public sealed class ContributorNameUpdatedEvent(Contributor contributor)...
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorDeletedHandler.cs
class ContributorDeletedHandler (line 8) | public class ContributorDeletedHandler : INotificationHandler<Contributo...
method ContributorDeletedHandler (line 13) | public ContributorDeletedHandler(IRepository<Project> repository,
method Handle (line 20) | public async ValueTask Handle(ContributorDeletedEvent domainEvent, Can...
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorNameUpdatedEventLoggingHandler.cs
class ContributorNameUpdatedEventLoggingHandler (line 6) | public class ContributorNameUpdatedEventLoggingHandler(ILogger<Contribut...
method Handle (line 11) | public ValueTask Handle(ContributorNameUpdatedEvent notification, Canc...
FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Specifications/ContributorByIdSpec.cs
class ContributorByIdSpec (line 3) | public class ContributorByIdSpec : Specification<Contributor>, ISingleRe...
method ContributorByIdSpec (line 5) | public ContributorByIdSpec(ContributorId contributorId)
FILE: sample/src/NimblePros.SampleToDo.Core/CoreServiceExtensions.cs
class CoreServiceExtensions (line 8) | public static class CoreServiceExtensions
method AddCoreServices (line 10) | public static IServiceCollection AddCoreServices(this IServiceCollecti...
FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IDeleteContributorService.cs
type IDeleteContributorService (line 5) | public interface IDeleteContributorService
method DeleteContributor (line 9) | public Task<Result> DeleteContributor(ContributorId contributorId);
FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IEmailSender.cs
type IEmailSender (line 3) | public interface IEmailSender
method SendEmailAsync (line 5) | Task SendEmailAsync(string to, string from, string subject, string body);
FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IToDoItemSearchService.cs
type IToDoItemSearchService (line 5) | public interface IToDoItemSearchService
method GetNextIncompleteItemAsync (line 7) | Task<Result<ToDoItem>> GetNextIncompleteItemAsync(ProjectId projectId);
method GetAllIncompleteItemsAsync (line 8) | Task<Result<List<ToDoItem>>> GetAllIncompleteItemsAsync(ProjectId proj...
FILE: sample/src/NimblePros.SampleToDo.Core/Localization.cs
class Localization (line 8) | public static class Localization
class LocalizationContext (line 15) | public sealed class LocalizationContext : ILocalizationContext
method LocalizationContext (line 19) | public LocalizationContext(IStringLocalizer localizer) =>
type ILocalizationContext (line 24) | public interface ILocalizationContext
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ContributorAddedToItemEvent.cs
class ContributorAddedToItemEvent (line 5) | public sealed class ContributorAddedToItemEvent(ToDoItem item, Contribut...
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/NewItemAddedEvent.cs
class NewItemAddedEvent (line 3) | public sealed class NewItemAddedEvent(Project project, ToDoItem newItem)...
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ToDoItemCompletedEvent.cs
class ToDoItemCompletedEvent (line 3) | public sealed class ToDoItemCompletedEvent(ToDoItem completedItem) : Dom...
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ContributorAddedToItemLoggingHandler.cs
class ContributorAddedToItemLoggingHandler (line 6) | public class ContributorAddedToItemLoggingHandler(ILogger<ContributorAdd...
method Handle (line 11) | public ValueTask Handle(ContributorAddedToItemEvent notification, Canc...
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ItemCompletedEmailNotificationHandler.cs
class ItemCompletedEmailNotificationHandler (line 6) | public class ItemCompletedEmailNotificationHandler : Mediator.INotificat...
method ItemCompletedEmailNotificationHandler (line 11) | public ItemCompletedEmailNotificationHandler(IEmailSender emailSender)
method Handle (line 18) | public async ValueTask Handle(ToDoItemCompletedEvent domainEvent,
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/NewItemAddedLoggingHandler.cs
class NewItemAddedLoggingHandler (line 6) | public class NewItemAddedLoggingHandler(ILogger<NewItemAddedLoggingHandl...
method Handle (line 11) | public ValueTask Handle(NewItemAddedEvent notification, CancellationTo...
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Priority.cs
class Priority (line 3) | public class Priority : SmartEnum<Priority>
method Priority (line 8) | protected Priority(string name, int value) : base(name, value) { }
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Project.cs
class Project (line 6) | public class Project : EntityBase<Project, ProjectId>, IAggregateRoot
method Project (line 14) | public Project(ProjectName name)
method AddItem (line 19) | public Project AddItem(ToDoItem newItem)
method UpdateName (line 29) | public Project UpdateName(ProjectName newName)
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectErrorMessages.cs
class ProjectErrorMessages (line 9) | public static class ProjectErrorMessages
method CoreProjectNameTooLong (line 15) | public static string CoreProjectNameTooLong(int maxLength) => Get(name...
method CoreToDoItemDescriptionTooLong (line 17) | public static string CoreToDoItemDescriptionTooLong(int maxLength) => ...
method CoreToDoItemTitleTooLong (line 19) | public static string CoreToDoItemTitleTooLong(int maxLength) => Get(na...
method Get (line 24) | private static string Get(string key, params object[] args)
method Fallback (line 43) | private static string Fallback(string key, object[] args) => key switch
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectName.cs
type ProjectName (line 10) | [ValueObject<string>(conversions: Conversions.SystemTextJson)]
method Validate (line 14) | private static Validation Validate(in string name) =>
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectStatus.cs
type ProjectStatus (line 3) | public enum ProjectStatus
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSearchSpec.cs
class IncompleteItemsSearchSpec (line 3) | public class IncompleteItemsSearchSpec : Specification<ToDoItem>
method IncompleteItemsSearchSpec (line 5) | public IncompleteItemsSearchSpec(string searchString)
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSpec.cs
class IncompleteItemsSpec (line 3) | public class IncompleteItemsSpec : Specification<ToDoItem>
method IncompleteItemsSpec (line 5) | public IncompleteItemsSpec()
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectByIdWithItemsSpec.cs
class ProjectByIdWithItemsSpec (line 3) | public class ProjectByIdWithItemsSpec : Specification<Project>
method ProjectByIdWithItemsSpec (line 5) | public ProjectByIdWithItemsSpec(ProjectId projectId)
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectsWithItemsByContributorId.cs
class ProjectsWithItemsByContributorIdSpec (line 5) | public class ProjectsWithItemsByContributorIdSpec : Specification<Project>
method ProjectsWithItemsByContributorIdSpec (line 7) | public ProjectsWithItemsByContributorIdSpec(ContributorId contributorId)
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItem.cs
class ToDoItem (line 7) | public class ToDoItem : EntityBase<ToDoItem, ToDoItemId>
method ToDoItem (line 9) | public ToDoItem() : this(Priority.Backlog)
method ToDoItem (line 12) | public ToDoItem(ToDoItemTitle title, ToDoItemDescription description) ...
method ToDoItem (line 18) | public ToDoItem(Priority priority)
method MarkComplete (line 30) | public ToDoItem MarkComplete()
method AddContributor (line 41) | public ToDoItem AddContributor(ContributorId contributorId)
method RemoveContributor (line 51) | public ToDoItem RemoveContributor()
method UpdateTitle (line 57) | public ToDoItem UpdateTitle(ToDoItemTitle newTitle)
method UpdateDescription (line 64) | public ToDoItem UpdateDescription(ToDoItemDescription newDescription)
method ToString (line 71) | public override string ToString()
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemDescription.cs
type ToDoItemDescription (line 5) | [ValueObject<string>(conversions: Conversions.SystemTextJson)]
method Validate (line 9) | private static Validation Validate(in string description) =>
FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemTitle.cs
type ToDoItemTitle (line 5) | [ValueObject<string>(conversions: Conversions.SystemTextJson)]
method Validate (line 9) | private static Validation Validate(in string title) =>
FILE: sample/src/NimblePros.SampleToDo.Core/Services/DeleteContributorService.cs
class DeleteContributorService (line 8) | public class DeleteContributorService : IDeleteContributorService
method DeleteContributorService (line 14) | public DeleteContributorService(IRepository<Contributor> repository,
method DeleteContributor (line 23) | public async Task<Result> DeleteContributor(ContributorId contributorId)
FILE: sample/src/NimblePros.SampleToDo.Core/Services/ToDoItemSearchService.cs
class ToDoItemSearchService (line 7) | public class ToDoItemSearchService : IToDoItemSearchService
method ToDoItemSearchService (line 11) | public ToDoItemSearchService(IRepository<Project> repository)
method GetAllIncompleteItemsAsync (line 16) | public async Task<Result<List<ToDoItem>>> GetAllIncompleteItemsAsync(P...
method GetNextIncompleteItemAsync (line 51) | public async Task<Result<ToDoItem>> GetNextIncompleteItemAsync(Project...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/AppDbContext.cs
class AppDbContext (line 6) | public class AppDbContext : DbContext
method AppDbContext (line 9) | public AppDbContext(DbContextOptions<AppDbContext> options)
method OnModelCreating (line 16) | protected override void OnModelCreating(ModelBuilder modelBuilder)
method ConfigureConventions (line 22) | protected override void ConfigureConventions(ModelConfigurationBuilder...
method SaveChanges (line 29) | public override int SaveChanges()
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ContributorConfiguration.cs
class ContributorConfiguration (line 5) | public class ContributorConfiguration : IEntityTypeConfiguration<Contrib...
method Configure (line 7) | public void Configure(EntityTypeBuilder<Contributor> builder)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/DataSchemaConstants.cs
class DataSchemaConstants (line 3) | public static class DataSchemaConstants
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ProjectConfiguration.cs
class ProjectConfiguration (line 5) | public class ProjectConfiguration : IEntityTypeConfiguration<Project>
method Configure (line 7) | public void Configure(EntityTypeBuilder<Project> builder)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ToDoItemConfiguration.cs
class ToDoItemConfiguration (line 6) | public class ToDoItemConfiguration : IEntityTypeConfiguration<ToDoItem>
method Configure (line 8) | public void Configure(EntityTypeBuilder<ToDoItem> builder)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/VogenIdValueGenerator.cs
class VogenIdValueGenerator (line 7) | internal class VogenIdValueGenerator<TContext, TEntityBase, TId> : Value...
method VogenIdValueGenerator (line 14) | public VogenIdValueGenerator()
method Next (line 32) | public override TId Next(EntityEntry entry)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/EfRepository.cs
class EfRepository (line 6) | public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IR...
method EfRepository (line 9) | public EfRepository(AppDbContext dbContext) : base(dbContext)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/EventDispatchInterceptor.cs
class EventDispatchInterceptor (line 7) | public class EventDispatchInterceptor(IDomainEventDispatcher domainEvent...
method SavedChangesAsync (line 12) | public override async ValueTask<int> SavedChangesAsync(SaveChangesComp...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListContributorsQueryService.cs
class FakeListContributorsQueryService (line 8) | public class FakeListContributorsQueryService : IListContributorsQuerySe...
method ListAsync (line 10) | public Task<PagedResult<ContributorDto>> ListAsync(int page, int perPage)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListIncompleteItemsQueryService.cs
class FakeListIncompleteItemsQueryService (line 7) | public class FakeListIncompleteItemsQueryService : IListIncompleteItemsQ...
method ListAsync (line 9) | public async Task<IEnumerable<ToDoItemDto>> ListAsync(int projectId)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListProjectsShallowQueryService.cs
class FakeListProjectsShallowQueryService (line 6) | public class FakeListProjectsShallowQueryService : IListProjectsShallowQ...
method ListAsync (line 8) | public async Task<IEnumerable<ProjectDto>> ListAsync()
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListContributorsQueryService.cs
class ListContributorsQueryService (line 7) | public class ListContributorsQueryService : IListContributorsQueryService
method ListContributorsQueryService (line 12) | public ListContributorsQueryService(AppDbContext db)
method ListAsync (line 17) | public async Task<PagedResult<ContributorDto>> ListAsync(int page, int...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListIncompleteItemsQueryService.cs
class ListIncompleteItemsQueryService (line 6) | public class ListIncompleteItemsQueryService : IListIncompleteItemsQuery...
method ListIncompleteItemsQueryService (line 10) | public ListIncompleteItemsQueryService(AppDbContext db)
method ListAsync (line 15) | public async Task<IEnumerable<ToDoItemDto>> ListAsync(int projectId)
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListProjectsShallowQueryService.cs
class ListProjectsShallowQueryService (line 6) | public class ListProjectsShallowQueryService(AppDbContext db) :
method ListAsync (line 11) | public async Task<IEnumerable<ProjectDto>> ListAsync()
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/FakeEmailSender.cs
class FakeEmailSender (line 5) | public class FakeEmailSender : IEmailSender
method FakeEmailSender (line 9) | public FakeEmailSender(ILogger<FakeEmailSender> logger)
method SendEmailAsync (line 13) | public Task SendEmailAsync(string to, string from, string subject, str...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/MailserverConfiguration.cs
class MailserverConfiguration (line 3) | public class MailserverConfiguration()
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/MimeKitEmailSender.cs
class MimeKitEmailSender (line 7) | public class MimeKitEmailSender(ILogger<MimeKitEmailSender> logger,
method SendEmailAsync (line 13) | public async Task SendEmailAsync(string to, string from, string subjec...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/SmtpEmailSender.cs
class SmtpEmailSender (line 5) | [Obsolete("Use MimeKitEmailSender instead")]
method SmtpEmailSender (line 10) | public SmtpEmailSender(ILogger<SmtpEmailSender> logger)
method SendEmailAsync (line 15) | public async Task SendEmailAsync(string to, string from, string subjec...
FILE: sample/src/NimblePros.SampleToDo.Infrastructure/InfrastructureServiceExtensions.cs
class InfrastructureServiceExtensions (line 14) | public static class InfrastructureServiceExtensions
method AddInfrastructureServices (line 16) | public static IServiceCollection AddInfrastructureServices(
method AddDbContextWithSqlite (line 41) | private static void AddDbContextWithSqlite(IServiceCollection services...
method RegisterDevelopmentOnlyDependencies (line 57) | private static void RegisterDevelopmentOnlyDependencies(IServiceCollec...
method RegisterTestingOnlyDependencies (line 66) | private static void RegisterTestingOnlyDependencies(IServiceCollection...
method RegisterProductionOnlyDependencies (line 76) | private static void RegisterProductionOnlyDependencies(IServiceCollect...
method RegisterEFRepositories (line 86) | private static void RegisterEFRepositories(IServiceCollection services)
FILE: sample/src/NimblePros.SampleToDo.ServiceDefaults/Extensions.cs
class Extensions (line 16) | public static class Extensions
method AddServiceDefaults (line 21) | public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder buil...
method ConfigureOpenTelemetry (line 47) | public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder ...
method AddOpenTelemetryExporters (line 81) | private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuil...
method AddDefaultHealthChecks (line 100) | public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder ...
method MapDefaultEndpoints (line 109) | public static WebApplication MapDefaultEndpoints(this WebApplication app)
FILE: sample/src/NimblePros.SampleToDo.UseCases/Constants.cs
class Constants (line 3) | public class Constants
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Create/CreateContributorCommand.cs
type CreateContributorCommand (line 9) | public record CreateContributorCommand(ContributorName Name) : Mediator....
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Create/CreateContributorHandler.cs
class CreateContributorHandler (line 5) | public class CreateContributorHandler(IRepository<Contributor> repository)
method Handle (line 10) | public async ValueTask<Result<int>> Handle(CreateContributorCommand co...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Delete/DeleteContributorCommand.cs
type DeleteContributorCommand (line 5) | public record DeleteContributorCommand(ContributorId ContributorId) : IC...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Delete/DeleteContributorHandler.cs
class DeleteContributorHandler (line 5) | public class DeleteContributorHandler : ICommandHandler<DeleteContributo...
method DeleteContributorHandler (line 9) | public DeleteContributorHandler(IDeleteContributorService deleteContri...
method Handle (line 14) | public async ValueTask<Result> Handle(DeleteContributorCommand request...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Update/UpdateContributorCommand.cs
type UpdateContributorCommand (line 5) | public record UpdateContributorCommand(ContributorId ContributorId, Cont...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Update/UpdateContributorHandler.cs
class UpdateContributorHandler (line 6) | public class UpdateContributorHandler : ICommandHandler<UpdateContributo...
method UpdateContributorHandler (line 10) | public UpdateContributorHandler(IRepository<Contributor> repository)
method Handle (line 15) | public async ValueTask<Result<ContributorDto>> Handle(UpdateContributo...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/ContributorDTO.cs
type ContributorDto (line 4) | public record ContributorDto(ContributorId Id, ContributorName Name);
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/Get/GetContributorHandler.cs
class GetContributorHandler (line 9) | public class GetContributorHandler(IReadRepository<Contributor> repository)
method Handle (line 14) | public async ValueTask<Result<ContributorDto>> Handle(GetContributorQu...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/Get/GetContributorQuery.cs
type GetContributorQuery (line 5) | public record GetContributorQuery(ContributorId ContributorId) : IQuery<...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/IListContributorsQueryService.cs
type IListContributorsQueryService (line 7) | public interface IListContributorsQueryService
method ListAsync (line 9) | Task<PagedResult<ContributorDto>> ListAsync(int page, int perPage);
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/ListContributorsHandler.cs
class ListContributorsHandler (line 3) | public class ListContributorsHandler : IQueryHandler<ListContributorsQue...
method ListContributorsHandler (line 7) | public ListContributorsHandler(IListContributorsQueryService query)
method Handle (line 12) | public async ValueTask<Result<PagedResult<ContributorDto>>> Handle(Lis...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/ListContributorsQuery.cs
type ListContributorsQuery (line 3) | public record ListContributorsQuery(int? Page = 1, int? PerPage = Consta...
FILE: sample/src/NimblePros.SampleToDo.UseCases/ICacheable.cs
type ICacheable (line 2) | public interface ICacheable
method GetCacheKey (line 4) | string GetCacheKey();
FILE: sample/src/NimblePros.SampleToDo.UseCases/PagedResult.cs
type PagedResult (line 3) | public record PagedResult<T>(
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/AddToDoItem/AddToDoItemCommand.cs
type AddToDoItemCommand (line 13) | public record AddToDoItemCommand(ProjectId ProjectId,
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/AddToDoItem/AddToDoItemHandler.cs
class AddToDoItemHandler (line 6) | public class AddToDoItemHandler : ICommandHandler<AddToDoItemCommand, Re...
method AddToDoItemHandler (line 10) | public AddToDoItemHandler(IRepository<Project> repository)
method Handle (line 15) | public async ValueTask<Result<ToDoItemId>> Handle(AddToDoItemCommand r...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Create/CreateProjectCommand.cs
type CreateProjectCommand (line 9) | public record CreateProjectCommand(ProjectName Name) : ICommand<Result<P...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Create/CreateProjectHandler.cs
class CreateProjectHandler (line 5) | public class CreateProjectHandler(IRepository<Project> repository) : ICo...
method Handle (line 9) | public async ValueTask<Result<ProjectId>> Handle(CreateProjectCommand ...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Delete/DeleteProjectCommand.cs
type DeleteProjectCommand (line 5) | public record DeleteProjectCommand(ProjectId ProjectId) : ICommand<Result>;
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Delete/DeleteProjectHandler.cs
class DeleteProjectHandler (line 5) | public class DeleteProjectHandler : ICommandHandler<DeleteProjectCommand...
method DeleteProjectHandler (line 9) | public DeleteProjectHandler(IRepository<Project> repository)
method Handle (line 14) | public async ValueTask<Result> Handle(DeleteProjectCommand request, Ca...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/GetWithAllItems/GetProjectWithAllItemsHandler.cs
class GetProjectWithAllItemsHandler (line 9) | public class GetProjectWithAllItemsHandler : IQueryHandler<GetProjectWit...
method GetProjectWithAllItemsHandler (line 13) | public GetProjectWithAllItemsHandler(IReadRepository<Project> repository)
method Handle (line 18) | public async ValueTask<Result<ProjectWithAllItemsDto>> Handle(GetProje...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/GetWithAllItems/GetProjectWithAllItemsQuery.cs
type GetProjectWithAllItemsQuery (line 5) | public record GetProjectWithAllItemsQuery(ProjectId ProjectId) :
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/IListIncompleteItemsQueryService.cs
type IListIncompleteItemsQueryService (line 7) | public interface IListIncompleteItemsQueryService
method ListAsync (line 9) | Task<IEnumerable<ToDoItemDto>> ListAsync(int projectId);
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/ListIncompleteItemsByProjectHandler.cs
class ListIncompleteItemsByProjectHandler (line 3) | public class ListIncompleteItemsByProjectHandler : IQueryHandler<ListInc...
method ListIncompleteItemsByProjectHandler (line 7) | public ListIncompleteItemsByProjectHandler(IListIncompleteItemsQuerySe...
method Handle (line 12) | public async ValueTask<Result<IEnumerable<ToDoItemDto>>> Handle(ListIn...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/ListIncompleteItemsByProjectQuery.cs
type ListIncompleteItemsByProjectQuery (line 3) | public record ListIncompleteItemsByProjectQuery(int ProjectId) :
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/IListProjectsShallowQueryService.cs
type IListProjectsShallowQueryService (line 7) | public interface IListProjectsShallowQueryService
method ListAsync (line 9) | Task<IEnumerable<ProjectDto>> ListAsync();
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/ListProjectsShallowHandler.cs
class ListProjectsShallowHandler (line 3) | public class ListProjectsShallowHandler(IListProjectsShallowQueryService...
method Handle (line 8) | public async ValueTask<Result<IEnumerable<ProjectDto>>> Handle(ListPro...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/ListProjectsShallowQuery.cs
type ListProjectsShallowQuery (line 3) | public record ListProjectsShallowQuery(int? Skip, int? Take) :
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/MarkToDoItemComplete/MarkToDoItemCompleteCommand.cs
type MarkToDoItemCompleteCommand (line 9) | public record MarkToDoItemCompleteCommand(ProjectId ProjectId, int ToDoI...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/MarkToDoItemComplete/MarkToDoItemCompleteHandler.cs
class MarkToDoItemCompleteHandler (line 6) | public class MarkToDoItemCompleteHandler : ICommandHandler<MarkToDoItemC...
method MarkToDoItemCompleteHandler (line 10) | public MarkToDoItemCompleteHandler(IRepository<Project> repository)
method Handle (line 15) | public async ValueTask<Result> Handle(MarkToDoItemCompleteCommand requ...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ProjectDTO.cs
type ProjectDto (line 3) | public record ProjectDto(int Id, string Name, string Status);
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ProjectWithAllItemsDTO.cs
type ProjectWithAllItemsDto (line 4) | public record ProjectWithAllItemsDto(ProjectId Id, ProjectName Name, Lis...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ToDoItemDTO.cs
type ToDoItemDto (line 6) | public record ToDoItemDto(ToDoItemId Id, string Title, string Descriptio...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Update/UpdateProjectCommand.cs
type UpdateProjectCommand (line 5) | public record UpdateProjectCommand(ProjectId ProjectId, ProjectName NewN...
FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Update/UpdateProjectHandler.cs
class UpdateProjectHandler (line 5) | public class UpdateProjectHandler : ICommandHandler<UpdateProjectCommand...
method UpdateProjectHandler (line 9) | public UpdateProjectHandler(IRepository<Project> repository)
method Handle (line 14) | public async ValueTask<Result<ProjectDto>> Handle(UpdateProjectCommand...
FILE: sample/src/NimblePros.SampleToDo.Web/CachingBehavior.cs
class CachingBehavior (line 9) | public class CachingBehavior<TRequest, TResponse>(IMemoryCache cache,
method Handle (line 19) | public async ValueTask<TResponse?> Handle(
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/CachingOptions.cs
class CachingOptions (line 3) | public class CachingOptions
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/CachingProfile.cs
class CachingProfile (line 3) | public class CachingProfile
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/GlobalExceptionHandler.cs
class GlobalExceptionHandler (line 5) | public class GlobalExceptionHandler(
method TryHandleAsync (line 9) | public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, E...
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/LoggerConfig.cs
class LoggerConfig (line 3) | public static class LoggerConfig
method AddLoggerConfigs (line 5) | public static WebApplicationBuilder AddLoggerConfigs(this WebApplicati...
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/MediatorConfig.cs
class MediatorConfig (line 7) | public static class MediatorConfig
method AddMediatorSourceGen (line 10) | public static IServiceCollection AddMediatorSourceGen(this IServiceCol...
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/MiddlewareConfig.cs
class MiddlewareConfig (line 6) | public static class MiddlewareConfig
method UseAppMiddleware (line 8) | public static async Task<IApplicationBuilder> UseAppMiddleware(this We...
method SeedDatabase (line 35) | static async Task SeedDatabase(WebApplication app)
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/OptionConfigs.cs
class OptionConfig (line 5) | public static class OptionConfig
method AddOptionConfigs (line 7) | public static IServiceCollection AddOptionConfigs(this IServiceCollect...
FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/ServiceConfigs.cs
class ServiceConfig (line 7) | public static class ServiceConfig
method AddServiceConfigs (line 9) | public static IServiceCollection AddServiceConfigs(this IServiceCollec...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/ContributorRecord.cs
type ContributorRecord (line 3) | public record ContributorRecord(int Id, string Name);
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Create.cs
class Create (line 14) | public class Create(IMediator mediator)
method Configure (line 22) | public override void Configure()
method ExecuteAsync (line 50) | public override async Task<Results<Created<CreateContributorResponse>,...
class CreateContributorRequest (line 61) | public class CreateContributorRequest
class CreateContributorValidator (line 69) | public class CreateContributorValidator : Validator<CreateContributorReq...
method CreateContributorValidator (line 71) | public CreateContributorValidator()
class CreateContributorResponse (line 81) | public class CreateContributorResponse(int id, string name)
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.DeleteContributorRequest.cs
type DeleteContributorRequest (line 3) | public record DeleteContributorRequest
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.DeleteContributorValidator.cs
class DeleteContributorValidator (line 9) | public class DeleteContributorValidator : Validator<DeleteContributorReq...
method DeleteContributorValidator (line 11) | public DeleteContributorValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.cs
class Delete (line 7) | public class Delete
method Delete (line 14) | public Delete(IMediator mediator) => _mediator = mediator;
method Configure (line 16) | public override void Configure()
method ExecuteAsync (line 43) | public override async Task<Results<NoContent, NotFound, ProblemHttpRes...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorByIdMapper.cs
class GetContributorByIdMapper (line 5) | public sealed class GetContributorByIdMapper
method FromEntity (line 8) | public override ContributorRecord FromEntity(ContributorDto e)
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorByIdRequest.cs
class GetContributorByIdRequest (line 3) | public class GetContributorByIdRequest
method BuildRoute (line 6) | public static string BuildRoute(int contributorId) => Route.Replace("{...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorValidator.cs
class GetContributorValidator (line 9) | public class GetContributorValidator : Validator<GetContributorByIdRequest>
method GetContributorValidator (line 11) | public GetContributorValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.cs
class GetById (line 7) | public class GetById(IMediator mediator)
method Configure (line 14) | public override void Configure()
method ExecuteAsync (line 42) | public override async Task<Results<Ok<ContributorRecord>, NotFound, Pr...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/List.ContributorListResponse.cs
type ContributorListResponse (line 4) | public record ContributorListResponse : UseCases.PagedResult<Contributor...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/List.cs
class List (line 7) | public class List(IMediator mediator) : Endpoint<ListContributorsRequest...
method Configure (line 11) | public override void Configure()
method HandleAsync (line 48) | public override async Task HandleAsync(ListContributorsRequest request...
method AddLinkHeader (line 64) | private void AddLinkHeader(int page, int perPage, int totalPages)
class ListContributorsRequest (line 86) | public sealed class ListContributorsRequest
class ListContributorsValidator (line 97) | public sealed class ListContributorsValidator : Validator<ListContributo...
method ListContributorsValidator (line 99) | public ListContributorsValidator()
class ListContributorsMapper (line 111) | public sealed class ListContributorsMapper
method FromEntity (line 114) | public override ContributorListResponse FromEntity(UseCases.PagedResul...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorRequest.cs
class UpdateContributorRequest (line 5) | public class UpdateContributorRequest
method BuildRoute (line 8) | public static string BuildRoute(int contributorId) => Route.Replace("{...
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorResponse.cs
class UpdateContributorResponse (line 3) | public class UpdateContributorResponse
method UpdateContributorResponse (line 5) | public UpdateContributorResponse(ContributorRecord contributor)
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorValidator.cs
class UpdateContributorValidator (line 9) | public class UpdateContributorValidator : Validator<UpdateContributorReq...
method UpdateContributorValidator (line 11) | public UpdateContributorValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.cs
class Update (line 8) | public class Update(IMediator mediator)
method Configure (line 16) | public override void Configure()
method ExecuteAsync (line 46) | public override async Task<Results<Ok<UpdateContributorResponse>, NotF...
class UpdateContributorMapper (line 59) | public sealed class UpdateContributorMapper
method FromEntity (line 62) | public override UpdateContributorResponse FromEntity(ContributorDto e)
FILE: sample/src/NimblePros.SampleToDo.Web/Extensions/ResultExtensions.cs
class ResultExtensions (line 5) | public static class ResultExtensions
method ToCreatedResult (line 10) | public static Results<Created<TResponse>, ValidationProblem, ProblemHt...
method ToGetByIdResult (line 36) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToGe...
method ToUpdateResult (line 46) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToUp...
method ToDeleteResult (line 56) | public static Results<NoContent, NotFound, ProblemHttpResult> ToDelete...
method ToOkOrNotFoundResult (line 73) | private static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToO...
method ToOkOnlyResult (line 92) | public static Ok<TResponse> ToOkOnlyResult<TValue, TResponse>(
FILE: sample/src/NimblePros.SampleToDo.Web/LoggingBehavior.cs
class LoggingBehavior (line 7) | public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TR...
method LoggingBehavior (line 12) | public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> l...
method Handle (line 17) | public async ValueTask<TResponse> Handle(
FILE: sample/src/NimblePros.SampleToDo.Web/Program.cs
class Program (line 11) | public partial class Program
method Main (line 13) | private static async Task Main(string[] args)
class Program (line 116) | public partial class Program
method Main (line 13) | private static async Task Main(string[] args)
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectRequest.cs
class CreateProjectRequest (line 5) | public class CreateProjectRequest
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectResponse.cs
type CreateProjectResponse (line 3) | public record CreateProjectResponse(int Id, string Name);
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectValidator.cs
class CreateProjectValidator (line 7) | public class CreateProjectValidator : Validator<CreateProjectRequest>
method CreateProjectValidator (line 9) | public CreateProjectValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.cs
class Create (line 7) | public class Create(IMediator mediator)
method Configure (line 12) | public override void Configure()
method ExecuteAsync (line 40) | public override async Task<Results<Created<CreateProjectResponse>, Val...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.CreateToDoItemRequest.cs
class CreateToDoItemRequest (line 6) | public class CreateToDoItemRequest
method BuildRoute (line 9) | public static string BuildRoute(int projectId) => Route.Replace("{Proj...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.CreateToDoItemValidator.cs
class CreateToDoItemValidator (line 9) | public class CreateToDoItemValidator : Validator<CreateToDoItemRequest>
method CreateToDoItemValidator (line 11) | public CreateToDoItemValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.cs
class Create (line 8) | public class Create : Endpoint<CreateToDoItemRequest, Results<Created, N...
method Create (line 12) | public Create(IMediator mediator)
method Configure (line 17) | public override void Configure()
method ExecuteAsync (line 52) | public override async Task<Results<Created, NotFound, ProblemHttpResult>>
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.DeleteProjectRequest.cs
class DeleteProjectRequest (line 3) | public class DeleteProjectRequest
method BuildRoute (line 6) | public static string BuildRoute(int projectId) => Route.Replace("{Proj...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.DeleteProjectValidator.cs
class DeleteProjectValidator (line 9) | public class DeleteProjectValidator : Validator<DeleteProjectRequest>
method DeleteProjectValidator (line 11) | public DeleteProjectValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.cs
class Delete (line 7) | public class Delete
method Delete (line 14) | public Delete(IMediator mediator) => _mediator = mediator;
method Configure (line 16) | public override void Configure()
method ExecuteAsync (line 43) | public override async Task<Results<NoContent, NotFound, ProblemHttpRes...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdRequest.cs
class GetProjectByIdRequest (line 4) | public class GetProjectByIdRequest
method BuildRoute (line 7) | public static string BuildRoute(int projectId) => Route.Replace("{Proj...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdResponse.cs
type GetProjectByIdResponse (line 3) | public record GetProjectByIdResponse(int Id, string Name, List<ToDoItemR...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdValidator.cs
class GetProjectByIdValidator (line 10) | public class GetProjectByIdValidator : Validator<GetProjectByIdRequest>
method GetProjectByIdValidator (line 12) | public GetProjectByIdValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.cs
class GetById (line 8) | public class GetById(IMediator mediator)
method Configure (line 14) | public override void Configure()
method ExecuteAsync (line 49) | public override async Task<Results<Ok<GetProjectByIdResponse>, NotFoun...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/List.ProjectListResponse.cs
type ProjectListResponse (line 3) | public record ProjectListResponse : UseCases.PagedResult<ProjectRecord>
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/List.cs
class List (line 8) | public class List(IMediator mediator) : Endpoint<ListProjectsRequest, Pr...
method Configure (line 12) | public override void Configure()
method HandleAsync (line 49) | public override async Task HandleAsync(ListProjectsRequest request, Ca...
method AddLinkHeader (line 79) | private void AddLinkHeader(int page, int perPage, int totalPages)
class ListProjectsRequest (line 101) | public sealed class ListProjectsRequest
class ListProjectsValidator (line 112) | public sealed class ListProjectsValidator : Validator<ListProjectsRequest>
method ListProjectsValidator (line 114) | public ListProjectsValidator()
class ListProjectsMapper (line 126) | public sealed class ListProjectsMapper
method FromEntity (line 129) | public override ProjectListResponse FromEntity(UseCases.PagedResult<Pr...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.ListIncompleteItemsRequest.cs
class ListIncompleteItemsRequest (line 5) | public class ListIncompleteItemsRequest
method BuildRoute (line 8) | public static string BuildRoute(int projectId) => Route.Replace("{Proj...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.ListIncompleteItemsResponse.cs
class ListIncompleteItemsResponse (line 3) | public class ListIncompleteItemsResponse
method ListIncompleteItemsResponse (line 5) | public ListIncompleteItemsResponse(int projectId, List<ToDoItemRecord>...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.cs
class ListIncompleteItems (line 13) | public class ListIncompleteItems(IMediator mediator) : Endpoint<ListInco...
method Configure (line 17) | public override void Configure()
method HandleAsync (line 23) | public override async Task HandleAsync(ListIncompleteItemsRequest requ...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/MarkItemComplete.MarkItemCompleteRequest.cs
class MarkItemCompleteRequest (line 6) | public class MarkItemCompleteRequest
method BuildRoute (line 9) | public static string BuildRoute(int projectId, int toDoItemId) => Rout...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/MarkItemComplete.cs
class MarkItemComplete (line 9) | public class MarkItemComplete(IMediator mediator) : Endpoint<MarkItemCom...
method Configure (line 13) | public override void Configure()
method HandleAsync (line 27) | public override async Task HandleAsync(
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ProjectRecord.cs
type ProjectRecord (line 3) | public record ProjectRecord(int Id, string Name);
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ToDoItemRecord.cs
type ToDoItemRecord (line 2) | public record ToDoItemRecord(int Id, string Title, string Description, b...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectRequest.cs
class UpdateProjectRequest (line 5) | public class UpdateProjectRequest
method BuildRoute (line 8) | public static string BuildRoute(int projectId) => Route.Replace("{Proj...
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectRequestValidator.cs
class UpdateProjectRequestValidator (line 9) | public class UpdateProjectRequestValidator : Validator<UpdateProjectRequ...
method UpdateProjectRequestValidator (line 11) | public UpdateProjectRequestValidator()
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectResponse.cs
class UpdateProjectResponse (line 3) | public class UpdateProjectResponse
method UpdateProjectResponse (line 5) | public UpdateProjectResponse(ProjectRecord project)
FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.cs
class Update (line 8) | public class Update(IMediator mediator)
method Configure (line 16) | public override void Configure()
method ExecuteAsync (line 46) | public override async Task<Results<Ok<UpdateProjectResponse>, NotFound...
class UpdateProjectMapper (line 59) | public sealed class UpdateProjectMapper
method FromEntity (line 62) | public override UpdateProjectResponse FromEntity(ProjectDto e)
FILE: sample/src/NimblePros.SampleToDo.Web/SeedData.cs
class SeedData (line 7) | public static class SeedData
method InitializeAsync (line 26) | public static async Task InitializeAsync(AppDbContext dbContext)
method PopulateTestDataAsync (line 36) | public static async Task PopulateTestDataAsync(AppDbContext dbContext)
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js
function getUidEvent (line 353) | function getUidEvent(element, uid) {
function getEvent (line 357) | function getEvent(element) {
function bootstrapHandler (line 364) | function bootstrapHandler(element, fn) {
function bootstrapDelegationHandler (line 376) | function bootstrapDelegationHandler(element, selector, fn) {
function findHandler (line 402) | function findHandler(events, handler, delegationSelector = null) {
function normalizeParams (line 416) | function normalizeParams(originalTypeEvent, handler, delegationFn) {
function addHandler (line 429) | function addHandler(element, originalTypeEvent, handler, delegationFn, o...
function removeHandler (line 477) | function removeHandler(element, events, typeEvent, handler, delegationSe...
function removeNamespacedHandlers (line 488) | function removeNamespacedHandlers(element, events, typeEvent, namespace) {
function getTypeEvent (line 498) | function getTypeEvent(event) {
method on (line 505) | on(element, event, handler, delegationFn) {
method one (line 509) | one(element, event, handler, delegationFn) {
method off (line 513) | off(element, originalTypeEvent, handler, delegationFn) {
method trigger (line 550) | trigger(element, event, args) {
method set (line 626) | set(element, key, instance) {
method get (line 643) | get(element, key) {
method remove (line 651) | remove(element, key) {
class BaseComponent (line 680) | class BaseComponent {
method constructor (line 681) | constructor(element) {
method dispose (line 692) | dispose() {
method _queueCallback (line 700) | _queueCallback(callback, element, isAnimated = true) {
method getInstance (line 706) | static getInstance(element) {
method getOrCreateInstance (line 710) | static getOrCreateInstance(element, config = {}) {
method VERSION (line 714) | static get VERSION() {
method NAME (line 718) | static get NAME() {
method DATA_KEY (line 722) | static get DATA_KEY() {
method EVENT_KEY (line 726) | static get EVENT_KEY() {
class Alert (line 783) | class Alert extends BaseComponent {
method NAME (line 785) | static get NAME() {
method close (line 790) | close() {
method _destroyElement (line 805) | _destroyElement() {
method jQueryInterface (line 813) | static jQueryInterface(config) {
class Button (line 872) | class Button extends BaseComponent {
method NAME (line 874) | static get NAME() {
method toggle (line 879) | toggle() {
method jQueryInterface (line 885) | static jQueryInterface(config) {
function normalizeData (line 924) | function normalizeData(val) {
function normalizeDataKey (line 944) | function normalizeDataKey(key) {
method setDataAttribute (line 949) | setDataAttribute(element, key, value) {
method removeDataAttribute (line 953) | removeDataAttribute(element, key) {
method getDataAttributes (line 957) | getDataAttributes(element) {
method getDataAttribute (line 971) | getDataAttribute(element, key) {
method offset (line 975) | offset(element) {
method position (line 983) | position(element) {
method find (line 1000) | find(selector, element = document.documentElement) {
method findOne (line 1004) | findOne(selector, element = document.documentElement) {
method children (line 1008) | children(element, selector) {
method parents (line 1012) | parents(element, selector) {
method prev (line 1027) | prev(element, selector) {
method next (line 1041) | next(element, selector) {
method focusableChildren (line 1055) | focusableChildren(element) {
class Carousel (line 1145) | class Carousel extends BaseComponent {
method constructor (line 1146) | constructor(element, config) {
method Default (line 1165) | static get Default() {
method NAME (line 1169) | static get NAME() {
method next (line 1174) | next() {
method nextWhenVisible (line 1178) | nextWhenVisible() {
method prev (line 1186) | prev() {
method pause (line 1190) | pause(event) {
method cycle (line 1204) | cycle(event) {
method to (line 1221) | to(index) {
method _getConfig (line 1247) | _getConfig(config) {
method _handleSwipe (line 1256) | _handleSwipe() {
method _addEventListeners (line 1273) | _addEventListeners() {
method _addTouchEventListeners (line 1288) | _addTouchEventListeners() {
method _keydown (line 1343) | _keydown(event) {
method _getItemIndex (line 1357) | _getItemIndex(element) {
method _getItemByOrder (line 1362) | _getItemByOrder(order, activeElement) {
method _triggerSlideEvent (line 1367) | _triggerSlideEvent(relatedTarget, eventDirectionName) {
method _setActiveIndicatorElement (line 1380) | _setActiveIndicatorElement(element) {
method _updateInterval (line 1397) | _updateInterval() {
method _slide (line 1414) | _slide(directionOrOrder, element) {
method _directionToOrder (line 1498) | _directionToOrder(direction) {
method _orderToDirection (line 1510) | _orderToDirection(order) {
method carouselInterface (line 1523) | static carouselInterface(element, config) {
method jQueryInterface (line 1551) | static jQueryInterface(config) {
method dataApiClickHandler (line 1557) | static dataApiClickHandler(event) {
class Collapse (line 1651) | class Collapse extends BaseComponent {
method constructor (line 1652) | constructor(element, config) {
method Default (line 1683) | static get Default() {
method NAME (line 1687) | static get NAME() {
method toggle (line 1692) | toggle() {
method show (line 1700) | show() {
method hide (line 1773) | hide() {
method _isShown (line 1821) | _isShown(element = this._element) {
method _getConfig (line 1826) | _getConfig(config) {
method _getDimension (line 1838) | _getDimension() {
method _initializeChildren (line 1842) | _initializeChildren() {
method _addAriaAndCollapsedClass (line 1857) | _addAriaAndCollapsedClass(triggerArray, isOpen) {
method jQueryInterface (line 1874) | static jQueryInterface(config) {
function getNodeName (line 1957) | function getNodeName(element) {
function getWindow (line 1961) | function getWindow(node) {
function isElement (line 1974) | function isElement(node) {
function isHTMLElement (line 1979) | function isHTMLElement(node) {
function isShadowRoot (line 1984) | function isShadowRoot(node) {
function applyStyles (line 1996) | function applyStyles(_ref) {
function effect$2 (line 2023) | function effect$2(_ref2) {
function getBasePlacement (line 2077) | function getBasePlacement(placement) {
function getBoundingClientRect (line 2082) | function getBoundingClientRect(element, includeScale) {
function getLayoutRect (line 2111) | function getLayoutRect(element) {
function contains (line 2134) | function contains(parent, child) {
function getComputedStyle$1 (line 2157) | function getComputedStyle$1(element) {
function isTableElement (line 2161) | function isTableElement(element) {
function getDocumentElement (line 2165) | function getDocumentElement(element) {
function getParentNode (line 2171) | function getParentNode(element) {
function getTrueOffsetParent (line 2188) | function getTrueOffsetParent(element) {
function getContainingBlock (line 2199) | function getContainingBlock(element) {
function getOffsetParent (line 2231) | function getOffsetParent(element) {
function getMainAxisFromPlacement (line 2246) | function getMainAxisFromPlacement(placement) {
function within (line 2254) | function within(min$1, value, max$1) {
function getFreshSideObject (line 2258) | function getFreshSideObject() {
function mergePaddingObject (line 2267) | function mergePaddingObject(paddingObject) {
function expandToHashMap (line 2271) | function expandToHashMap(value, keys) {
function arrow (line 2285) | function arrow(_ref) {
function effect$1 (line 2322) | function effect$1(_ref2) {
function roundOffsetsByDPR (line 2369) | function roundOffsetsByDPR(_ref) {
function mapToStyles (line 2380) | function mapToStyles(_ref2) {
function computeStyles (line 2449) | function computeStyles(_ref4) {
function effect (line 2502) | function effect(_ref) {
function getOppositePlacement (line 2552) | function getOppositePlacement(placement) {
function getOppositeVariationPlacement (line 2562) | function getOppositeVariationPlacement(placement) {
function getWindowScroll (line 2568) | function getWindowScroll(node) {
function getWindowScrollBarX (line 2578) | function getWindowScrollBarX(element) {
function getViewportRect (line 2589) | function getViewportRect(element) {
function getDocumentRect (line 2629) | function getDocumentRect(element) {
function isScrollParent (line 2652) | function isScrollParent(element) {
function getScrollParent (line 2662) | function getScrollParent(node) {
function listScrollParents (line 2682) | function listScrollParents(element, list) {
function rectToClientRect (line 2698) | function rectToClientRect(rect) {
function getInnerBoundingClientRect (line 2707) | function getInnerBoundingClientRect(element) {
function getClientRectFromMixedType (line 2720) | function getClientRectFromMixedType(element, clippingParent) {
function getClippingParents (line 2727) | function getClippingParents(element) {
function getClippingRect (line 2744) | function getClippingRect(element, boundary, rootBoundary) {
function getVariation (line 2763) | function getVariation(placement) {
function computeOffsets (line 2767) | function computeOffsets(_ref) {
function detectOverflow (line 2832) | function detectOverflow(state, options) {
function computeAutoPlacement (line 2887) | function computeAutoPlacement(state, options) {
function getExpandedFallbackPlacements (line 2927) | function getExpandedFallbackPlacements(placement) {
function flip (line 2936) | function flip(_ref) {
function getSideOffsets (line 3067) | function getSideOffsets(overflow, rect, preventedOffsets) {
function isAnySideFullyClipped (line 3083) | function isAnySideFullyClipped(overflow) {
function hide (line 3089) | function hide(_ref) {
function distanceAndSkiddingToXY (line 3126) | function distanceAndSkiddingToXY(placement, rects, offset) {
function offset (line 3147) | function offset(_ref2) {
function popperOffsets (line 3178) | function popperOffsets(_ref) {
function getAltAxis (line 3202) | function getAltAxis(axis) {
function preventOverflow (line 3206) | function preventOverflow(_ref) {
function getHTMLElementScroll (line 3318) | function getHTMLElementScroll(element) {
function getNodeScroll (line 3325) | function getNodeScroll(node) {
function isElementScaled (line 3333) | function isElementScaled(element) {
function getCompositeRect (line 3342) | function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
function order (line 3383) | function order(modifiers) {
function orderModifiers (line 3415) | function orderModifiers(modifiers) {
function debounce (line 3426) | function debounce(fn) {
function mergeByName (line 3442) | function mergeByName(modifiers) {
function areValidElements (line 3463) | function areValidElements() {
function popperGenerator (line 3473) | function popperGenerator(generatorOptions) {
class Dropdown (line 3769) | class Dropdown extends BaseComponent {
method constructor (line 3770) | constructor(element, config) {
method Default (line 3779) | static get Default() {
method DefaultType (line 3783) | static get DefaultType() {
method NAME (line 3787) | static get NAME() {
method toggle (line 3792) | toggle() {
method show (line 3796) | show() {
method hide (line 3837) | hide() {
method dispose (line 3849) | dispose() {
method update (line 3857) | update() {
method _completeHide (line 3866) | _completeHide(relatedTarget) {
method _getConfig (line 3893) | _getConfig(config) {
method _createPopper (line 3908) | _createPopper(parent) {
method _isShown (line 3933) | _isShown(element = this._element) {
method _getMenuElement (line 3937) | _getMenuElement() {
method _getPlacement (line 3941) | _getPlacement() {
method _detectNavbar (line 3962) | _detectNavbar() {
method _getOffset (line 3966) | _getOffset() {
method _getPopperConfig (line 3982) | _getPopperConfig() {
method _selectMenuItem (line 4010) | _selectMenuItem({
method jQueryInterface (line 4026) | static jQueryInterface(config) {
method clearMenus (line 4042) | static clearMenus(event) {
method getParentFromElement (line 4086) | static getParentFromElement(element) {
method dataApiKeydownHandler (line 4090) | static dataApiKeydownHandler(event) {
class ScrollBarHelper (line 4172) | class ScrollBarHelper {
method constructor (line 4173) | constructor() {
method getWidth (line 4177) | getWidth() {
method hide (line 4183) | hide() {
method _disableOverFlow (line 4197) | _disableOverFlow() {
method _setElementAttributes (line 4203) | _setElementAttributes(selector, styleProp, callback) {
method reset (line 4220) | reset() {
method _saveInitialAttribute (line 4230) | _saveInitialAttribute(element, styleProp) {
method _resetElementAttributes (line 4238) | _resetElementAttributes(selector, styleProp) {
method _applyManipulationCallback (line 4253) | _applyManipulationCallback(selector, callBack) {
method isOverflowing (line 4261) | isOverflowing() {
class Backdrop (line 4294) | class Backdrop {
method constructor (line 4295) | constructor(config) {
method show (line 4301) | show(callback) {
method hide (line 4320) | hide(callback) {
method _getElement (line 4335) | _getElement() {
method _getConfig (line 4350) | _getConfig(config) {
method _append (line 4360) | _append() {
method dispose (line 4373) | dispose() {
method _emulateAnimation (line 4385) | _emulateAnimation(callback) {
class FocusTrap (line 4415) | class FocusTrap {
method constructor (line 4416) | constructor(config) {
method activate (line 4422) | activate() {
method deactivate (line 4443) | deactivate() {
method _handleFocusin (line 4453) | _handleFocusin(event) {
method _handleKeydown (line 4476) | _handleKeydown(event) {
method _getConfig (line 4484) | _getConfig(config) {
class Modal (line 4545) | class Modal extends BaseComponent {
method constructor (line 4546) | constructor(element, config) {
method Default (line 4559) | static get Default() {
method NAME (line 4563) | static get NAME() {
method toggle (line 4568) | toggle(relatedTarget) {
method show (line 4572) | show(relatedTarget) {
method hide (line 4612) | hide() {
method dispose (line 4645) | dispose() {
method handleUpdate (line 4655) | handleUpdate() {
method _initializeBackDrop (line 4660) | _initializeBackDrop() {
method _initializeFocusTrap (line 4668) | _initializeFocusTrap() {
method _getConfig (line 4674) | _getConfig(config) {
method _showElement (line 4683) | _showElement(relatedTarget) {
method _setEscapeEvent (line 4727) | _setEscapeEvent() {
method _setResizeEvent (line 4742) | _setResizeEvent() {
method _hideModal (line 4750) | _hideModal() {
method _showBackdrop (line 4772) | _showBackdrop(callback) {
method _isAnimated (line 4793) | _isAnimated() {
method _triggerBackdropTransition (line 4797) | _triggerBackdropTransition() {
method _adjustDialog (line 4837) | _adjustDialog() {
method _resetAdjustments (line 4853) | _resetAdjustments() {
method jQueryInterface (line 4859) | static jQueryInterface(config, relatedTarget) {
class Offcanvas (line 4959) | class Offcanvas extends BaseComponent {
method constructor (line 4960) | constructor(element, config) {
method NAME (line 4971) | static get NAME() {
method Default (line 4975) | static get Default() {
method toggle (line 4980) | toggle(relatedTarget) {
method show (line 4984) | show(relatedTarget) {
method hide (line 5027) | hide() {
method dispose (line 5067) | dispose() {
method _getConfig (line 5076) | _getConfig(config) {
method _initializeBackDrop (line 5085) | _initializeBackDrop() {
method _initializeFocusTrap (line 5095) | _initializeFocusTrap() {
method _addEventListeners (line 5101) | _addEventListeners() {
method jQueryInterface (line 5110) | static jQueryInterface(config) {
function sanitizeHtml (line 5249) | function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
class Tooltip (line 5376) | class Tooltip extends BaseComponent {
method constructor (line 5377) | constructor(element, config) {
method Default (line 5397) | static get Default() {
method NAME (line 5401) | static get NAME() {
method Event (line 5405) | static get Event() {
method DefaultType (line 5409) | static get DefaultType() {
method enable (line 5414) | enable() {
method disable (line 5418) | disable() {
method toggleEnabled (line 5422) | toggleEnabled() {
method toggle (line 5426) | toggle(event) {
method dispose (line 5452) | dispose() {
method show (line 5467) | show() {
method hide (line 5549) | hide() {
method update (line 5601) | update() {
method isWithContent (line 5608) | isWithContent() {
method getTipElement (line 5612) | getTipElement() {
method setContent (line 5626) | setContent(tip) {
method _sanitizeAndSetContent (line 5630) | _sanitizeAndSetContent(template, content, selector) {
method setElementContent (line 5642) | setElementContent(element, content) {
method getTitle (line 5673) | getTitle() {
method updateAttachment (line 5679) | updateAttachment(attachment) {
method _initializeOnDelegatedTarget (line 5692) | _initializeOnDelegatedTarget(event, context) {
method _getOffset (line 5696) | _getOffset() {
method _resolvePossibleFunction (line 5712) | _resolvePossibleFunction(content) {
method _getPopperConfig (line 5716) | _getPopperConfig(attachment) {
method _addAttachmentClass (line 5756) | _addAttachmentClass(attachment) {
method _getAttachment (line 5760) | _getAttachment(placement) {
method _setListeners (line 5764) | _setListeners() {
method _fixTitle (line 5796) | _fixTitle() {
method _enter (line 5812) | _enter(event, context) {
method _leave (line 5839) | _leave(event, context) {
method _isWithActiveTrigger (line 5865) | _isWithActiveTrigger() {
method _getConfig (line 5875) | _getConfig(config) {
method _getDelegateConfig (line 5912) | _getDelegateConfig() {
method _cleanTipClass (line 5927) | _cleanTipClass() {
method _getBasicClassPrefix (line 5937) | _getBasicClassPrefix() {
method _handlePopperPlacementChange (line 5941) | _handlePopperPlacementChange(popperData) {
method jQueryInterface (line 5958) | static jQueryInterface(config) {
class Popover (line 6029) | class Popover extends Tooltip {
method Default (line 6031) | static get Default() {
method NAME (line 6035) | static get NAME() {
method Event (line 6039) | static get Event() {
method DefaultType (line 6043) | static get DefaultType() {
method isWithContent (line 6048) | isWithContent() {
method setContent (line 6052) | setContent(tip) {
method _getContent (line 6059) | _getContent() {
method _getBasicClassPrefix (line 6063) | _getBasicClassPrefix() {
method jQueryInterface (line 6068) | static jQueryInterface(config) {
class ScrollSpy (line 6140) | class ScrollSpy extends BaseComponent {
method constructor (line 6141) | constructor(element, config) {
method Default (line 6156) | static get Default() {
method NAME (line 6160) | static get NAME() {
method refresh (line 6165) | refresh() {
method dispose (line 6193) | dispose() {
method _getConfig (line 6199) | _getConfig(config) {
method _getScrollTop (line 6209) | _getScrollTop() {
method _getScrollHeight (line 6213) | _getScrollHeight() {
method _getOffsetHeight (line 6217) | _getOffsetHeight() {
method _process (line 6221) | _process() {
method _activate (line 6259) | _activate(target) {
method _clear (line 6287) | _clear() {
method jQueryInterface (line 6292) | static jQueryInterface(config) {
class Tab (line 6366) | class Tab extends BaseComponent {
method NAME (line 6368) | static get NAME() {
method show (line 6373) | show() {
method _activate (line 6419) | _activate(element, container, callback) {
method _transitionComplete (line 6435) | _transitionComplete(element, active, callback) {
method jQueryInterface (line 6483) | static jQueryInterface(config) {
class Toast (line 6570) | class Toast extends BaseComponent {
method constructor (line 6571) | constructor(element, config) {
method DefaultType (line 6582) | static get DefaultType() {
method Default (line 6586) | static get Default() {
method NAME (line 6590) | static get NAME() {
method show (line 6595) | show() {
method hide (line 6628) | hide() {
method dispose (line 6655) | dispose() {
method _getConfig (line 6666) | _getConfig(config) {
method _maybeScheduleHide (line 6675) | _maybeScheduleHide() {
method _onInteraction (line 6689) | _onInteraction(event, isInteracting) {
method _setListeners (line 6717) | _setListeners() {
method _clearTimeout (line 6724) | _clearTimeout() {
method jQueryInterface (line 6730) | static jQueryInterface(config) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js
constant MAX_UID (line 14) | const MAX_UID = 1000000;
constant MILLISECONDS_MULTIPLIER (line 15) | const MILLISECONDS_MULTIPLIER = 1000;
constant TRANSITION_END (line 16) | const TRANSITION_END = 'transitionend';
function getUidEvent (line 349) | function getUidEvent(element, uid) {
function getEvent (line 353) | function getEvent(element) {
function bootstrapHandler (line 360) | function bootstrapHandler(element, fn) {
function bootstrapDelegationHandler (line 372) | function bootstrapDelegationHandler(element, selector, fn) {
function findHandler (line 398) | function findHandler(events, handler, delegationSelector = null) {
function normalizeParams (line 412) | function normalizeParams(originalTypeEvent, handler, delegationFn) {
function addHandler (line 425) | function addHandler(element, originalTypeEvent, handler, delegationFn, o...
function removeHandler (line 473) | function removeHandler(element, events, typeEvent, handler, delegationSe...
function removeNamespacedHandlers (line 484) | function removeNamespacedHandlers(element, events, typeEvent, namespace) {
function getTypeEvent (line 494) | function getTypeEvent(event) {
method on (line 501) | on(element, event, handler, delegationFn) {
method one (line 505) | one(element, event, handler, delegationFn) {
method off (line 509) | off(element, originalTypeEvent, handler, delegationFn) {
method trigger (line 546) | trigger(element, event, args) {
method set (line 622) | set(element, key, instance) {
method get (line 639) | get(element, key) {
method remove (line 647) | remove(element, key) {
constant VERSION (line 674) | const VERSION = '5.1.0';
class BaseComponent (line 676) | class BaseComponent {
method constructor (line 677) | constructor(element) {
method dispose (line 688) | dispose() {
method _queueCallback (line 696) | _queueCallback(callback, element, isAnimated = true) {
method getInstance (line 702) | static getInstance(element) {
method getOrCreateInstance (line 706) | static getOrCreateInstance(element, config = {}) {
method VERSION (line 710) | static get VERSION() {
method NAME (line 714) | static get NAME() {
method DATA_KEY (line 718) | static get DATA_KEY() {
method EVENT_KEY (line 722) | static get EVENT_KEY() {
constant EVENT_CLOSE (line 769) | const EVENT_CLOSE = `close${EVENT_KEY$c}`;
constant EVENT_CLOSED (line 770) | const EVENT_CLOSED = `closed${EVENT_KEY$c}`;
class Alert (line 779) | class Alert extends BaseComponent {
method NAME (line 781) | static get NAME() {
method close (line 786) | close() {
method _destroyElement (line 801) | _destroyElement() {
method jQueryInterface (line 809) | static jQueryInterface(config) {
class Button (line 868) | class Button extends BaseComponent {
method NAME (line 870) | static get NAME() {
method toggle (line 875) | toggle() {
method jQueryInterface (line 881) | static jQueryInterface(config) {
function normalizeData (line 920) | function normalizeData(val) {
function normalizeDataKey (line 940) | function normalizeDataKey(key) {
method setDataAttribute (line 945) | setDataAttribute(element, key, value) {
method removeDataAttribute (line 949) | removeDataAttribute(element, key) {
method getDataAttributes (line 953) | getDataAttributes(element) {
method getDataAttribute (line 967) | getDataAttribute(element, key) {
method offset (line 971) | offset(element) {
method position (line 979) | position(element) {
constant NODE_TEXT (line 994) | const NODE_TEXT = 3;
method find (line 996) | find(selector, element = document.documentElement) {
method findOne (line 1000) | findOne(selector, element = document.documentElement) {
method children (line 1004) | children(element, selector) {
method parents (line 1008) | parents(element, selector) {
method prev (line 1023) | prev(element, selector) {
method next (line 1037) | next(element, selector) {
method focusableChildren (line 1051) | focusableChildren(element) {
constant ARROW_LEFT_KEY (line 1074) | const ARROW_LEFT_KEY = 'ArrowLeft';
constant ARROW_RIGHT_KEY (line 1075) | const ARROW_RIGHT_KEY = 'ArrowRight';
constant TOUCHEVENT_COMPAT_WAIT (line 1076) | const TOUCHEVENT_COMPAT_WAIT = 500;
constant SWIPE_THRESHOLD (line 1078) | const SWIPE_THRESHOLD = 40;
constant ORDER_NEXT (line 1095) | const ORDER_NEXT = 'next';
constant ORDER_PREV (line 1096) | const ORDER_PREV = 'prev';
constant DIRECTION_LEFT (line 1097) | const DIRECTION_LEFT = 'left';
constant DIRECTION_RIGHT (line 1098) | const DIRECTION_RIGHT = 'right';
constant KEY_TO_DIRECTION (line 1099) | const KEY_TO_DIRECTION = {
constant EVENT_SLIDE (line 1103) | const EVENT_SLIDE = `slide${EVENT_KEY$a}`;
constant EVENT_SLID (line 1104) | const EVENT_SLID = `slid${EVENT_KEY$a}`;
constant EVENT_KEYDOWN (line 1105) | const EVENT_KEYDOWN = `keydown${EVENT_KEY$a}`;
constant EVENT_MOUSEENTER (line 1106) | const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY$a}`;
constant EVENT_MOUSELEAVE (line 1107) | const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY$a}`;
constant EVENT_TOUCHSTART (line 1108) | const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$a}`;
constant EVENT_TOUCHMOVE (line 1109) | const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$a}`;
constant EVENT_TOUCHEND (line 1110) | const EVENT_TOUCHEND = `touchend${EVENT_KEY$a}`;
constant EVENT_POINTERDOWN (line 1111) | const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$a}`;
constant EVENT_POINTERUP (line 1112) | const EVENT_POINTERUP = `pointerup${EVENT_KEY$a}`;
constant EVENT_DRAG_START (line 1113) | const EVENT_DRAG_START = `dragstart${EVENT_KEY$a}`;
constant CLASS_NAME_CAROUSEL (line 1116) | const CLASS_NAME_CAROUSEL = 'carousel';
constant CLASS_NAME_SLIDE (line 1118) | const CLASS_NAME_SLIDE = 'slide';
constant CLASS_NAME_END (line 1119) | const CLASS_NAME_END = 'carousel-item-end';
constant CLASS_NAME_START (line 1120) | const CLASS_NAME_START = 'carousel-item-start';
constant CLASS_NAME_NEXT (line 1121) | const CLASS_NAME_NEXT = 'carousel-item-next';
constant CLASS_NAME_PREV (line 1122) | const CLASS_NAME_PREV = 'carousel-item-prev';
constant CLASS_NAME_POINTER_EVENT (line 1123) | const CLASS_NAME_POINTER_EVENT = 'pointer-event';
constant SELECTOR_ACTIVE_ITEM (line 1125) | const SELECTOR_ACTIVE_ITEM = '.active.carousel-item';
constant SELECTOR_ITEM (line 1126) | const SELECTOR_ITEM = '.carousel-item';
constant SELECTOR_ITEM_IMG (line 1127) | const SELECTOR_ITEM_IMG = '.carousel-item img';
constant SELECTOR_NEXT_PREV (line 1128) | const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev';
constant SELECTOR_INDICATORS (line 1129) | const SELECTOR_INDICATORS = '.carousel-indicators';
constant SELECTOR_INDICATOR (line 1130) | const SELECTOR_INDICATOR = '[data-bs-target]';
constant SELECTOR_DATA_SLIDE (line 1131) | const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
constant SELECTOR_DATA_RIDE (line 1132) | const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
constant POINTER_TYPE_TOUCH (line 1133) | const POINTER_TYPE_TOUCH = 'touch';
constant POINTER_TYPE_PEN (line 1134) | const POINTER_TYPE_PEN = 'pen';
class Carousel (line 1141) | class Carousel extends BaseComponent {
method constructor (line 1142) | constructor(element, config) {
method Default (line 1161) | static get Default() {
method NAME (line 1165) | static get NAME() {
method next (line 1170) | next() {
method nextWhenVisible (line 1174) | nextWhenVisible() {
method prev (line 1182) | prev() {
method pause (line 1186) | pause(event) {
method cycle (line 1200) | cycle(event) {
method to (line 1217) | to(index) {
method _getConfig (line 1243) | _getConfig(config) {
method _handleSwipe (line 1252) | _handleSwipe() {
method _addEventListeners (line 1269) | _addEventListeners() {
method _addTouchEventListeners (line 1284) | _addTouchEventListeners() {
method _keydown (line 1339) | _keydown(event) {
method _getItemIndex (line 1353) | _getItemIndex(element) {
method _getItemByOrder (line 1358) | _getItemByOrder(order, activeElement) {
method _triggerSlideEvent (line 1363) | _triggerSlideEvent(relatedTarget, eventDirectionName) {
method _setActiveIndicatorElement (line 1376) | _setActiveIndicatorElement(element) {
method _updateInterval (line 1393) | _updateInterval() {
method _slide (line 1410) | _slide(directionOrOrder, element) {
method _directionToOrder (line 1494) | _directionToOrder(direction) {
method _orderToDirection (line 1506) | _orderToDirection(order) {
method carouselInterface (line 1519) | static carouselInterface(element, config) {
method jQueryInterface (line 1547) | static jQueryInterface(config) {
method dataApiClickHandler (line 1553) | static dataApiClickHandler(event) {
constant CLASS_NAME_COLLAPSE (line 1633) | const CLASS_NAME_COLLAPSE = 'collapse';
constant CLASS_NAME_COLLAPSING (line 1634) | const CLASS_NAME_COLLAPSING = 'collapsing';
constant CLASS_NAME_COLLAPSED (line 1635) | const CLASS_NAME_COLLAPSED = 'collapsed';
constant CLASS_NAME_HORIZONTAL (line 1636) | const CLASS_NAME_HORIZONTAL = 'collapse-horizontal';
constant WIDTH (line 1637) | const WIDTH = 'width';
constant HEIGHT (line 1638) | const HEIGHT = 'height';
constant SELECTOR_ACTIVES (line 1639) | const SELECTOR_ACTIVES = '.show, .collapsing';
class Collapse (line 1647) | class Collapse extends BaseComponent {
method constructor (line 1648) | constructor(element, config) {
method Default (line 1679) | static get Default() {
method NAME (line 1683) | static get NAME() {
method toggle (line 1688) | toggle() {
method show (line 1696) | show() {
method hide (line 1769) | hide() {
method _isShown (line 1817) | _isShown(element = this._element) {
method _getConfig (line 1822) | _getConfig(config) {
method _getDimension (line 1834) | _getDimension() {
method _initializeChildren (line 1838) | _initializeChildren() {
method _addAriaAndCollapsedClass (line 1853) | _addAriaAndCollapsedClass(triggerArray, isOpen) {
method jQueryInterface (line 1870) | static jQueryInterface(config) {
constant SPACE_KEY (line 1938) | const SPACE_KEY = 'Space';
constant ARROW_UP_KEY (line 1940) | const ARROW_UP_KEY = 'ArrowUp';
constant ARROW_DOWN_KEY (line 1941) | const ARROW_DOWN_KEY = 'ArrowDown';
constant RIGHT_MOUSE_BUTTON (line 1942) | const RIGHT_MOUSE_BUTTON = 2;
constant REGEXP_KEYDOWN (line 1944) | const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${E...
constant EVENT_KEYDOWN_DATA_API (line 1950) | const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$8}${DATA_API_KEY$4}`;
constant EVENT_KEYUP_DATA_API (line 1951) | const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$8}${DATA_API_KEY$4}`;
constant CLASS_NAME_DROPUP (line 1953) | const CLASS_NAME_DROPUP = 'dropup';
constant CLASS_NAME_DROPEND (line 1954) | const CLASS_NAME_DROPEND = 'dropend';
constant CLASS_NAME_DROPSTART (line 1955) | const CLASS_NAME_DROPSTART = 'dropstart';
constant CLASS_NAME_NAVBAR (line 1956) | const CLASS_NAME_NAVBAR = 'navbar';
constant SELECTOR_MENU (line 1958) | const SELECTOR_MENU = '.dropdown-menu';
constant SELECTOR_NAVBAR_NAV (line 1959) | const SELECTOR_NAVBAR_NAV = '.navbar-nav';
constant SELECTOR_VISIBLE_ITEMS (line 1960) | const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disab...
constant PLACEMENT_TOP (line 1961) | const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';
constant PLACEMENT_TOPEND (line 1962) | const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';
constant PLACEMENT_BOTTOM (line 1963) | const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';
constant PLACEMENT_BOTTOMEND (line 1964) | const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';
constant PLACEMENT_RIGHT (line 1965) | const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';
constant PLACEMENT_LEFT (line 1966) | const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';
class Dropdown (line 1989) | class Dropdown extends BaseComponent {
method constructor (line 1990) | constructor(element, config) {
method Default (line 1999) | static get Default() {
method DefaultType (line 2003) | static get DefaultType() {
method NAME (line 2007) | static get NAME() {
method toggle (line 2012) | toggle() {
method show (line 2016) | show() {
method hide (line 2057) | hide() {
method dispose (line 2069) | dispose() {
method update (line 2077) | update() {
method _completeHide (line 2086) | _completeHide(relatedTarget) {
method _getConfig (line 2113) | _getConfig(config) {
method _createPopper (line 2128) | _createPopper(parent) {
method _isShown (line 2153) | _isShown(element = this._element) {
method _getMenuElement (line 2157) | _getMenuElement() {
method _getPlacement (line 2161) | _getPlacement() {
method _detectNavbar (line 2182) | _detectNavbar() {
method _getOffset (line 2186) | _getOffset() {
method _getPopperConfig (line 2202) | _getPopperConfig() {
method _selectMenuItem (line 2230) | _selectMenuItem({
method jQueryInterface (line 2246) | static jQueryInterface(config) {
method clearMenus (line 2262) | static clearMenus(event) {
method getParentFromElement (line 2306) | static getParentFromElement(element) {
method dataApiKeydownHandler (line 2310) | static dataApiKeydownHandler(event) {
constant SELECTOR_FIXED_CONTENT (line 2389) | const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .s...
constant SELECTOR_STICKY_CONTENT (line 2390) | const SELECTOR_STICKY_CONTENT = '.sticky-top';
class ScrollBarHelper (line 2392) | class ScrollBarHelper {
method constructor (line 2393) | constructor() {
method getWidth (line 2397) | getWidth() {
method hide (line 2403) | hide() {
method _disableOverFlow (line 2417) | _disableOverFlow() {
method _setElementAttributes (line 2423) | _setElementAttributes(selector, styleProp, callback) {
method reset (line 2440) | reset() {
method _saveInitialAttribute (line 2450) | _saveInitialAttribute(element, styleProp) {
method _resetElementAttributes (line 2458) | _resetElementAttributes(selector, styleProp) {
method _applyManipulationCallback (line 2473) | _applyManipulationCallback(selector, callBack) {
method isOverflowing (line 2481) | isOverflowing() {
constant EVENT_MOUSEDOWN (line 2512) | const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$8}`;
class Backdrop (line 2514) | class Backdrop {
method constructor (line 2515) | constructor(config) {
method show (line 2521) | show(callback) {
method hide (line 2540) | hide(callback) {
method _getElement (line 2555) | _getElement() {
method _getConfig (line 2570) | _getConfig(config) {
method _append (line 2580) | _append() {
method dispose (line 2593) | dispose() {
method _emulateAnimation (line 2605) | _emulateAnimation(callback) {
constant EVENT_KEYDOWN_TAB (line 2630) | const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$7}`;
constant TAB_KEY (line 2631) | const TAB_KEY = 'Tab';
constant TAB_NAV_FORWARD (line 2632) | const TAB_NAV_FORWARD = 'forward';
constant TAB_NAV_BACKWARD (line 2633) | const TAB_NAV_BACKWARD = 'backward';
class FocusTrap (line 2635) | class FocusTrap {
method constructor (line 2636) | constructor(config) {
method activate (line 2642) | activate() {
method deactivate (line 2663) | deactivate() {
method _handleFocusin (line 2673) | _handleFocusin(event) {
method _handleKeydown (line 2696) | _handleKeydown(event) {
method _getConfig (line 2704) | _getConfig(config) {
constant EVENT_HIDE_PREVENTED (line 2742) | const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$6}`;
constant EVENT_RESIZE (line 2746) | const EVENT_RESIZE = `resize${EVENT_KEY$6}`;
constant EVENT_CLICK_DISMISS (line 2747) | const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$6}`;
constant EVENT_MOUSEUP_DISMISS (line 2749) | const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY$6}`;
constant EVENT_MOUSEDOWN_DISMISS (line 2750) | const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$6}`;
constant CLASS_NAME_OPEN (line 2752) | const CLASS_NAME_OPEN = 'modal-open';
constant CLASS_NAME_STATIC (line 2755) | const CLASS_NAME_STATIC = 'modal-static';
constant SELECTOR_DIALOG (line 2756) | const SELECTOR_DIALOG = '.modal-dialog';
constant SELECTOR_MODAL_BODY (line 2757) | const SELECTOR_MODAL_BODY = '.modal-body';
class Modal (line 2765) | class Modal extends BaseComponent {
method constructor (line 2766) | constructor(element, config) {
method Default (line 2779) | static get Default() {
method NAME (line 2783) | static get NAME() {
method toggle (line 2788) | toggle(relatedTarget) {
method show (line 2792) | show(relatedTarget) {
method hide (line 2832) | hide() {
method dispose (line 2865) | dispose() {
method handleUpdate (line 2875) | handleUpdate() {
method _initializeBackDrop (line 2880) | _initializeBackDrop() {
method _initializeFocusTrap (line 2888) | _initializeFocusTrap() {
method _getConfig (line 2894) | _getConfig(config) {
method _showElement (line 2903) | _showElement(relatedTarget) {
method _setEscapeEvent (line 2947) | _setEscapeEvent() {
method _setResizeEvent (line 2962) | _setResizeEvent() {
method _hideModal (line 2970) | _hideModal() {
method _showBackdrop (line 2992) | _showBackdrop(callback) {
method _isAnimated (line 3013) | _isAnimated() {
method _triggerBackdropTransition (line 3017) | _triggerBackdropTransition() {
method _adjustDialog (line 3057) | _adjustDialog() {
method _resetAdjustments (line 3073) | _resetAdjustments() {
method jQueryInterface (line 3079) | static jQueryInterface(config, relatedTarget) {
constant ESCAPE_KEY (line 3152) | const ESCAPE_KEY = 'Escape';
constant CLASS_NAME_BACKDROP (line 3164) | const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
constant OPEN_SELECTOR (line 3165) | const OPEN_SELECTOR = '.offcanvas.show';
constant EVENT_KEYDOWN_DISMISS (line 3171) | const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$5}`;
class Offcanvas (line 3179) | class Offcanvas extends BaseComponent {
method constructor (line 3180) | constructor(element, config) {
method NAME (line 3191) | static get NAME() {
method Default (line 3195) | static get Default() {
method toggle (line 3200) | toggle(relatedTarget) {
method show (line 3204) | show(relatedTarget) {
method hide (line 3247) | hide() {
method dispose (line 3287) | dispose() {
method _getConfig (line 3296) | _getConfig(config) {
method _initializeBackDrop (line 3305) | _initializeBackDrop() {
method _initializeFocusTrap (line 3315) | _initializeFocusTrap() {
method _addEventListeners (line 3321) | _addEventListeners() {
method jQueryInterface (line 3330) | static jQueryInterface(config) {
constant ARIA_ATTRIBUTE_PATTERN (line 3398) | const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
constant SAFE_URL_PATTERN (line 3405) | const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(...
constant DATA_URL_PATTERN (line 3412) | const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|w...
function sanitizeHtml (line 3469) | function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
constant DISALLOWED_ATTRIBUTES (line 3520) | const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitiz...
constant CLASS_NAME_MODAL (line 3579) | const CLASS_NAME_MODAL = 'modal';
constant HOVER_STATE_SHOW (line 3581) | const HOVER_STATE_SHOW = 'show';
constant HOVER_STATE_OUT (line 3582) | const HOVER_STATE_OUT = 'out';
constant SELECTOR_TOOLTIP_INNER (line 3583) | const SELECTOR_TOOLTIP_INNER = '.tooltip-inner';
constant SELECTOR_MODAL (line 3584) | const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;
constant EVENT_MODAL_HIDE (line 3585) | const EVENT_MODAL_HIDE = 'hide.bs.modal';
constant TRIGGER_HOVER (line 3586) | const TRIGGER_HOVER = 'hover';
constant TRIGGER_FOCUS (line 3587) | const TRIGGER_FOCUS = 'focus';
constant TRIGGER_CLICK (line 3588) | const TRIGGER_CLICK = 'click';
constant TRIGGER_MANUAL (line 3589) | const TRIGGER_MANUAL = 'manual';
class Tooltip (line 3596) | class Tooltip extends BaseComponent {
method constructor (line 3597) | constructor(element, config) {
method Default (line 3617) | static get Default() {
method NAME (line 3621) | static get NAME() {
method Event (line 3625) | static get Event() {
method DefaultType (line 3629) | static get DefaultType() {
method enable (line 3634) | enable() {
method disable (line 3638) | disable() {
method toggleEnabled (line 3642) | toggleEnabled() {
method toggle (line 3646) | toggle(event) {
method dispose (line 3672) | dispose() {
method show (line 3687) | show() {
method hide (line 3769) | hide() {
method update (line 3821) | update() {
method isWithContent (line 3828) | isWithContent() {
method getTipElement (line 3832) | getTipElement() {
method setContent (line 3846) | setContent(tip) {
method _sanitizeAndSetContent (line 3850) | _sanitizeAndSetContent(template, content, selector) {
method setElementContent (line 3862) | setElementContent(element, content) {
method getTitle (line 3893) | getTitle() {
method updateAttachment (line 3899) | updateAttachment(attachment) {
method _initializeOnDelegatedTarget (line 3912) | _initializeOnDelegatedTarget(event, context) {
method _getOffset (line 3916) | _getOffset() {
method _resolvePossibleFunction (line 3932) | _resolvePossibleFunction(content) {
method _getPopperConfig (line 3936) | _getPopperConfig(attachment) {
method _addAttachmentClass (line 3976) | _addAttachmentClass(attachment) {
method _getAttachment (line 3980) | _getAttachment(placement) {
method _setListeners (line 3984) | _setListeners() {
method _fixTitle (line 4016) | _fixTitle() {
method _enter (line 4032) | _enter(event, context) {
method _leave (line 4059) | _leave(event, context) {
method _isWithActiveTrigger (line 4085) | _isWithActiveTrigger() {
method _getConfig (line 4095) | _getConfig(config) {
method _getDelegateConfig (line 4132) | _getDelegateConfig() {
method _cleanTipClass (line 4147) | _cleanTipClass() {
method _getBasicClassPrefix (line 4157) | _getBasicClassPrefix() {
method _handlePopperPlacementChange (line 4161) | _handlePopperPlacementChange(popperData) {
method jQueryInterface (line 4178) | static jQueryInterface(config) {
constant CLASS_PREFIX (line 4218) | const CLASS_PREFIX = 'bs-popover';
constant SELECTOR_TITLE (line 4241) | const SELECTOR_TITLE = '.popover-header';
constant SELECTOR_CONTENT (line 4242) | const SELECTOR_CONTENT = '.popover-body';
class Popover (line 4249) | class Popover extends Tooltip {
method Default (line 4251) | static get Default() {
method NAME (line 4255) | static get NAME() {
method Event (line 4259) | static get Event() {
method DefaultType (line 4263) | static get DefaultType() {
method isWithContent (line 4268) | isWithContent() {
method setContent (line 4272) | setContent(tip) {
method _getContent (line 4279) | _getContent() {
method _getBasicClassPrefix (line 4283) | _getBasicClassPrefix() {
method jQueryInterface (line 4288) | static jQueryInterface(config) {
constant EVENT_ACTIVATE (line 4339) | const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;
constant EVENT_SCROLL (line 4340) | const EVENT_SCROLL = `scroll${EVENT_KEY$2}`;
constant EVENT_LOAD_DATA_API (line 4341) | const EVENT_LOAD_DATA_API = `load${EVENT_KEY$2}${DATA_API_KEY$1}`;
constant CLASS_NAME_DROPDOWN_ITEM (line 4342) | const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
constant SELECTOR_DATA_SPY (line 4344) | const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
constant SELECTOR_NAV_LINKS (line 4346) | const SELECTOR_NAV_LINKS = '.nav-link';
constant SELECTOR_NAV_ITEMS (line 4347) | const SELECTOR_NAV_ITEMS = '.nav-item';
constant SELECTOR_LIST_ITEMS (line 4348) | const SELECTOR_LIST_ITEMS = '.list-group-item';
constant SELECTOR_LINK_ITEMS (line 4349) | const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEM...
constant METHOD_OFFSET (line 4352) | const METHOD_OFFSET = 'offset';
constant METHOD_POSITION (line 4353) | const METHOD_POSITION = 'position';
class ScrollSpy (line 4360) | class ScrollSpy extends BaseComponent {
method constructor (line 4361) | constructor(element, config) {
method Default (line 4376) | static get Default() {
method NAME (line 4380) | static get NAME() {
method refresh (line 4385) | refresh() {
method dispose (line 4413) | dispose() {
method _getConfig (line 4419) | _getConfig(config) {
method _getScrollTop (line 4429) | _getScrollTop() {
method _getScrollHeight (line 4433) | _getScrollHeight() {
method _getOffsetHeight (line 4437) | _getOffsetHeight() {
method _process (line 4441) | _process() {
method _activate (line 4479) | _activate(target) {
method _clear (line 4507) | _clear() {
method jQueryInterface (line 4512) | static jQueryInterface(config) {
constant DATA_API_KEY (line 4563) | const DATA_API_KEY = '.data-api';
constant EVENT_CLICK_DATA_API (line 4568) | const EVENT_CLICK_DATA_API = `click${EVENT_KEY$1}${DATA_API_KEY}`;
constant CLASS_NAME_DROPDOWN_MENU (line 4569) | const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';
constant CLASS_NAME_ACTIVE (line 4570) | const CLASS_NAME_ACTIVE = 'active';
constant SELECTOR_DROPDOWN (line 4573) | const SELECTOR_DROPDOWN = '.dropdown';
constant SELECTOR_NAV_LIST_GROUP (line 4574) | const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
constant SELECTOR_ACTIVE (line 4575) | const SELECTOR_ACTIVE = '.active';
constant SELECTOR_ACTIVE_UL (line 4576) | const SELECTOR_ACTIVE_UL = ':scope > li > .active';
constant SELECTOR_DATA_TOGGLE (line 4577) | const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="p...
constant SELECTOR_DROPDOWN_TOGGLE (line 4578) | const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
constant SELECTOR_DROPDOWN_ACTIVE_CHILD (line 4579) | const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active';
class Tab (line 4586) | class Tab extends BaseComponent {
method NAME (line 4588) | static get NAME() {
method show (line 4593) | show() {
method _activate (line 4639) | _activate(element, container, callback) {
method _transitionComplete (line 4655) | _transitionComplete(element, active, callback) {
method jQueryInterface (line 4703) | static jQueryInterface(config) {
constant NAME (line 4758) | const NAME = 'toast';
constant DATA_KEY (line 4759) | const DATA_KEY = 'bs.toast';
constant EVENT_KEY (line 4760) | const EVENT_KEY = `.${DATA_KEY}`;
constant EVENT_MOUSEOVER (line 4761) | const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`;
constant EVENT_MOUSEOUT (line 4762) | const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`;
constant EVENT_FOCUSIN (line 4763) | const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
constant EVENT_FOCUSOUT (line 4764) | const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`;
constant EVENT_HIDE (line 4765) | const EVENT_HIDE = `hide${EVENT_KEY}`;
constant EVENT_HIDDEN (line 4766) | const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
constant EVENT_SHOW (line 4767) | const EVENT_SHOW = `show${EVENT_KEY}`;
constant EVENT_SHOWN (line 4768) | const EVENT_SHOWN = `shown${EVENT_KEY}`;
constant CLASS_NAME_FADE (line 4769) | const CLASS_NAME_FADE = 'fade';
constant CLASS_NAME_HIDE (line 4770) | const CLASS_NAME_HIDE = 'hide';
constant CLASS_NAME_SHOW (line 4772) | const CLASS_NAME_SHOW = 'show';
constant CLASS_NAME_SHOWING (line 4773) | const CLASS_NAME_SHOWING = 'showing';
class Toast (line 4790) | class Toast extends BaseComponent {
method constructor (line 4791) | constructor(element, config) {
method DefaultType (line 4802) | static get DefaultType() {
method Default (line 4806) | static get Default() {
method NAME (line 4810) | static get NAME() {
method show (line 4815) | show() {
method hide (line 4848) | hide() {
method dispose (line 4875) | dispose() {
method _getConfig (line 4886) | _getConfig(config) {
method _maybeScheduleHide (line 4895) | _maybeScheduleHide() {
method _onInteraction (line 4909) | _onInteraction(event, isInteracting) {
method _setListeners (line 4937) | _setListeners() {
method _clearTimeout (line 4944) | _clearTimeout() {
method jQueryInterface (line 4950) | static jQueryInterface(config) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.js
function _interopNamespace (line 12) | function _interopNamespace(e) {
function getUidEvent (line 375) | function getUidEvent(element, uid) {
function getEvent (line 379) | function getEvent(element) {
function bootstrapHandler (line 386) | function bootstrapHandler(element, fn) {
function bootstrapDelegationHandler (line 398) | function bootstrapDelegationHandler(element, selector, fn) {
function findHandler (line 424) | function findHandler(events, handler, delegationSelector = null) {
function normalizeParams (line 438) | function normalizeParams(originalTypeEvent, handler, delegationFn) {
function addHandler (line 451) | function addHandler(element, originalTypeEvent, handler, delegationFn, o...
function removeHandler (line 499) | function removeHandler(element, events, typeEvent, handler, delegationSe...
function removeNamespacedHandlers (line 510) | function removeNamespacedHandlers(element, events, typeEvent, namespace) {
function getTypeEvent (line 520) | function getTypeEvent(event) {
method on (line 527) | on(element, event, handler, delegationFn) {
method one (line 531) | one(element, event, handler, delegationFn) {
method off (line 535) | off(element, originalTypeEvent, handler, delegationFn) {
method trigger (line 572) | trigger(element, event, args) {
method set (line 648) | set(element, key, instance) {
method get (line 665) | get(element, key) {
method remove (line 673) | remove(element, key) {
class BaseComponent (line 702) | class BaseComponent {
method constructor (line 703) | constructor(element) {
method dispose (line 714) | dispose() {
method _queueCallback (line 722) | _queueCallback(callback, element, isAnimated = true) {
method getInstance (line 728) | static getInstance(element) {
method getOrCreateInstance (line 732) | static getOrCreateInstance(element, config = {}) {
method VERSION (line 736) | static get VERSION() {
method NAME (line 740) | static get NAME() {
method DATA_KEY (line 744) | static get DATA_KEY() {
method EVENT_KEY (line 748) | static get EVENT_KEY() {
class Alert (line 805) | class Alert extends BaseComponent {
method NAME (line 807) | static get NAME() {
method close (line 812) | close() {
method _destroyElement (line 827) | _destroyElement() {
method jQueryInterface (line 835) | static jQueryInterface(config) {
class Button (line 894) | class Button extends BaseComponent {
method NAME (line 896) | static get NAME() {
method toggle (line 901) | toggle() {
method jQueryInterface (line 907) | static jQueryInterface(config) {
function normalizeData (line 946) | function normalizeData(val) {
function normalizeDataKey (line 966) | function normalizeDataKey(key) {
method setDataAttribute (line 971) | setDataAttribute(element, key, value) {
method removeDataAttribute (line 975) | removeDataAttribute(element, key) {
method getDataAttributes (line 979) | getDataAttributes(element) {
method getDataAttribute (line 993) | getDataAttribute(element, key) {
method offset (line 997) | offset(element) {
method position (line 1005) | position(element) {
method find (line 1022) | find(selector, element = document.documentElement) {
method findOne (line 1026) | findOne(selector, element = document.documentElement) {
method children (line 1030) | children(element, selector) {
method parents (line 1034) | parents(element, selector) {
method prev (line 1049) | prev(element, selector) {
method next (line 1063) | next(element, selector) {
method focusableChildren (line 1077) | focusableChildren(element) {
class Carousel (line 1167) | class Carousel extends BaseComponent {
method constructor (line 1168) | constructor(element, config) {
method Default (line 1187) | static get Default() {
method NAME (line 1191) | static get NAME() {
method next (line 1196) | next() {
method nextWhenVisible (line 1200) | nextWhenVisible() {
method prev (line 1208) | prev() {
method pause (line 1212) | pause(event) {
method cycle (line 1226) | cycle(event) {
method to (line 1243) | to(index) {
method _getConfig (line 1269) | _getConfig(config) {
method _handleSwipe (line 1278) | _handleSwipe() {
method _addEventListeners (line 1295) | _addEventListeners() {
method _addTouchEventListeners (line 1310) | _addTouchEventListeners() {
method _keydown (line 1365) | _keydown(event) {
method _getItemIndex (line 1379) | _getItemIndex(element) {
method _getItemByOrder (line 1384) | _getItemByOrder(order, activeElement) {
method _triggerSlideEvent (line 1389) | _triggerSlideEvent(relatedTarget, eventDirectionName) {
method _setActiveIndicatorElement (line 1402) | _setActiveIndicatorElement(element) {
method _updateInterval (line 1419) | _updateInterval() {
method _slide (line 1436) | _slide(directionOrOrder, element) {
method _directionToOrder (line 1520) | _directionToOrder(direction) {
method _orderToDirection (line 1532) | _orderToDirection(order) {
method carouselInterface (line 1545) | static carouselInterface(element, config) {
method jQueryInterface (line 1573) | static jQueryInterface(config) {
method dataApiClickHandler (line 1579) | static dataApiClickHandler(event) {
class Collapse (line 1673) | class Collapse extends BaseComponent {
method constructor (line 1674) | constructor(element, config) {
method Default (line 1705) | static get Default() {
method NAME (line 1709) | static get NAME() {
method toggle (line 1714) | toggle() {
method show (line 1722) | show() {
method hide (line 1795) | hide() {
method _isShown (line 1843) | _isShown(element = this._element) {
method _getConfig (line 1848) | _getConfig(config) {
method _getDimension (line 1860) | _getDimension() {
method _initializeChildren (line 1864) | _initializeChildren() {
method _addAriaAndCollapsedClass (line 1879) | _addAriaAndCollapsedClass(triggerArray, isOpen) {
method jQueryInterface (line 1896) | static jQueryInterface(config) {
class Dropdown (line 2015) | class Dropdown extends BaseComponent {
method constructor (line 2016) | constructor(element, config) {
method Default (line 2025) | static get Default() {
method DefaultType (line 2029) | static get DefaultType() {
method NAME (line 2033) | static get NAME() {
method toggle (line 2038) | toggle() {
method show (line 2042) | show() {
method hide (line 2083) | hide() {
method dispose (line 2095) | dispose() {
method update (line 2103) | update() {
method _completeHide (line 2112) | _completeHide(relatedTarget) {
method _getConfig (line 2139) | _getConfig(config) {
method _createPopper (line 2154) | _createPopper(parent) {
method _isShown (line 2179) | _isShown(element = this._element) {
method _getMenuElement (line 2183) | _getMenuElement() {
method _getPlacement (line 2187) | _getPlacement() {
method _detectNavbar (line 2208) | _detectNavbar() {
method _getOffset (line 2212) | _getOffset() {
method _getPopperConfig (line 2228) | _getPopperConfig() {
method _selectMenuItem (line 2256) | _selectMenuItem({
method jQueryInterface (line 2272) | static jQueryInterface(config) {
method clearMenus (line 2288) | static clearMenus(event) {
method getParentFromElement (line 2332) | static getParentFromElement(element) {
method dataApiKeydownHandler (line 2336) | static dataApiKeydownHandler(event) {
class ScrollBarHelper (line 2418) | class ScrollBarHelper {
method constructor (line 2419) | constructor() {
method getWidth (line 2423) | getWidth() {
method hide (line 2429) | hide() {
method _disableOverFlow (line 2443) | _disableOverFlow() {
method _setElementAttributes (line 2449) | _setElementAttributes(selector, styleProp, callback) {
method reset (line 2466) | reset() {
method _saveInitialAttribute (line 2476) | _saveInitialAttribute(element, styleProp) {
method _resetElementAttributes (line 2484) | _resetElementAttributes(selector, styleProp) {
method _applyManipulationCallback (line 2499) | _applyManipulationCallback(selector, callBack) {
method isOverflowing (line 2507) | isOverflowing() {
class Backdrop (line 2540) | class Backdrop {
method constructor (line 2541) | constructor(config) {
method show (line 2547) | show(callback) {
method hide (line 2566) | hide(callback) {
method _getElement (line 2581) | _getElement() {
method _getConfig (line 2596) | _getConfig(config) {
method _append (line 2606) | _append() {
method dispose (line 2619) | dispose() {
method _emulateAnimation (line 2631) | _emulateAnimation(callback) {
class FocusTrap (line 2661) | class FocusTrap {
method constructor (line 2662) | constructor(config) {
method activate (line 2668) | activate() {
method deactivate (line 2689) | deactivate() {
method _handleFocusin (line 2699) | _handleFocusin(event) {
method _handleKeydown (line 2722) | _handleKeydown(event) {
method _getConfig (line 2730) | _getConfig(config) {
class Modal (line 2791) | class Modal extends BaseComponent {
method constructor (line 2792) | constructor(element, config) {
method Default (line 2805) | static get Default() {
method NAME (line 2809) | static get NAME() {
method toggle (line 2814) | toggle(relatedTarget) {
method show (line 2818) | show(relatedTarget) {
method hide (line 2858) | hide() {
method dispose (line 2891) | dispose() {
method handleUpdate (line 2901) | handleUpdate() {
method _initializeBackDrop (line 2906) | _initializeBackDrop() {
method _initializeFocusTrap (line 2914) | _initializeFocusTrap() {
method _getConfig (line 2920) | _getConfig(config) {
method _showElement (line 2929) | _showElement(relatedTarget) {
method _setEscapeEvent (line 2973) | _setEscapeEvent() {
method _setResizeEvent (line 2988) | _setResizeEvent() {
method _hideModal (line 2996) | _hideModal() {
method _showBackdrop (line 3018) | _showBackdrop(callback) {
method _isAnimated (line 3039) | _isAnimated() {
method _triggerBackdropTransition (line 3043) | _triggerBackdropTransition() {
method _adjustDialog (line 3083) | _adjustDialog() {
method _resetAdjustments (line 3099) | _resetAdjustments() {
method jQueryInterface (line 3105) | static jQueryInterface(config, relatedTarget) {
class Offcanvas (line 3205) | class Offcanvas extends BaseComponent {
method constructor (line 3206) | constructor(element, config) {
method NAME (line 3217) | static get NAME() {
method Default (line 3221) | static get Default() {
method toggle (line 3226) | toggle(relatedTarget) {
method show (line 3230) | show(relatedTarget) {
method hide (line 3273) | hide() {
method dispose (line 3313) | dispose() {
method _getConfig (line 3322) | _getConfig(config) {
method _initializeBackDrop (line 3331) | _initializeBackDrop() {
method _initializeFocusTrap (line 3341) | _initializeFocusTrap() {
method _addEventListeners (line 3347) | _addEventListeners() {
method jQueryInterface (line 3356) | static jQueryInterface(config) {
function sanitizeHtml (line 3495) | function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
class Tooltip (line 3622) | class Tooltip extends BaseComponent {
method constructor (line 3623) | constructor(element, config) {
method Default (line 3643) | static get Default() {
method NAME (line 3647) | static get NAME() {
method Event (line 3651) | static get Event() {
method DefaultType (line 3655) | static get DefaultType() {
method enable (line 3660) | enable() {
method disable (line 3664) | disable() {
method toggleEnabled (line 3668) | toggleEnabled() {
method toggle (line 3672) | toggle(event) {
method dispose (line 3698) | dispose() {
method show (line 3713) | show() {
method hide (line 3795) | hide() {
method update (line 3847) | update() {
method isWithContent (line 3854) | isWithContent() {
method getTipElement (line 3858) | getTipElement() {
method setContent (line 3872) | setContent(tip) {
method _sanitizeAndSetContent (line 3876) | _sanitizeAndSetContent(template, content, selector) {
method setElementContent (line 3888) | setElementContent(element, content) {
method getTitle (line 3919) | getTitle() {
method updateAttachment (line 3925) | updateAttachment(attachment) {
method _initializeOnDelegatedTarget (line 3938) | _initializeOnDelegatedTarget(event, context) {
method _getOffset (line 3942) | _getOffset() {
method _resolvePossibleFunction (line 3958) | _resolvePossibleFunction(content) {
method _getPopperConfig (line 3962) | _getPopperConfig(attachment) {
method _addAttachmentClass (line 4002) | _addAttachmentClass(attachment) {
method _getAttachment (line 4006) | _getAttachment(placement) {
method _setListeners (line 4010) | _setListeners() {
method _fixTitle (line 4042) | _fixTitle() {
method _enter (line 4058) | _enter(event, context) {
method _leave (line 4085) | _leave(event, context) {
method _isWithActiveTrigger (line 4111) | _isWithActiveTrigger() {
method _getConfig (line 4121) | _getConfig(config) {
method _getDelegateConfig (line 4158) | _getDelegateConfig() {
method _cleanTipClass (line 4173) | _cleanTipClass() {
method _getBasicClassPrefix (line 4183) | _getBasicClassPrefix() {
method _handlePopperPlacementChange (line 4187) | _handlePopperPlacementChange(popperData) {
method jQueryInterface (line 4204) | static jQueryInterface(config) {
class Popover (line 4275) | class Popover extends Tooltip {
method Default (line 4277) | static get Default() {
method NAME (line 4281) | static get NAME() {
method Event (line 4285) | static get Event() {
method DefaultType (line 4289) | static get DefaultType() {
method isWithContent (line 4294) | isWithContent() {
method setContent (line 4298) | setContent(tip) {
method _getContent (line 4305) | _getContent() {
method _getBasicClassPrefix (line 4309) | _getBasicClassPrefix() {
method jQueryInterface (line 4314) | static jQueryInterface(config) {
class ScrollSpy (line 4386) | class ScrollSpy extends BaseComponent {
method constructor (line 4387) | constructor(element, config) {
method Default (line 4402) | static get Default() {
method NAME (line 4406) | static get NAME() {
method refresh (line 4411) | refresh() {
method dispose (line 4439) | dispose() {
method _getConfig (line 4445) | _getConfig(config) {
method _getScrollTop (line 4455) | _getScrollTop() {
method _getScrollHeight (line 4459) | _getScrollHeight() {
method _getOffsetHeight (line 4463) | _getOffsetHeight() {
method _process (line 4467) | _process() {
method _activate (line 4505) | _activate(target) {
method _clear (line 4533) | _clear() {
method jQueryInterface (line 4538) | static jQueryInterface(config) {
class Tab (line 4612) | class Tab extends BaseComponent {
method NAME (line 4614) | static get NAME() {
method show (line 4619) | show() {
method _activate (line 4665) | _activate(element, container, callback) {
method _transitionComplete (line 4681) | _transitionComplete(element, active, callback) {
method jQueryInterface (line 4729) | static jQueryInterface(config) {
class Toast (line 4816) | class Toast extends BaseComponent {
method constructor (line 4817) | constructor(element, config) {
method DefaultType (line 4828) | static get DefaultType() {
method Default (line 4832) | static get Default() {
method NAME (line 4836) | static get NAME() {
method show (line 4841) | show() {
method hide (line 4874) | hide() {
method dispose (line 4901) | dispose() {
method _getConfig (line 4912) | _getConfig(config) {
method _maybeScheduleHide (line 4921) | _maybeScheduleHide() {
method _onInteraction (line 4935) | _onInteraction(event, isInteracting) {
method _setListeners (line 4963) | _setListeners() {
method _clearTimeout (line 4970) | _clearTimeout() {
method jQueryInterface (line 4976) | static jQueryInterface(config) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js
function setValidationValues (line 25) | function setValidationValues(options, ruleName, value) {
function splitAndTrim (line 32) | function splitAndTrim(value) {
function escapeAttributeValue (line 36) | function escapeAttributeValue(value) {
function getModelPrefix (line 41) | function getModelPrefix(fieldName) {
function appendModelPrefix (line 45) | function appendModelPrefix(value, prefix) {
function onError (line 52) | function onError(error, inputElement) { // 'this' is the form element
function onErrors (line 69) | function onErrors(event, validator) { // 'this' is the form element
function onSuccess (line 83) | function onSuccess(error) { // 'this' is the form element
function onReset (line 99) | function onReset(event) { // 'this' is the form element
function validationInfo (line 124) | function validationInfo(form) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/jquery-validation/dist/additional-methods.js
function stripHtml (line 21) | function stripHtml( value ) {
function isOdd (line 212) | function isOdd( n ) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.js
function handle (line 70) | function handle() {
function delegate (line 411) | function delegate( event ) {
FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/jquery/dist/jquery.js
function DOMEval (line 103) | function DOMEval( code, node, doc ) {
function toType (line 133) | function toType( obj ) {
function isArrayLike (line 503) | function isArrayLike( obj ) {
function Sizzle (line 755) | function Sizzle( selector, context, results, seed ) {
function createCache (line 903) | function createCache() {
function markFunction (line 923) | function markFunction( fn ) {
function assert (line 932) | function assert( fn ) {
function addHandle (line 956) | function addHandle( attrs, handler ) {
function siblingCheck (line 971) | function siblingCheck( a, b ) {
function createInputPseudo (line 997) | function createInputPseudo( type ) {
function createButtonPseudo (line 1008) | function createButtonPseudo( type ) {
function createDisabledPseudo (line 1019) | function createDisabledPseudo( disabled ) {
function createPositionalPseudo (line 1075) | function createPositionalPseudo( fn ) {
function testContext (line 1098) | function testContext( context ) {
function setFilters (line 2309) | function setFilters() {}
function toSelector (line 2383) | function toSelector( tokens ) {
function addCombinator (line 2393) | function addCombinator( matcher, combinator, base ) {
function elementMatcher (line 2460) | function elementMatcher( matchers ) {
function multipleContexts (line 2474) | function multipleContexts( selector, contexts, results ) {
function condense (line 2483) | function condense( unmatched, map, filter, context, xml ) {
function setMatcher (line 2504) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
function matcherFromTokens (line 2604) | function matcherFromTokens( tokens ) {
function matcherFromGroupMatchers (line 2667) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
function nodeName (line 3025) | function nodeName( elem, name ) {
function winnow (line 3035) | function winnow( elements, qualifier, not ) {
function sibling (line 3330) | function sibling( cur, dir ) {
function createOptions (line 3423) | function createOptions( options ) {
function Identity (line 3648) | function Identity( v ) {
function Thrower (line 3651) | function Thrower( ex ) {
function adoptValue (line 3655) | function adoptValue( value, resolve, reject, noValue ) {
function resolve (line 3748) | function resolve( depth, deferred, handler, special ) {
function completed (line 4113) | function completed() {
function fcamelCase (line 4208) | function fcamelCase( _all, letter ) {
function camelCase (line 4215) | function camelCase( string ) {
function Data (line 4232) | function Data() {
function getData (line 4401) | function getData( data ) {
function dataAttr (line 4426) | function dataAttr( elem, key, data ) {
function adjustCSS (line 4738) | function adjustCSS( elem, prop, valueParts, tween ) {
function getDefaultDisplay (line 4806) | function getDefaultDisplay( elem ) {
function showHide (line 4829) | function showHide( elements, show ) {
function getAll (line 4961) | function getAll( context, tag ) {
function setGlobalEval (line 4986) | function setGlobalEval( elems, refElements ) {
function buildFragment (line 5002) | function buildFragment( elems, context, scripts, selection, ignored ) {
function returnTrue (line 5097) | function returnTrue() {
function returnFalse (line 5101) | function returnFalse() {
function expectSync (line 5111) | function expectSync( elem, type ) {
function safeActiveElement (line 5118) | function safeActiveElement() {
function on (line 5124) | function on( elem, types, selector, data, fn, one ) {
function leverageNative (line 5612) | function leverageNative( el, type, expectSync ) {
function manipulationTarget (line 5976) | function manipulationTarget( elem, content ) {
function disableScript (line 5987) | function disableScript( elem ) {
function restoreScript (line 5991) | function restoreScript( elem ) {
function cloneCopyEvent (line 6001) | function cloneCopyEvent( src, dest ) {
function fixInput (line 6034) | function fixInput( src, dest ) {
function domManip (line 6047) | function domManip( collection, args, callback, ignored ) {
function remove (line 6139) | function remove( elem, selector, keepData ) {
function computeStyleTests (line 6453) | function computeStyleTests() {
function roundPixelMeasures (line 6497) | function roundPixelMeasures( measure ) {
function curCSS (line 6571) | function curCSS( elem, name, computed ) {
function addGetHookIf (line 6624) | function addGetHookIf( conditionFn, hookFn ) {
function vendorPropName (line 6649) | function vendorPropName( name ) {
function finalPropName (line 6664) | function finalPropName( name ) {
function setPositiveNumber (line 6690) | function setPositiveNumber( _elem, value, subtract ) {
function boxModelAdjustment (line 6702) | function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, ...
function getWidthOrHeight (line 6770) | function getWidthOrHeight( elem, dimension, extra ) {
function Tween (line 7146) | function Tween( elem, options, prop, end, easing ) {
function schedule (line 7269) | function schedule() {
function createFxNow (line 7282) | function createFxNow() {
function genFx (line 7290) | function genFx( type, includeWidth ) {
function createTween (line 7310) | function createTween( value, prop, animation ) {
function defaultPrefilter (line 7324) | function defaultPrefilter( elem, props, opts ) {
function propFilter (line 7496) | function propFilter( props, specialEasing ) {
function Animation (line 7533) | function Animation( elem, properties, options ) {
function stripAndCollapse (line 8248) | function stripAndCollapse( value ) {
function getClass (line 8254) | function getClass( elem ) {
function classesToArray (line 8258) | function classesToArray( value ) {
function buildParams (line 8885) | function buildParams( prefix, obj, traditional, add ) {
function addToPrefiltersOrTransports (line 9039) | function addToPrefiltersOrTransports( structure ) {
function inspectPrefiltersOrTransports (line 9073) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
function ajaxExtend (line 9102) | function ajaxExtend( target, src ) {
function ajaxHandleResponses (line 9122) | function ajaxHandleResponses( s, jqXHR, responses ) {
function ajaxConvert (line 9180) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
function done (line 9696) | function done( status, nativeStatusText, responses, headers ) {
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Contributors/ContributorCreate.cs
class ContributorCreate (line 6) | [Collection("Sequential")]
method ContributorCreate (line 11) | public ContributorCreate(CustomWebApplicationFactory<Program> factory)
method ReturnsOneContributor (line 16) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Contributors/ContributorDelete.cs
class ContributorDelete (line 6) | [Collection("Sequential")]
method ContributorDelete (line 11) | public ContributorDelete(CustomWebApplicationFactory<Program> factory)
method DeletesExistingContributor (line 16) | [Fact]
method ReturnsNotFoundGivenMissingContributorId (line 26) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Contributors/ContributorGetById.cs
class ContributorGetById (line 6) | [Collection("Sequential")]
method ContributorGetById (line 11) | public ContributorGetById(CustomWebApplicationFactory<Program> factory)
method ReturnsSeedContributorGivenId1 (line 16) | [Fact]
method ReturnsNotFoundGivenInvalidId1000 (line 25) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Contributors/ContributorList.cs
class ContributorList (line 6) | [Collection("Sequential")]
method ContributorList (line 11) | public ContributorList(CustomWebApplicationFactory<Program> factory)
method ReturnsTwoContributors (line 16) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Contributors/ContributorUpdate.cs
class ContributorUpdate (line 7) | [Collection("Sequential")]
method ContributorUpdate (line 12) | public ContributorUpdate(CustomWebApplicationFactory<Program> factory)
method UpdatesContributorNameAndReturnsUpdatedRecord (line 17) | [Fact]
method ReturnsNotFoundGivenMissingContributorId (line 32) | [Fact]
method ReturnsBadRequestIfRouteIdDoesNotMatchBodyId (line 43) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/CustomWebApplicationFactory.cs
class CustomWebApplicationFactory (line 9) | public class CustomWebApplicationFactory<TProgram> : WebApplicationFacto...
method CreateHost (line 17) | protected override IHost CreateHost(IHostBuilder builder)
method ConfigureWebHost (line 58) | protected override void ConfigureWebHost(IWebHostBuilder builder)
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Fixtures/SmtpServerFixture.cs
class SmtpServerFixture (line 6) | public class SmtpServerFixture : IAsyncLifetime
method InitializeAsync (line 13) | public async Task InitializeAsync()
method DisposeAsync (line 28) | public async Task DisposeAsync()
method EnsureContainerIsRunning (line 46) | public void EnsureContainerIsRunning()
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/CreateToDoItemRequestBuilder.cs
class CreateToDoItemRequestBuilder (line 9) | public class CreateToDoItemRequestBuilder
method WithProjectId (line 13) | public CreateToDoItemRequestBuilder WithProjectId(int projectId)
method WithTitle (line 19) | public CreateToDoItemRequestBuilder WithTitle(string title)
method WithDescription (line 25) | public CreateToDoItemRequestBuilder WithDescription(string description)
method WithContributorId (line 31) | public CreateToDoItemRequestBuilder WithContributorId(int? contributorId)
method WithValidDefaults (line 37) | public CreateToDoItemRequestBuilder WithValidDefaults()
method Build (line 46) | public CreateToDoItemRequest Build() => _request;
method Create (line 48) | public static CreateToDoItemRequestBuilder Create() => new();
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/ProjectAddToDoItem.cs
class ProjectAddToDoItem (line 8) | [Collection("Sequential")]
method ProjectAddToDoItem (line 11) | public ProjectAddToDoItem(CustomWebApplicationFactory<Program> factory...
method AddsItemAndReturnsRouteToProject (line 16) | private async Task AddsItemAndReturnsRouteToProject()
method ReturnsBadRequestWhenTitleIsMissing (line 48) | [Fact]
method ReturnsBadRequestWhenDescriptionIsMissing (line 64) | [Fact]
method ReturnsBadRequestWhenProjectIdIsZero (line 80) | [Fact]
method ReturnsNotFoundWhenProjectDoesNotExist (line 96) | [Fact]
method AddsItemWithValidContributor (line 113) | [Fact]
method AddsItemWithNullContributor (line 143) | private async Task AddsItemWithNullContributor()
method HandlesSpecialCharactersInTitleAndDescription (line 172) | private async Task HandlesSpecialCharactersInTitleAndDescription()
method HandlesLongTitleAndDescription (line 203) | private async Task HandlesLongTitleAndDescription()
method ReturnsBadRequestWhenTitleExceedsMaxLength (line 233) | [Fact]
method ReturnsBadRequestWhenDescriptionExceedsMaxLength (line 250) | [Fact]
method HandlesWhitespaceOnlyTitleAndDescription (line 267) | [Fact]
method ReturnsCorrectStatusCodeAndContentType (line 285) | [Fact]
method DoesNotReturnResponseBodyOnSuccess (line 308) | [Fact]
method IncreasesTotalItemCountInProject (line 332) | private async Task IncreasesTotalItemCountInProject()
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/ProjectCreate.cs
class ProjectCreate (line 6) | [Collection("Sequential")]
method ProjectCreate (line 11) | public ProjectCreate(CustomWebApplicationFactory<Program> factory)
method ReturnsOneProject (line 16) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/ProjectGetById.cs
class ProjectGetById (line 8) | [Collection("Sequential")]
method ProjectGetById (line 13) | public ProjectGetById(CustomWebApplicationFactory<Program> factory)
method ReturnsSeedProjectGivenId1 (line 18) | [Fact]
method ReturnsNotFoundGivenInvalidId1000 (line 28) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/ProjectItemMarkComplete.cs
class ProjectItemMarkComplete (line 9) | [Collection("Sequential")]
method ProjectItemMarkComplete (line 16) | public ProjectItemMarkComplete(CustomWebApplicationFactory<Program> fa...
method MarksIncompleteItemComplete (line 26) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/Projects/ProjectList.cs
class ProjectList (line 6) | [Collection("Sequential")]
method ProjectList (line 11) | public ProjectList(CustomWebApplicationFactory<Program> factory)
method ReturnsOneProject (line 16) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.FunctionalTests/TestBase.cs
class TestBase (line 10) | public abstract class TestBase : IClassFixture<CustomWebApplicationFacto...
method TestBase (line 15) | protected TestBase(CustomWebApplicationFactory<Program> factory)
method InitializeAsync (line 21) | public virtual Task InitializeAsync()
method DisposeAsync (line 27) | public virtual async Task DisposeAsync()
method ResetDatabaseAsync (line 33) | protected async Task ResetDatabaseAsync()
FILE: sample/tests/NimblePros.SampleToDo.IntegrationTests/Data/BaseEfRepoTestFixture.cs
class BaseEfRepoTestFixture (line 6) | public abstract class BaseEfRepoTestFixture
method BaseEfRepoTestFixture (line 10) | protected BaseEfRepoTestFixture()
method CreateNewContextOptions (line 16) | protected static DbContextOptions<AppDbContext> CreateNewContextOptions()
method GetRepository (line 39) | protected EfRepository<Project> GetRepository()
FILE: sample/tests/NimblePros.SampleToDo.IntegrationTests/Data/EfRepositoryAdd.cs
class EfRepositoryAdd (line 5) | public class EfRepositoryAdd : BaseEfRepoTestFixture
method AddsProjectAndSetsId (line 7) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.IntegrationTests/Data/EfRepositoryDelete.cs
class EfRepositoryDelete (line 5) | public class EfRepositoryDelete : BaseEfRepoTestFixture
method DeletesItemAfterAddingIt (line 7) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.IntegrationTests/Data/EfRepositoryUpdate.cs
class EfRepositoryUpdate (line 5) | public class EfRepositoryUpdate : BaseEfRepoTestFixture
method UpdatesItemAfterAddingIt (line 7) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ContributorAggregate/ContributorConstructor.cs
class ContributorConstructor (line 5) | public class ContributorConstructor
method CreateContributor (line 10) | private Contributor CreateContributor()
method InitializesName (line 15) | [Fact]
class ContributorUpdateName (line 24) | public class ContributorUpdateName
method CreateContributor (line 29) | private Contributor CreateContributor()
method DoesNothingGivenSameName (line 34) | [Fact]
method UpdatesNameAndRegistersEventGivenNewName (line 48) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ContributorAggregate/ContributorIdFrom.cs
class ContributorIdFrom (line 5) | public class ContributorIdFrom
method CreatesGivenValidValue (line 7) | [Fact]
method ThrowsGivenInvalidValue (line 15) | [Theory]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Handlers/ItemCompletedEmailNotificationHandlerHandle.cs
class ItemCompletedEmailNotificationHandlerHandle (line 8) | public class ItemCompletedEmailNotificationHandlerHandle
method ItemCompletedEmailNotificationHandlerHandle (line 13) | public ItemCompletedEmailNotificationHandlerHandle()
method ThrowsExceptionGivenNullEventArgument (line 18) | [Fact]
method SendsEmailGivenEventInstance (line 27) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ProjectAggregate/ProjectConstructor.cs
class ProjectConstructor (line 6) | public class ProjectConstructor
method CreateProject (line 12) | private Project CreateProject()
method InitializesName (line 17) | [Fact]
method InitializesTaskListToEmptyList (line 25) | [Fact]
method InitializesStatusToInProgress (line 33) | [Fact]
method ProjectName_TooLong_ReturnsLocalizedMessage (line 40) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ProjectAggregate/ProjectNameFrom.cs
class ProjectNameFrom (line 7) | public class ProjectNameFrom
method ThrowsGivenNullOrEmpty (line 9) | [Theory]
method DoesNotThrowGivenValidData (line 17) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ProjectAggregate/Project_AddItem.cs
class Project_AddItem (line 5) | public class Project_AddItem
method AddsItemToItems (line 9) | [Fact]
method ThrowsExceptionGivenNullItem (line 20) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ProjectAggregate/ToDoItemConstructor.cs
class ToDoItemConstructor (line 6) | public class ToDoItemConstructor
method InitializesPriority (line 8) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/ProjectAggregate/ToDoItemMarkComplete.cs
class ToDoItemMarkComplete (line 5) | public class ToDoItemMarkComplete
method SetsIsDoneToTrue (line 7) | [Fact]
method RaisesToDoItemCompletedEvent (line 20) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Services/DeleteContributorSevice_DeleteContributor.cs
class DeleteContributorService_DeleteContributor (line 6) | public class DeleteContributorService_DeleteContributor
method DeleteContributorService_DeleteContributor (line 14) | public DeleteContributorService_DeleteContributor()
method ReturnsNotFoundGivenCantFindContributor (line 19) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Services/ToDoItemSearchServiceTests.cs
class ToDoItemSearchServiceTests (line 7) | public class ToDoItemSearchServiceTests
method ToDoItemSearchServiceTests (line 12) | public ToDoItemSearchServiceTests()
method ReturnsValidationErrors (line 18) | [Fact]
method ReturnsProjectNotFound (line 26) | [Fact]
method ReturnsAllIncompleteItems (line 34) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Services/ToDoItemSearchService_GetAllIncompleteItems.cs
class ToDoItemSearchService_GetAllIncompleteItems (line 12) | public class ToDoItemSearchService_GetAllIncompleteItems
method ToDoItemSearchService_GetAllIncompleteItems (line 17) | public ToDoItemSearchService_GetAllIncompleteItems()
method ReturnsInvalidGivenNullSearchString (line 22) | [Fact]
method ReturnsErrorGivenDataAccessException (line 31) | [Fact]
method ReturnsListGivenSearchString (line 44) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Services/ToDoItemSearchService_GetNextIncompleteItem.cs
class ToDoItemSearchService_GetNextIncompleteItem (line 13) | public class ToDoItemSearchService_GetNextIncompleteItem
method ReturnsNotFoundGivenNoRemainingItems (line 15) | [Fact]
method ReturnsFirstItemFromList (line 28) | [Fact]
method GetTestItems (line 42) | private List<ToDoItem> GetTestItems()
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/Core/Specifications/IncompleteItemSpecificationsConstructor.cs
class IncompleteItemsSpecificationConstructor (line 6) | public class IncompleteItemsSpecificationConstructor
method FilterCollectionToOnlyReturnItemsWithIsDoneFalse (line 8) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/NoOpMediator.cs
class NoOpMediator (line 3) | public class NoOpMediator : IMediator
method CreateStream (line 5) | public async Task<IAsyncEnumerable<TResponse>> CreateStream<TResponse>...
method CreateStream (line 11) | public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamRequ...
method CreateStream (line 16) | public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamComm...
method CreateStream (line 21) | public IAsyncEnumerable<object?> CreateStream(object message, Cancella...
method Publish (line 26) | public ValueTask Publish<TNotification>(TNotification notification, Ca...
method Publish (line 31) | public ValueTask Publish(object notification, CancellationToken cancel...
method Send (line 36) | public ValueTask<TResponse> Send<TResponse>(IRequest<TResponse> reques...
method Send (line 41) | public ValueTask<TResponse> Send<TResponse>(ICommand<TResponse> comman...
method Send (line 46) | public ValueTask<TResponse> Send<TResponse>(IQuery<TResponse> query, C...
method Send (line 51) | public ValueTask<object?> Send(object message, CancellationToken cance...
method CreateStream (line 56) | IAsyncEnumerable<TResponse> ISender.CreateStream<TResponse>(IStreamQue...
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/ToDoItemBuilder.cs
class ToDoItemBuilder (line 7) | public class ToDoItemBuilder
method Id (line 11) | public ToDoItemBuilder Id(int id)
method Title (line 17) | public ToDoItemBuilder Title(String title)
method Description (line 23) | public ToDoItemBuilder Description(String description)
method WithDefaultValues (line 29) | public ToDoItemBuilder WithDefaultValues()
method Build (line 36) | public ToDoItem Build() => _todo;
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/UseCases/Contributors/CreateContributorHandlerHandle.cs
class CreateContributorHandlerHandle (line 6) | public class CreateContributorHandlerHandle
method CreateContributorHandlerHandle (line 12) | public CreateContributorHandlerHandle()
method CreateContributor (line 17) | private Contributor CreateContributor()
method ReturnsSuccessGivenValidName (line 22) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/UseCases/Contributors/GetContributorHandlerHandle.cs
class GetContributorHandlerHandle (line 8) | public class GetContributorHandlerHandle
method GetContributorHandlerHandle (line 14) | public GetContributorHandlerHandle()
method ReturnsRecordGivenValidId (line 19) | [Fact]
method ReturnsNotFoundGivenInvalidId (line 31) | [Fact]
FILE: sample/tests/NimblePros.SampleToDo.UnitTests/UseCases/Contributors/UpdateContributorHandlerHandle.cs
class UpdateContributorHandlerHandle (line 8) | public class UpdateContributorHandlerHandle
method UpdateContributorHandlerHandle (line 15) | public UpdateContributorHandlerHandle()
method ReturnsRecordGivenValidId (line 20) | [Fact]
method ReturnsNotFoundGivenNonexistentId (line 32) | [Fact]
FILE: src/Clean.Architecture.Core/ContributorAggregate/Contributor.cs
class Contributor (line 5) | public class Contributor(ContributorName name) : EntityBase<Contributor,...
method UpdatePhoneNumber (line 11) | public Contributor UpdatePhoneNumber(PhoneNumber newPhoneNumber)
method UpdateName (line 17) | public Contributor UpdateName(ContributorName newName)
FILE: src/Clean.Architecture.Core/ContributorAggregate/ContributorId.cs
type ContributorId (line 9) | [ValueObject<int>]
method Validate (line 12) | private static Validation Validate(int value)
FILE: src/Clean.Architecture.Core/ContributorAggregate/ContributorName.cs
type ContributorName (line 5) | [ValueObject<string>(conversions: Conversions.SystemTextJson)]
method Validate (line 9) | private static Validation Validate(in string name) =>
FILE: src/Clean.Architecture.Core/ContributorAggregate/ContributorStatus.cs
class ContributorStatus (line 3) | public class ContributorStatus : SmartEnum<ContributorStatus>
method ContributorStatus (line 9) | protected ContributorStatus(string name, int value) : base(name, value...
FILE: src/Clean.Architecture.Core/ContributorAggregate/Events/ContributorDeletedEvent.cs
class ContributorDeletedEvent (line 8) | public sealed class ContributorDeletedEvent(ContributorId contributorId)...
FILE: src/Clean.Architecture.Core/ContributorAggregate/Events/ContributorNameUpdatedEvent.cs
class ContributorNameUpdatedEvent (line 3) | public sealed class ContributorNameUpdatedEvent(Contributor contributor)...
FILE: src/Clean.Architecture.Core/ContributorAggregate/Handlers/ContributorDeletedHandler.cs
class ContributorDeletedHandler (line 6) | public class ContributorDeletedHandler(ILogger<ContributorDeletedHandler...
method Handle (line 9) | public async ValueTask Handle(ContributorDeletedEvent domainEvent, Can...
FILE: src/Clean.Architecture.Core/ContributorAggregate/Handlers/ContributorNameUpdatedEmailNotificationHandler.cs
class ContributorNameUpdatedEmailNotificationHandler (line 6) | public class ContributorNameUpdatedEmailNotificationHandler(
method Handle (line 10) | public async ValueTask Handle(ContributorNameUpdatedEvent domainEvent,...
FILE: src/Clean.Architecture.Core/ContributorAggregate/PhoneNumber.cs
class PhoneNumber (line 3) | public class PhoneNumber(string countryCode, string number, string? exte...
method GetEqualityComponents (line 10) | protected override IEnumerable<object> GetEqualityComponents()
method ToString (line 17) | public override string ToString()
FILE: src/Clean.Architecture.Core/ContributorAggregate/Specifications/ContributorByIdSpec.cs
class ContributorByIdSpec (line 3) | public class ContributorByIdSpec : Specification<Contributor>
method ContributorByIdSpec (line 5) | public ContributorByIdSpec(ContributorId contributorId) =>
FILE: src/Clean.Architecture.Core/Interfaces/IDeleteContributorService.cs
type IDeleteContributorService (line 5) | public interface IDeleteContributorService
method DeleteContributor (line 9) | public ValueTask<Result> DeleteContributor(ContributorId contributorId);
FILE: src/Clean.Architecture.Core/Interfaces/IEmailSender.cs
type IEmailSender (line 3) | public interface IEmailSender
method SendEmailAsync (line 5) | Task SendEmailAsync(string to, string from, string subject, string body);
FILE: src/Clean.Architecture.Core/Services/DeleteContributorService.cs
class DeleteContributorService (line 14) | public class DeleteContributorService(IRepository<Contributor> _repository,
method DeleteContributor (line 18) | public async ValueTask<Result> DeleteContributor(ContributorId contrib...
FILE: src/Clean.Architecture.Infrastructure/Data/AppDbContext.cs
class AppDbContext (line 4) | public class AppDbContext(DbContextOptions<AppDbContext> options) : DbCo...
method OnModelCreating (line 8) | protected override void OnModelCreating(ModelBuilder modelBuilder)
method SaveChanges (line 14) | public override int SaveChanges() =>
FILE: src/Clean.Architecture.Infrastructure/Data/AppDbContextExtensions.cs
class AppDbContextExtensions (line 3) | public static class AppDbContextExtensions
method AddApplicationDbContext (line 5) | public static void AddApplicationDbContext(this IServiceCollection ser...
FILE: src/Clean.Architecture.Infrastructure/Data/Config/ContributorConfiguration.cs
class ContributorConfiguration (line 5) | public class ContributorConfiguration : IEntityTypeConfiguration<Contrib...
method Configure (line 7) | public void Configure(EntityTypeBuilder<Contributor> builder)
FILE: src/Clean.Architecture.Infrastructure/Data/Config/DataSchemaConstants.cs
class DataSchemaConstants (line 3) | public static class DataSchemaConstants
FILE: src/Clean.Architecture.Infrastructure/Data/Config/VogenIdValueGenerator.cs
class VogenIdValueGenerator (line 6) | internal class VogenIdValueGenerator<TContext, TEntityBase, TId> : Value...
method VogenIdValueGenerator (line 13) | public VogenIdValueGenerator()
method Next (line 31) | public override TId Next(EntityEntry entry)
FILE: src/Clean.Architecture.Infrastructure/Data/EfRepository.cs
class EfRepository (line 4) | public class EfRepository<T>(AppDbContext dbContext) :
FILE: src/Clean.Architecture.Infrastructure/Data/EventDispatcherInterceptor.cs
class EventDispatchInterceptor (line 6) | public class EventDispatchInterceptor(IDomainEventDispatcher domainEvent...
method SavedChangesAsync (line 11) | public override async ValueTask<int> SavedChangesAsync(SaveChangesComp...
FILE: src/Clean.Architecture.Infrastructure/Data/Migrations/20231218143922_PhoneNumber.Designer.cs
class PhoneNumber (line 12) | [DbContext(typeof(AppDbContext))]
method BuildTargetModel (line 17) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Clean.Architecture.Infrastructure/Data/Migrations/20231218143922_PhoneNumber.cs
class PhoneNumber (line 8) | public partial class PhoneNumber : Migration
method Up (line 11) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 32) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Clean.Architecture.Infrastructure/Data/Migrations/20251113164108_UpdateForNet10.Designer.cs
class UpdateForNet10 (line 13) | [DbContext(typeof(AppDbContext))]
method BuildTargetModel (line 18) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Clean.Architecture.Infrastructure/Data/Migrations/20251113164108_UpdateForNet10.cs
class UpdateForNet10 (line 8) | public partial class UpdateForNet10 : Migration
method Up (line 11) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 74) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Clean.Architecture.Infrastructure/Data/Migrations/AppDbContextModelSnapshot.cs
class AppDbContextModelSnapshot (line 12) | [DbContext(typeof(AppDbContext))]
method BuildModel (line 15) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: src/Clean.Architecture.Infrastructure/Data/Queries/FakeListContributorsQueryService.cs
class FakeListContributorsQueryService (line 7) | public class FakeListContributorsQueryService : IListContributorsQuerySe...
method ListAsync (line 9) | public Task<UseCases.PagedResult<ContributorDto>> ListAsync(int page, ...
FILE: src/Clean.Architecture.Infrastructure/Data/Queries/ListContributorsQueryService.cs
class ListContributorsQueryService (line 7) | public class ListContributorsQueryService : IListContributorsQueryService
method ListContributorsQueryService (line 12) | public ListContributorsQueryService(AppDbContext db)
method ListAsync (line 17) | public async Task<UseCases.PagedResult<ContributorDto>> ListAsync(int ...
FILE: src/Clean.Architecture.Infrastructure/Data/SeedData.cs
class SeedData (line 5) | public static class SeedData
method InitializeAsync (line 11) | public static async Task InitializeAsync(AppDbContext dbContext)
method PopulateTestDataAsync (line 18) | public static async Task PopulateTestDataAsync(AppDbContext dbContext)
FILE: src/Clean.Architecture.Infrastructure/Email/FakeEmailSender.cs
class FakeEmailSender (line 5) | public class FakeEmailSender(ILogger<FakeEmailSender> logger) : IEmailSe...
method SendEmailAsync (line 8) | public Task SendEmailAsync(string to, string from, string subject, str...
FILE: src/Clean.Architecture.Infrastructure/Email/MailserverConfiguration.cs
class MailserverConfiguration (line 3) | public class MailserverConfiguration()
FILE: src/Clean.Architecture.Infrastructure/Email/MimeKitEmailSender.cs
class MimeKitEmailSender (line 5) | public class MimeKitEmailSender(ILogger<MimeKitEmailSender> logger,
method SendEmailAsync (line 11) | public async Task SendEmailAsync(string to, string from, string subjec...
FILE: src/Clean.Architecture.Infrastructure/InfrastructureServiceExtensions.cs
class InfrastructureServiceExtensions (line 8) | public static class InfrastructureServiceExtensions
method AddInfrastructureServices (line 10) | public static IServiceCollection AddInfrastructureServices(
FILE: src/Clean.Architecture.ServiceDefaults/Extensions.cs
class Extensions (line 16) | public static class Extensions
method AddServiceDefaults (line 21) | public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder buil...
method ConfigureOpenTelemetry (line 47) | public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder ...
method AddOpenTelemetryExporters (line 81) | private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuil...
method AddDefaultHealthChecks (line 100) | public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder ...
method MapDefaultEndpoints (line 109) | public static WebApplication MapDefaultEndpoints(this WebApplication app)
FILE: src/Clean.Architecture.UseCases/Constants.cs
class Constants (line 3) | public class Constants
FILE: src/Clean.Architecture.UseCases/Contributors/ContributorDTO.cs
type ContributorDto (line 4) | public record ContributorDto(ContributorId Id, ContributorName Name, Pho...
FILE: src/Clean.Architecture.UseCases/Contributors/Create/CreateContributorCommand.cs
type CreateContributorCommand (line 9) | public record CreateContributorCommand(ContributorName Name, string? Pho...
FILE: src/Clean.Architecture.UseCases/Contributors/Create/CreateContributorHandler.cs
class CreateContributorHandler (line 5) | public class CreateContributorHandler(IRepository<Contributor> _repository)
method Handle (line 8) | public async ValueTask<Result<ContributorId>> Handle(CreateContributor...
FILE: src/Clean.Architecture.UseCases/Contributors/Delete/DeleteContributorCommand.cs
type DeleteContributorCommand (line 5) | public record DeleteContributorCommand(ContributorId ContributorId) : IC...
FILE: src/Clean.Architecture.UseCases/Contributors/Delete/DeleteContributorHandler.cs
class DeleteContributorHandler (line 5) | public class DeleteContributorHandler(IDeleteContributorService _deleteC...
method Handle (line 8) | public async ValueTask<Result> Handle(DeleteContributorCommand request...
FILE: src/Clean.Architecture.UseCases/Contributors/Get/GetContributorHandler.cs
class GetContributorHandler (line 9) | public class GetContributorHandler(IReadRepository<Contributor> _reposit...
method Handle (line 12) | public async ValueTask<Result<ContributorDto>> Handle(GetContributorQu...
FILE: src/Clean.Architecture.UseCases/Contributors/Get/GetContributorQuery.cs
type GetContributorQuery (line 5) | public record GetContributorQuery(ContributorId ContributorId) : IQuery<...
FILE: src/Clean.Architecture.UseCases/Contributors/List/IListContributorsQueryService.cs
type IListContributorsQueryService (line 7) | public interface IListContributorsQueryService
method ListAsync (line 9) | Task<UseCases.PagedResult<ContributorDto>> ListAsync(int page, int per...
FILE: src/Clean.Architecture.UseCases/Contributors/List/ListContributorsHandler.cs
class ListContributorsHandler (line 3) | public class ListContributorsHandler : IQueryHandler<ListContributorsQue...
method ListContributorsHandler (line 7) | public ListContributorsHandler(IListContributorsQueryService query)
method Handle (line 12) | public async ValueTask<Result<PagedResult<ContributorDto>>> Handle(Lis...
FILE: src/Clean.Architecture.UseCases/Contributors/List/ListContributorsQuery.cs
type ListContributorsQuery (line 3) | public record ListContributorsQuery(int? Page = 1, int? PerPage = Consta...
FILE: src/Clean.Architecture.UseCases/Contributors/Update/UpdateContributorCommand.cs
type UpdateContributorCommand (line 5) | public record UpdateContributorCommand(ContributorId ContributorId, Cont...
FILE: src/Clean.Architecture.UseCases/Contributors/Update/UpdateContributorHandler.cs
class UpdateContributorHandler (line 5) | public class UpdateContributorHandler(IRepository<Contributor> _repository)
method Handle (line 8) | public async ValueTask<Result<ContributorDto>> Handle(UpdateContributo...
FILE: src/Clean.Architecture.UseCases/PagedResult.cs
type PagedResult (line 3) | public record PagedResult<T>(
FILE: src/Clean.Architecture.Web/Configurations/LoggerConfigs.cs
class LoggerConfigs (line 5) | public static class LoggerConfigs
method AddLoggerConfigs (line 7) | public static WebApplicationBuilder AddLoggerConfigs(this WebApplicati...
FILE: src/Clean.Architecture.Web/Configurations/MediatorConfig.cs
class MediatorConfig (line 8) | public static class MediatorConfig
method AddMediatorSourceGen (line 11) | public static IServiceCollection AddMediatorSourceGen(this IServiceCol...
FILE: src/Clean.Architecture.Web/Configurations/MiddlewareConfig.cs
class MiddlewareConfig (line 7) | public static class MiddlewareConfig
method UseAppMiddlewareAndSeedDatabase (line 9) | public static async Task<IApplicationBuilder> UseAppMiddlewareAndSeedD...
method MigrateDatabaseAsync (line 58) | static async Task MigrateDatabaseAsync(WebApplication app)
method SeedDatabaseAsync (line 89) | static async Task SeedDatabaseAsync(WebApplication app)
FILE: src/Clean.Architecture.Web/Configurations/OptionConfigs.cs
class OptionConfigs (line 6) | public static class OptionConfigs
method AddOptionConfigs (line 8) | public static IServiceCollection AddOptionConfigs(this IServiceCollect...
FILE: src/Clean.Architecture.Web/Configurations/ServiceConfigs.cs
class ServiceConfigs (line 7) | public static class ServiceConfigs
method AddServiceConfigs (line 9) | public static IServiceCollection AddServiceConfigs(this IServiceCollec...
FILE: src/Clean.Architecture.Web/Contributors/ContributorRecord.cs
type ContributorRecord (line 3) | public record ContributorRecord(int Id, string Name, string? PhoneNumber);
FILE: src/Clean.Architecture.Web/Contributors/Create.cs
class Create (line 15) | public class Create(IMediator mediator)
method Configure (line 23) | public override void Configure()
method ExecuteAsync (line 51) | public override async Task<Results<Created<CreateContributorResponse>,...
class CreateContributorRequest (line 62) | public class CreateContributorRequest
class CreateContributorValidator (line 71) | public class CreateContributorValidator : Validator<CreateContributorReq...
method CreateContributorValidator (line 73) | public CreateContributorValidator()
class CreateContributorResponse (line 83) | public class CreateContributorResponse(int id, string name)
FILE: src/Clean.Architecture.Web/Contributors/Delete.DeleteContributorRequest.cs
type DeleteContributorRequest (line 3) | public record DeleteContributorRequest
FILE: src/Clean.Architecture.Web/Contributors/Delete.DeleteContributorValidator.cs
class DeleteContributorValidator (line 8) | public class DeleteContributorValidator : Validator<DeleteContributorReq...
method DeleteContributorValidator (line 10) | public DeleteContributorValidator()
FILE: src/Clean.Architecture.Web/Contributors/Delete.cs
class Delete (line 8) | public class Delete
method Delete (line 15) | public Delete(IMediator mediator) => _mediator = mediator;
method Configure (line 17) | public override void Configure()
method ExecuteAsync (line 44) | public override async Task<Results<NoContent, NotFound, ProblemHttpRes...
FILE: src/Clean.Architecture.Web/Contributors/GetById.GetContributorByIdRequest.cs
class GetContributorByIdRequest (line 3) | public class GetContributorByIdRequest
method BuildRoute (line 6) | public static string BuildRoute(int contributorId) => Route.Replace("{...
FILE: src/Clean.Architecture.Web/Contributors/GetById.GetContributorValidator.cs
class GetContributorValidator (line 9) | public class GetContributorValidator : Validator<GetContributorByIdRequest>
method GetContributorValidator (line 11) | public GetContributorValidator()
FILE: src/Clean.Architecture.Web/Contributors/GetById.cs
class GetById (line 9) | public class GetById(IMediator mediator)
method Configure (line 16) | public override void Configure()
method ExecuteAsync (line 44) | public override async Task<Results<Ok<ContributorRecord>, NotFound, Pr...
class GetContributorByIdMapper (line 52) | public sealed class GetContributorByIdMapper
method FromEntity (line 55) | public override ContributorRecord FromEntity(ContributorDto e)
FILE: src/Clean.Architecture.Web/Contributors/List.cs
class List (line 8) | public class List(IMediator mediator) : Endpoint<ListContributorsRequest...
method Configure (line 12) | public override void Configure()
method HandleAsync (line 49) | public override async Task HandleAsync(ListContributorsRequest request...
method AddLinkHeader (line 65) | private void AddLinkHeader(int page, int perPage, int totalPages)
class ListContributorsRequest (line 87) | public sealed class ListContributorsRequest
type ContributorListResponse (line 98) | public record ContributorListResponse : UseCases.PagedResult<Contributor...
class ListContributorsValidator (line 107) | public sealed class ListContributorsValidator : Validator<ListContributo...
method ListContributorsValidator (line 109) | public ListContributorsValidator()
class ListContributorsMapper (line 121) | public sealed class ListContributorsMapper
method FromEntity (line 124) | public override ContributorListResponse FromEntity(UseCases.PagedResul...
FILE: src/Clean.Architecture.Web/Contributors/Update.UpdateContributorRequest.cs
class UpdateContributorRequest (line 5) | public class UpdateContributorRequest
method BuildRoute (line 8) | public static string BuildRoute(int contributorId) => Route.Replace("{...
FILE: src/Clean.Architecture.Web/Contributors/Update.UpdateContributorResponse.cs
class UpdateContributorResponse (line 3) | public class UpdateContributorResponse(ContributorRecord contributor)
FILE: src/Clean.Architecture.Web/Contributors/Update.UpdateContributorValidator.cs
class UpdateContributorValidator (line 10) | public class UpdateContributorValidator : Validator<UpdateContributorReq...
method UpdateContributorValidator (line 12) | public UpdateContributorValidator()
FILE: src/Clean.Architecture.Web/Contributors/Update.cs
class Update (line 10) | public class Update(IMediator mediator)
method Configure (line 18) | public override void Configure()
method ExecuteAsync (line 48) | public override async Task<Results<Ok<UpdateContributorResponse>, NotF...
class UpdateContributorMapper (line 61) | public sealed class UpdateContributorMapper
method FromEntity (line 64) | public override UpdateContributorResponse FromEntity(ContributorDto e)
FILE: src/Clean.Architecture.Web/Extensions/ResultExtensions.cs
class ResultExtensions (line 5) | public static class ResultExtensions
method ToCreatedResult (line 10) | public static Results<Created<TResponse>, ValidationProblem, ProblemHt...
method ToGetByIdResult (line 36) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToGe...
method ToUpdateResult (line 46) | public static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToUp...
method ToDeleteResult (line 56) | public static Results<NoContent, NotFound, ProblemHttpResult> ToDelete...
method ToOkOrNotFoundResult (line 73) | private static Results<Ok<TResponse>, NotFound, ProblemHttpResult> ToO...
method ToOkOnlyResult (line 92) | public static Ok<TResponse> ToOkOnlyResult<TValue, TResponse>(
FILE: src/Clean.Architecture.Web/Program.cs
class Program (line 37) | public partial class Program { }
FILE: tests/Clean.Architecture.AspireTests/AspireIntegrationTests.cs
class AspireIntegrationTests (line 3) | public class AspireIntegrationTests
FILE: tests/Clean.Architecture.FunctionalTests/ApiEndpoints/ContributorGetById.cs
class ContributorGetById (line 7) | [Collection("Sequential")]
method ReturnsSeedContributorGivenId1 (line 12) | [Fact]
method ReturnsNotFoundGivenId1000 (line 21) | [Fact]
FILE: tests/Clean.Architecture.FunctionalTests/ApiEndpoints/ContributorList.cs
class ContributorList (line 6) | [Collection("Sequential")]
method ReturnsTwoContributors (line 11) | [Fact]
FILE: tests/Clean.Architecture.FunctionalTests/CustomWebApplicationFactory.cs
class CustomWebApplicationFactory (line 8) | public class CustomWebApplicationFactory<TProgram> : WebApplicationFacto...
method InitializeAsync (line 12) | public async Task InitializeAsync()
method DisposeAsync (line 29) | public new async Task DisposeAsync()
method CreateHost (line 45) | protected override IHost CreateHost(IHostBuilder builder)
method ConfigureWebHost (line 91) | protected override void ConfigureWebHost(IWebHostBuilder builder)
FILE: tests/Clean.Architecture.FunctionalTests/DockerAvailabilityTests.cs
class DockerAvailabilityTests (line 5) | public class DockerAvailabilityTests
method Docker_ShouldBeRunning_ForFullFunctionalTestCoverage (line 7) | [Fact]
FILE: tests/Clean.Architecture.IntegrationTests/Data/BaseEfRepoTestFixture.cs
class BaseEfRepoTestFixture (line 6) | public abstract class BaseEfRepoTestFixture
method BaseEfRepoTestFixture (line 10) | protected BaseEfRepoTestFixture()
method CreateNewContextOptions (line 16) | protected static DbContextOptions<AppDbContext> CreateNewContextOptions()
method GetRepository (line 39) | protected EfRepository<Contributor> GetRepository()
FILE: tests/Clean.Architecture.IntegrationTests/Data/EfRepositoryAdd.cs
class EfRepositoryAdd (line 5) | public class EfRepositoryAdd : BaseEfRepoTestFixture
method AddsContributorAndSetsId (line 7) | [Fact]
FILE: tests/Clean.Architecture.IntegrationTests/Data/EfRepositoryDelete.cs
class EfRepositoryDelete (line 5) | public class EfRepositoryDelete : BaseEfRepoTestFixture
method DeletesItemAfterAddingIt (line 7) | [Fact]
FILE: tests/Clean.Architecture.IntegrationTests/Data/EfRepositoryUpdate.cs
class EfRepositoryUpdate (line 5) | public class EfRepositoryUpdate : BaseEfRepoTestFixture
method UpdatesItemAfterAddingIt (line 7) | [Fact]
FILE: tests/Clean.Architecture.UnitTests/Core/ContributorAggregate/ContributorConstructor.cs
class ContributorConstructor (line 3) | public class ContributorConstructor
method CreateContributor (line 8) | private Contributor CreateContributor()
method InitializesName (line 13) | [Fact]
FILE: tests/Clean.Architecture.UnitTests/Core/ContributorAggregate/ContributorIdFrom.cs
class ContributorIdFrom (line 3) | public class ContributorIdFrom
method CreatesGivenValidValue (line 5) | [Fact]
method ThrowsGivenInvalidValue (line 13) | [Theory]
FILE: tests/Clean.Architecture.UnitTests/Core/ContributorAggregate/ContributorNameFrom.cs
class ContributorNameFrom (line 3) | public class ContributorNameFrom
method CreatesGivenValidValue (line 5) | [Fact]
method ThrowsGivenInvalidValue (line 13) | [Theory]
FILE: tests/Clean.Architecture.UnitTests/Core/ContributorAggregate/ContributorUpdateName.cs
class ContributorUpdateName (line 5) | public class ContributorUpdateName
method CreateContributor (line 10) | private Contributor CreateContributor()
method UpdatesName (line 15) | [Fact]
method RegistersDomainEvent (line 23) | [Fact]
method DoesNotRegisterDomainEventGivenCurrentName (line 32) | [Fact]
FILE: tests/Clean.Architecture.UnitTests/Core/Services/DeleteContributorSevice_DeleteContributor.cs
class DeleteContributorService_DeleteContributor (line 5) | public class DeleteContributorService_DeleteContributor
method DeleteContributorService_DeleteContributor (line 13) | public DeleteContributorService_DeleteContributor()
method ReturnsNotFoundGivenCantFindContributor (line 18) | [Fact]
FILE: tests/Clean.Architecture.UnitTests/Core/Services/ToDoItemSearchService_GetAllIncompleteItems.cs
class ToDoItemSearchService_GetAllIncompleteItems (line 12) | public class ToDoItemSearchService_GetAllIncompleteItems
method ToDoItemSearchService_GetAllIncompleteItems (line 17) | public ToDoItemSearchService_GetAllIncompleteItems()
method ReturnsInvalidGivenNullSearchString (line 22) | [Fact]
method ReturnsErrorGivenDataAccessException (line 31) | [Fact]
method ReturnsListGivenSearchString (line 44) | [Fact]
FILE: tests/Clean.Architecture.UnitTests/Core/Services/ToDoItemSearchService_GetNextIncompleteItem.cs
class ToDoItemSearchService_GetNextIncompleteItem (line 13) | public class ToDoItemSearchService_GetNextIncompleteItem
method ReturnsNotFoundGivenNoRemainingItems (line 15) | [Fact]
method ReturnsFirstItemFromList (line 28) | [Fact]
method GetTestItems (line 42) | private List<ToDoItem> GetTestItems()
FILE: tests/Clean.Architecture.UnitTests/NoOpMediator.cs
class NoOpMediator (line 3) | public class NoOpMediator : IMediator
method CreateStream (line 5) | public async Task<IAsyncEnumerable<TResponse>> CreateStream<TResponse>...
method CreateStream (line 11) | public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamRequ...
method CreateStream (line 16) | public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamComm...
method CreateStream (line 21) | public IAsyncEnumerable<object?> CreateStream(object message, Cancella...
method Publish (line 26) | public ValueTask Publish<TNotification>(TNotification notification, Ca...
method Publish (line 31) | public ValueTask Publish(object notification, CancellationToken cancel...
method Send (line 36) | public ValueTask<TResponse> Send<TResponse>(IRequest<TResponse> reques...
method Send (line 41) | public ValueTask<TResponse> Send<TResponse>(ICommand<TResponse> comman...
method Send (line 46) | public ValueTask<TResponse> Send<TResponse>(IQuery<TResponse> query, C...
method Send (line 51) | public ValueTask<object?> Send(object message, CancellationToken cance...
method CreateStream (line 56) | IAsyncEnumerable<TResponse> ISender.CreateStream<TResponse>(IStreamQue...
FILE: tests/Clean.Architecture.UnitTests/UseCases/Contributors/CreateContributorHandlerHandle.cs
class CreateContributorHandlerHandle (line 3) | public class CreateContributorHandlerHandle
method CreateContributorHandlerHandle (line 9) | public CreateContributorHandlerHandle()
method CreateContributor (line 14) | private Contributor CreateContributor()
method ReturnsSuccessGivenValidName (line 19) | [Fact]
Condensed preview — 495 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,353K chars).
[
{
"path": ".aspire/settings.json",
"chars": 96,
"preview": "{\n \"appHostPath\": \"../src/Clean.Architecture.AspireHost/Clean.Architecture.AspireHost.csproj\"\n}"
},
{
"path": ".editorconfig",
"chars": 7198,
"preview": "###############################\n# Core EditorConfig Options #\n###############################\nroot = true\n# All files\n"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 2483,
"preview": "# Contributing to CleanArchitecture\n\n**First:** if you're unsure or afraid of _anything_, just ask or submit the\nissue o"
},
{
"path": ".github/FUNDING.yml",
"chars": 65,
"preview": "# These are supported funding model platforms\n\ngithub: [ardalis]\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 239,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\n---\n<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 202,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Question\n url: https://stackoverflow.com/questions/tagged/ardali"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 248,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n<!-- ⚠️⚠️ Do Not Delete This! feature_request_te"
},
{
"path": ".github/copilot-instructions.md",
"chars": 5008,
"preview": "# GitHub Copilot Instructions for Clean Architecture Template\n\n## Project Overview\nThis is a **Clean Architecture templa"
},
{
"path": ".github/dependabot.yml",
"chars": 127,
"preview": "version: 2\nupdates:\n- package-ecosystem: nuget\n directory: \"/\"\n schedule:\n interval: daily\n open-pull-requests-lim"
},
{
"path": ".github/workflows/build-ramdisk.yml",
"chars": 1091,
"preview": "name: Build and Test with Ramdisk\n\non:\n push:\n branches:\n - main\n pull_request:\n\njobs:\n build-and-test:\n r"
},
{
"path": ".github/workflows/codeql-analysis.yml",
"chars": 695,
"preview": "name: CodeQL Analysis\n\non:\n push:\n branches: [ main ]\n pull_request:\n schedule:\n - cron: '0 8 * * *'\n\njobs:\n a"
},
{
"path": ".github/workflows/dotnetcore.yml",
"chars": 623,
"preview": "name: .NET Core\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n\n runs-on:"
},
{
"path": ".github/workflows/publish-templates.yml",
"chars": 4169,
"preview": "name: Publish Templates to NuGet\n\non:\n workflow_dispatch:\n inputs:\n publish-full:\n description: 'Publish"
},
{
"path": ".github/workflows/publish.yml",
"chars": 1709,
"preview": "name: Publish to Nuget\n\non:\n workflow_dispatch:\n push:\n tags:\n - 'v*'\n release:\n types: [published]\n\nenv:\n"
},
{
"path": ".gitignore",
"chars": 4443,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
},
{
"path": ".runsettings",
"chars": 615,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RunSettings>\n <RunConfiguration>\n <!-- Enable parallel test execution at the"
},
{
"path": ".template.config/template.json",
"chars": 1027,
"preview": "{\n \"$schema\": \"http://json.schemastore.org/template\",\n \"author\": \"ardalis (Steve Smith)\",\n \"classifications\": [\n \""
},
{
"path": ".vscode/launch.json",
"chars": 1452,
"preview": "{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n // Use IntelliSense to find out which attributes"
},
{
"path": ".vscode/settings.json",
"chars": 903,
"preview": "{\n \"workbench.colorCustomizations\": {\n \"activityBar.activeBackground\": \"#6b9a8e\",\n \"activityBar.backgro"
},
{
"path": ".vscode/tasks.json",
"chars": 1184,
"preview": "{\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"label\": \"build\",\n \"command\": \"dotnet\",\n "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 258,
"preview": "# Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant\nto clarify expected "
},
{
"path": "CONTRIBUTING.md",
"chars": 2065,
"preview": "# Contributing to Ardalis.CleanArchitecture\n\nWe love your input! We want to make contributing to this project as easy an"
},
{
"path": "Clean.Architecture.slnx",
"chars": 1626,
"preview": "<Solution>\n <Configurations>\n <Platform Name=\"Any CPU\" />\n <Platform Name=\"x64\" />\n <Platform Name=\"x86\" />\n "
},
{
"path": "CleanArchitecture.nuspec",
"chars": 1301,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n <me"
},
{
"path": "Directory.Build.props",
"chars": 567,
"preview": "<Project>\n <PropertyGroup>\n <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n <CentralPackag"
},
{
"path": "Directory.Packages.props",
"chars": 4059,
"preview": "<Project>\n <ItemGroup>\n <PackageVersion Include=\"Ardalis.GuardClauses\" Version=\"5.0.0\" />\n <PackageVersion Includ"
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) 2016 Steve Smith\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "MinimalClean/.editorconfig",
"chars": 7198,
"preview": "###############################\n# Core EditorConfig Options #\n###############################\nroot = true\n# All files\n"
},
{
"path": "MinimalClean/.gitignore",
"chars": 3901,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
},
{
"path": "MinimalClean/.runsettings",
"chars": 615,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RunSettings>\n <RunConfiguration>\n <!-- Enable parallel test execution at the"
},
{
"path": "MinimalClean/.template.config/template.json",
"chars": 1074,
"preview": "{\n \"$schema\": \"http://json.schemastore.org/template\",\n \"author\": \"ardalis (Steve Smith)\",\n \"classifications\": [\n \""
},
{
"path": "MinimalClean/Directory.Build.props",
"chars": 477,
"preview": "<Project>\n <PropertyGroup>\n <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n <TreatWarnings"
},
{
"path": "MinimalClean/Directory.Packages.props",
"chars": 4174,
"preview": "<Project>\n <ItemGroup>\n <PackageVersion Include=\"Ardalis.GuardClauses\" Version=\"5.0.0\" />\n <PackageVersion Includ"
},
{
"path": "MinimalClean/MinimalClean.Architecture.slnx",
"chars": 761,
"preview": "<Solution>\n <Configurations>\n <Platform Name=\"Any CPU\" />\n <Platform Name=\"x64\" />\n <Platform Name=\"x86\" />\n "
},
{
"path": "MinimalClean/README.template.md",
"chars": 6095,
"preview": "# MinimalClean.Architecture\n\nWelcome to your new project generated with the **Minimal Clean Architecture** template!\n\nTh"
},
{
"path": "MinimalClean/global.json",
"chars": 108,
"preview": "{\n \"sdk\": {\n \"version\": \"10.0.100\",\n \"rollForward\": \"latestMajor\",\n \"allowPrerelease\": true\n }\n}\n"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.AspireHost/AppHost.cs",
"chars": 1055,
"preview": "using System.Net.Sockets;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\n// Add SQL Server container\nvar s"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.AspireHost/MinimalClean.Architecture.AspireHost.csproj",
"chars": 1388,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"13.0.0\" />\n\n <PropertyGroup>\n <OutputT"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.AspireHost/Properties/launchSettings.json",
"chars": 1003,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n \"profiles\": {\n \"https\": {\n \"commandName\": \""
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.Development.json",
"chars": 119,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\"\n }\n }\n}\n"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.json",
"chars": 158,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\",\n \"Aspir"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/Extensions.cs",
"chars": 4671,
"preview": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.Depe"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/MinimalClean.Architecture.ServiceDefaults.csproj",
"chars": 745,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <IsAspireSharedProject>true</IsAspireSharedProject>\n </Propert"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/AssemblyInfo.cs",
"chars": 250,
"preview": "using Vogen;\n[assembly: VogenDefaults(\n staticAbstractsGeneration: StaticAbstractsGeneration.MostCommon |\n "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartEndpoint.cs",
"chars": 3262,
"preview": "using FluentValidation;\nusing Microsoft.AspNetCore.Http.HttpResults;\nusing MinimalClean.Architecture.Web.Domain.CartAggr"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartHandler.cs",
"chars": 2040,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\nusing MinimalClean.Architecture.Web.Domain.CartAggregate.Speci"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartDto.cs",
"chars": 293,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\n\nnamespace MinimalClean.Architecture.Web.CartFeatures;\n\npublic"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartResponse.cs",
"chars": 251,
"preview": "namespace MinimalClean.Architecture.Web.CartFeatures;\n\npublic record CartResponse(Guid CartId, IReadOnlyList<CartItemRes"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutEndpoint.cs",
"chars": 3249,
"preview": "using FastEndpoints;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Http.HttpResults;\nusing MinimalClean.Architectu"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutHandler.cs",
"chars": 2295,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\nusing MinimalClean.Architecture.Web.Domain.CartAggregate.Speci"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetByIdEndpoint.cs",
"chars": 2218,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\nusing MinimalClean.Architecture.Web.Extensions;\nusing Microsof"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetCartHandler.cs",
"chars": 1000,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\nusing MinimalClean.Architecture.Web.Domain.CartAggregate.Speci"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/DatabaseOptions.cs",
"chars": 395,
"preview": "namespace MinimalClean.Architecture.Web.Configurations;\n\n/// <summary>\n/// Configuration options for database management"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggerConfigs.cs",
"chars": 677,
"preview": "using Serilog;\n\nnamespace MinimalClean.Architecture.Web.Configurations;\n\npublic static class LoggerConfigs\n{\n public s"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggingBehavior.cs",
"chars": 1050,
"preview": "using System.Diagnostics;\n\nnamespace Nimble.Modulith.Web;\n\npublic class LoggingBehavior<TRequest, TResponse>(ILogger<Lo"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MediatorConfig.cs",
"chars": 1058,
"preview": "namespace MinimalClean.Architecture.Web.Configurations;\n\npublic static class MediatorConfig\n{\n // Should be called from"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MiddlewareConfig.cs",
"chars": 2303,
"preview": "using Ardalis.ListStartupServices;\nusing FastEndpoints;\nusing FastEndpoints.Swagger;\nusing Microsoft.EntityFrameworkCore"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/OptionConfigs.cs",
"chars": 1459,
"preview": "using Ardalis.ListStartupServices;\nusing MinimalClean.Architecture.Web.Infrastructure.Email;\n\nnamespace MinimalClean.Arc"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Configurations/ServiceConfigs.cs",
"chars": 1075,
"preview": "using MinimalClean.Architecture.Web.Domain.Interfaces;\nusing MinimalClean.Architecture.Web.Infrastructure;\nusing Minimal"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Constants.cs",
"chars": 152,
"preview": "namespace MinimalClean.Architecture.Web;\n\npublic class Constants\n{\n public const int DEFAULT_PAGE_SIZE = 10;\n public c"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Cart.cs",
"chars": 579,
"preview": "namespace MinimalClean.Architecture.Web.Domain.CartAggregate;\n\npublic class Cart : EntityBase<Cart, CartId>, IAggregate"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartId.cs",
"chars": 357,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.CartAggregate;\n\n[ValueObject<Guid>]\npublic readonly partial"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItem.cs",
"chars": 481,
"preview": "namespace MinimalClean.Architecture.Web.Domain.CartAggregate;\n\npublic class CartItem : EntityBase<CartItem, CartItemId>\n"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItemId.cs",
"chars": 304,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.CartAggregate;\n\n[ValueObject<Guid>]\npublic readonly partial"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Specifications/CartByIdSpec.cs",
"chars": 271,
"preview": "namespace MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications;\n\npublic class CartByIdSpec : Specification<"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUser.cs",
"chars": 378,
"preview": "namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate;\n\npublic class GuestUser : EntityBase<GuestUser, Guest"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUserId.cs",
"chars": 297,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate;\n\n[ValueObject<Guid>]\npublic readonly pa"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByEmailSpec.cs",
"chars": 234,
"preview": "namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications;\n\npublic class GuestUserByEmailSpec : S"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByIdSpec.cs",
"chars": 242,
"preview": "namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications;\n\npublic class GuestUserByIdSpec : Spec"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/Interfaces/IEmailSender.cs",
"chars": 170,
"preview": "namespace MinimalClean.Architecture.Web.Domain.Interfaces;\n\npublic interface IEmailSender\n{\n Task SendEmailAsync(string"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Order.cs",
"chars": 1326,
"preview": "using MinimalClean.Architecture.Web.Domain.ProductAggregate;\nusing MinimalClean.Architecture.Web.Infrastructure.Data;\n\nn"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderId.cs",
"chars": 285,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.OrderAggregate;\n\n[ValueObject<Guid>]\npublic readonly partia"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItem.cs",
"chars": 589,
"preview": "\nusing MinimalClean.Architecture.Web.Domain.ProductAggregate;\n\nnamespace MinimalClean.Architecture.Web.Domain.OrderAggr"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItemId.cs",
"chars": 293,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.OrderAggregate;\n\n[ValueObject<Guid>]\npublic readonly partia"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Price.cs",
"chars": 287,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.OrderAggregate;\n\n[ValueObject<decimal>]\npublic readonly par"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Quantity.cs",
"chars": 389,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.OrderAggregate;\n\n[ValueObject<int>]\npublic readonly partia"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Product.cs",
"chars": 1020,
"preview": "using Ardalis.GuardClauses;\n\nnamespace MinimalClean.Architecture.Web.Domain.ProductAggregate;\n\npublic class Product : E"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/ProductId.cs",
"chars": 509,
"preview": "using Vogen;\n\nnamespace MinimalClean.Architecture.Web.Domain.ProductAggregate;\n\n[ValueObject<int>]\npublic readonly parti"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Specifications/ProductByIdSpec.cs",
"chars": 250,
"preview": "namespace MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications;\n\npublic class ProductByIdSpec : Specific"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Extensions/ResultExtensions.cs",
"chars": 3322,
"preview": "using Microsoft.AspNetCore.Http.HttpResults;\n\nnamespace MinimalClean.Architecture.Web.Extensions;\n\npublic static class "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/GlobalUsings.cs",
"chars": 123,
"preview": "global using Mediator;\nglobal using Ardalis.Result;\nglobal using Ardalis.Specification;\nglobal using Ardalis.SharedKerne"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContext.cs",
"chars": 1065,
"preview": "using System.Reflection;\nusing Microsoft.EntityFrameworkCore;\nusing MinimalClean.Architecture.Web.Domain.CartAggregate;\n"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextExtensions.cs",
"chars": 356,
"preview": "using Microsoft.EntityFrameworkCore;\n\nnamespace MinimalClean.Architecture.Web.Infrastructure.Data;\n\npublic static class "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextFactory.cs",
"chars": 1599,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Design;\n\nnamespace MinimalClean.Architecture.We"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartConfiguration.cs",
"chars": 732,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartItemConfiguration.cs",
"chars": 812,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/DataSchemaConstants.cs",
"chars": 159,
"preview": "namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config;\n\npublic static class DataSchemaConstants\n{\n public "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/GuestUserConfiguration.cs",
"chars": 684,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderConfiguration.cs",
"chars": 962,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderItemConfiguration.cs",
"chars": 1105,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/ProductConfiguration.cs",
"chars": 1012,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing MinimalClean.Architect"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenEfCoreConverters.cs",
"chars": 597,
"preview": "using MinimalClean.Architecture.Web.Domain.CartAggregate;\nusing MinimalClean.Architecture.Web.Domain.GuestUserAggregate;"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenGuidIdValueGenerator.cs",
"chars": 897,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFramework"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenIntIdValueGenerator.cs",
"chars": 1658,
"preview": "using System.Reflection;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking;\nusing "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EfRepository.cs",
"chars": 313,
"preview": "using Ardalis.Specification.EntityFrameworkCore;\n\nnamespace MinimalClean.Architecture.Web.Infrastructure.Data;\n\n// inher"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EventDispatcherInterceptor.cs",
"chars": 1290,
"preview": "using Microsoft.EntityFrameworkCore.Diagnostics;\n\nnamespace MinimalClean.Architecture.Web.Infrastructure.Data;\n\n// Inter"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.Designer.cs",
"chars": 4156,
"preview": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastruct"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.cs",
"chars": 3420,
"preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\n#pragma warning disable CA1814 // Pref"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs",
"chars": 7004,
"preview": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastruct"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.cs",
"chars": 4780,
"preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace MinimalClean.Architecture.We"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/AppDbContextModelSnapshot.cs",
"chars": 6867,
"preview": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastruct"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Queries/ListProductsQueryService.cs",
"chars": 897,
"preview": "using Microsoft.EntityFrameworkCore;\nusing MinimalClean.Architecture.Web.ProductFeatures;\nusing MinimalClean.Architectu"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/SeedData.cs",
"chars": 989,
"preview": "using Microsoft.EntityFrameworkCore;\nusing MinimalClean.Architecture.Web.Domain.ProductAggregate;\nusing Microsoft.Extens"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/FakeEmailSender.cs",
"chars": 506,
"preview": "using MinimalClean.Architecture.Web.Domain.Interfaces;\n\nnamespace MinimalClean.Architecture.Web.Infrastructure.Email;\n\np"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MailserverConfiguration.cs",
"chars": 198,
"preview": "namespace MinimalClean.Architecture.Web.Infrastructure.Email;\n\npublic class MailserverConfiguration()\n{\n public string "
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MimeKitEmailSender.cs",
"chars": 1228,
"preview": "using Microsoft.Extensions.Options;\nusing MimeKit;\nusing MinimalClean.Architecture.Web.Domain.Interfaces;\n\nnamespace Min"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/InfrastructureServiceExtensions.cs",
"chars": 1499,
"preview": "using Ardalis.GuardClauses;\nusing MinimalClean.Architecture.Web.Infrastructure.Data;\nusing MinimalClean.Architecture.Web"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/MinimalClean.Architecture.Web.csproj",
"chars": 2623,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n <Sdk Name=\"Microsoft.Build.CentralPackageVersions\" Version=\"2.1.3\" />\n\n <Prope"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/PagedResult.cs",
"chars": 162,
"preview": "namespace MinimalClean.Architecture.Web;\n\npublic record PagedResult<T>(\n IReadOnlyList<T> Items,\n int Page,\n int PerP"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/Create/CreateEndpoint.cs",
"chars": 2348,
"preview": "using FastEndpoints;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Http.HttpResults;\nusing MinimalClean.Architectur"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetByIdEndpoint.cs",
"chars": 2295,
"preview": "using FastEndpoints;\nusing FluentValidation;\nusing Microsoft.AspNetCore.Http.HttpResults;\nusing MinimalClean.Architectu"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetProductHandler.cs",
"chars": 792,
"preview": "using MinimalClean.Architecture.Web.Domain.ProductAggregate;\nusing MinimalClean.Architecture.Web.Domain.ProductAggregate"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/IListProductsQueryService.cs",
"chars": 318,
"preview": "namespace MinimalClean.Architecture.Web.ProductFeatures.List;\n\n/// <summary>\n/// Represents a service that will actually"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListEndpoint.cs",
"chars": 3891,
"preview": "using FastEndpoints;\nusing FluentValidation;\nusing MinimalClean.Architecture.Web.ProductFeatures;\n\nnamespace MinimalClea"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListProductsHandler.cs",
"chars": 748,
"preview": "namespace MinimalClean.Architecture.Web.ProductFeatures.List;\n\npublic record ListProductsQuery(int? Page = 1,\n int? Pe"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductDto.cs",
"chars": 191,
"preview": "using MinimalClean.Architecture.Web.Domain.ProductAggregate;\n\nnamespace MinimalClean.Architecture.Web.ProductFeatures;\np"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductRecord.cs",
"chars": 127,
"preview": "namespace MinimalClean.Architecture.Web.ProductFeatures;\n\npublic record ProductRecord(int Id, string Name, decimal UnitP"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Program.cs",
"chars": 1112,
"preview": "using FastEndpoints;\nusing FastEndpoints.Swagger;\nusing MinimalClean.Architecture.Web.Configurations;\nusing Serilog;\n\nv"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/Properties/launchSettings.json",
"chars": 278,
"preview": "{\n \"profiles\": {\n \"https\": {\n \"commandName\": \"Project\",\n \"dotnetRunMessages\": true,\n \"launchUrl\": \"sc"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/api.http",
"chars": 1103,
"preview": "@MinimalClean_HostAddress = https://localhost:57379\n\n@MinimalClean_CartId = 68fe4cfd-84bb-4b8a-bb4e-528c26325c72\n\n### Li"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/appsettings.Development.json",
"chars": 231,
"preview": "{\n \"DatabaseOptions\": {\n \"RecreateOnStartup\": true\n },\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Informati"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/appsettings.json",
"chars": 773,
"preview": "{\n \"ConnectionStrings\": {\n \"AppDb\": \"Server=(localdb)\\\\mssqllocaldb;Database=MinimalCleanArchitecture;Trusted_Conne"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/config.nsdepcop",
"chars": 751,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<NsDepCopConfig>\n <Allowed From=\"*\" To=\"*\" />\n\n <Disallowed From=\"MinimalC"
},
{
"path": "MinimalClean/src/MinimalClean.Architecture.Web/wwwroot/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "MinimalClean.nuspec",
"chars": 1715,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n <me"
},
{
"path": "PARALLEL_TEST_EXECUTION.md",
"chars": 3056,
"preview": "# Parallel Test Execution Configuration\n\nThis workspace is configured to run all three test projects in parallel in Visu"
},
{
"path": "README.md",
"chars": 28081,
"preview": "[](https://github.com/ardalis/"
},
{
"path": "README.template.md",
"chars": 842,
"preview": "# ${name}\n\nWelcome to your new project generated with the Clean Architecture template!\n\n## Getting Started\n\n- Build the "
},
{
"path": "TESTCONTAINERS_IMPLEMENTATION.md",
"chars": 2786,
"preview": "# Testcontainers Implementation for Functional Tests\n\n## Summary\n\nSuccessfully migrated functional tests from in-memory "
},
{
"path": "docs/architecture-decisions/README.md",
"chars": 3919,
"preview": "# Architecture Decision Records (ADR)\n\n## What is an Architecture Decision Record (ADR)?\nAn Architecture Decision Record"
},
{
"path": "docs/architecture-decisions/adr-001-dotnet-di-adoption.md",
"chars": 2142,
"preview": "# ADR 001: Replace Autofac with .NET Core Dependency Injection\n\n## Status\nAccepted\n\n## Context\nInitially, this repositor"
},
{
"path": "docs/minimal-clean-architecture.md",
"chars": 12349,
"preview": "# Minimal Clean Architecture\n\n## Overview\n\nThe **Minimal Clean Architecture** template provides a simplified, pragmatic "
},
{
"path": "global.json",
"chars": 107,
"preview": "{\n \"sdk\": {\n \"version\": \"10.0.100\",\n \"rollForward\": \"latestMajor\",\n \"allowPrerelease\": true\n }\n}"
},
{
"path": "nuget.config",
"chars": 944,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <packageRestore>\n <add key=\"enabled\" value=\"True\" />\n"
},
{
"path": "sample/.editorconfig",
"chars": 6711,
"preview": "###############################\n# Core EditorConfig Options #\n###############################\nroot = true\n# All files\n"
},
{
"path": "sample/.github/copilot-instructions.md",
"chars": 4273,
"preview": "# Solution Development Practices & Conventions\n\nThis document provides guidance for contributing to this solution, whic"
},
{
"path": "sample/.runsettings",
"chars": 181,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RunSettings>\n <RunConfiguration>\n <MaxCpuCount>0</MaxCpuCount> <!-- 0 = use "
},
{
"path": "sample/Directory.Build.props",
"chars": 439,
"preview": "<Project>\n <PropertyGroup>\n <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n <TreatWarnings"
},
{
"path": "sample/Directory.Packages.props",
"chars": 4564,
"preview": "<Project>\n <ItemGroup>\n <PackageVersion Include=\"Ardalis.GuardClauses\" Version=\"5.0.0\" />\n <PackageVersion Includ"
},
{
"path": "sample/NimblePros.SampleToDo.slnx",
"chars": 1597,
"preview": "<Solution>\n <Configurations>\n <Platform Name=\"Any CPU\" />\n <Platform Name=\"x64\" />\n <Platform Name=\"x86\" />\n "
},
{
"path": "sample/src/NimblePros.SampleToDo.AspireHost/NimblePros.SampleToDo.AspireHost.csproj",
"chars": 885,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"9.5.1\" />\n\n <PropertyGroup>\n <OutputTyp"
},
{
"path": "sample/src/NimblePros.SampleToDo.AspireHost/Program.cs",
"chars": 1167,
"preview": "using System.Net.Sockets;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\n// Papercut container\nvar papercu"
},
{
"path": "sample/src/NimblePros.SampleToDo.AspireHost/Properties/launchSettings.json",
"chars": 1003,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n \"profiles\": {\n \"https\": {\n \"commandName\": \""
},
{
"path": "sample/src/NimblePros.SampleToDo.AspireHost/appsettings.Development.json",
"chars": 119,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\"\n }\n }\n}\n"
},
{
"path": "sample/src/NimblePros.SampleToDo.AspireHost/appsettings.json",
"chars": 158,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\",\n \"Aspir"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Contributor.cs",
"chars": 556,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate.Events;\n\nnamespace NimblePros.SampleToDo.Core.ContributorAggregat"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorId.cs",
"chars": 279,
"preview": "using Vogen;\n\nnamespace NimblePros.SampleToDo.Core.ContributorAggregate;\n\n[ValueObject<int>]\npublic partial struct Cont"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorName.cs",
"chars": 494,
"preview": "using Vogen;\n\nnamespace NimblePros.SampleToDo.Core.ContributorAggregate;\n\n[ValueObject<string>(conversions: Conversions"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorDeletedEvent.cs",
"chars": 406,
"preview": "namespace NimblePros.SampleToDo.Core.ContributorAggregate.Events;\n\n/// <summary>\n/// A domain event that is dispatched "
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorNameUpdatedEvent.cs",
"chars": 233,
"preview": "namespace NimblePros.SampleToDo.Core.ContributorAggregate.Events;\n\npublic sealed class ContributorNameUpdatedEvent(Cont"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorDeletedHandler.cs",
"chars": 1450,
"preview": "using Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.ContributorAggregate.Events;\nusing NimblePros.Samp"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorNameUpdatedEventLoggingHandler.cs",
"chars": 805,
"preview": "using Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.ContributorAggregate.Events;\n\nnamespace NimblePros"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Specifications/ContributorByIdSpec.cs",
"chars": 323,
"preview": "namespace NimblePros.SampleToDo.Core.ContributorAggregate.Specifications;\n\npublic class ContributorByIdSpec : Specifica"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/CoreServiceExtensions.cs",
"chars": 615,
"preview": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.In"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/GlobalUsings.cs",
"chars": 194,
"preview": "global using Ardalis.GuardClauses;\nglobal using Ardalis.Result;\nglobal using Ardalis.SmartEnum;\nglobal using Ardalis.Sp"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Interfaces/IDeleteContributorService.cs",
"chars": 355,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\n\nnamespace NimblePros.SampleToDo.Core.Interfaces;\n\npublic interf"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Interfaces/IEmailSender.cs",
"chars": 161,
"preview": "namespace NimblePros.SampleToDo.Core.Interfaces;\n\npublic interface IEmailSender\n{\n Task SendEmailAsync(string to, stri"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Interfaces/IToDoItemSearchService.cs",
"chars": 322,
"preview": "using NimblePros.SampleToDo.Core.ProjectAggregate;\n\nnamespace NimblePros.SampleToDo.Core.Interfaces;\n\npublic interface "
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Localization.cs",
"chars": 715,
"preview": "using Microsoft.Extensions.Localization;\n\n/// <summary>\n/// Exposes the current <see cref=\"IStringLocalizer\"/> to stati"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/NimblePros.SampleToDo.Core.csproj",
"chars": 595,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n <ItemGroup>\n <PackageReference Include=\"Ardalis.GuardClauses\" />\n <PackageRef"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ContributorAddedToItemEvent.cs",
"chars": 348,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\n\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\n"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/NewItemAddedEvent.cs",
"chars": 276,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\npublic sealed class NewItemAddedEvent(Project project, T"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ToDoItemCompletedEvent.cs",
"chars": 224,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\npublic sealed class ToDoItemCompletedEvent(ToDoItem comp"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ContributorAddedToItemLoggingHandler.cs",
"chars": 676,
"preview": "using Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\nnamespace NimblePros.Sam"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ItemCompletedEmailNotificationHandler.cs",
"chars": 1000,
"preview": "using NimblePros.SampleToDo.Core.Interfaces;\nusing NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\nnamespace Nimbl"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/NewItemAddedLoggingHandler.cs",
"chars": 609,
"preview": "using Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.ProjectAggregate.Events;\n\nnamespace NimblePros.Sam"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Priority.cs",
"chars": 315,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\npublic class Priority : SmartEnum<Priority>\n{\n public static r"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Project.cs",
"chars": 963,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate.Events;\nusing NimblePros.SampleToDo.Core.ProjectAggregate.Events;"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectErrorMessages.cs",
"chars": 2832,
"preview": "// Core/ProjectAggregate/ProjectMessages.cs\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\n/// <summary>\n/// S"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectId.cs",
"chars": 122,
"preview": "using Vogen;\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\n[ValueObject<int>]\npublic partial struct ProjectId"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectName.cs",
"chars": 730,
"preview": "using Vogen;\n\n[assembly: VogenDefaults(\n staticAbstractsGeneration: StaticAbstractsGeneration.MostCommon | Stati"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectStatus.cs",
"chars": 201,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\npublic enum ProjectStatus\n{\n InProgress, // NOTE: Better to us"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSearchSpec.cs",
"chars": 363,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications;\n\npublic class IncompleteItemsSearchSpec : Specifi"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSpec.cs",
"chars": 213,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications;\n\npublic class IncompleteItemsSpec : Specification"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectByIdWithItemsSpec.cs",
"chars": 307,
"preview": "namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications;\n\npublic class ProjectByIdWithItemsSpec : Specific"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectsWithItemsByContributorId.cs",
"chars": 434,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\n\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifica"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItem.cs",
"chars": 1932,
"preview": "using System.Xml.Linq;\nusing NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo.Core.ProjectA"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemDescription.cs",
"chars": 552,
"preview": "using Vogen;\n\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\n[ValueObject<string>(conversions: Conversions.Sys"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemId.cs",
"chars": 123,
"preview": "using Vogen;\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\n[ValueObject<int>]\npublic partial struct ToDoItemI"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemTitle.cs",
"chars": 516,
"preview": "using Vogen;\n\nnamespace NimblePros.SampleToDo.Core.ProjectAggregate;\n\n[ValueObject<string>(conversions: Conversions.Sys"
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Services/DeleteContributorService.cs",
"chars": 1200,
"preview": "using Microsoft.Extensions.Logging;\nusing NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo."
},
{
"path": "sample/src/NimblePros.SampleToDo.Core/Services/ToDoItemSearchService.cs",
"chars": 2018,
"preview": "using NimblePros.SampleToDo.Core.Interfaces;\nusing NimblePros.SampleToDo.Core.ProjectAggregate;\nusing NimblePros.Sample"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/AppDbContext.cs",
"chars": 989,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo.Core.ProjectAggregate;\n\nnamespace Ni"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ContributorConfiguration.cs",
"chars": 596,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\n\nnamespace NimblePros.SampleToDo.Infrastructure.Data.Config;\n\npu"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/DataSchemaConstants.cs",
"chars": 152,
"preview": "namespace NimblePros.SampleToDo.Infrastructure.Data.Config;\n\npublic static class DataSchemaConstants\n{\n public const i"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ProjectConfiguration.cs",
"chars": 549,
"preview": "using NimblePros.SampleToDo.Core.ProjectAggregate;\n\nnamespace NimblePros.SampleToDo.Infrastructure.Data.Config;\n\npublic"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ToDoItemConfiguration.cs",
"chars": 1131,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo.Core.ProjectAggregate;\n\nnamespace Ni"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/VogenEfCoreConverters.cs",
"chars": 458,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo.Core.ProjectAggregate;\nusing Vogen;\n"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/VogenIdValueGenerator.cs",
"chars": 1558,
"preview": "using Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing NimblePr"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/EfRepository.cs",
"chars": 326,
"preview": "using NimblePros.SharedKernel;\n\nnamespace NimblePros.SampleToDo.Infrastructure.Data;\n\n// inherit from Ardalis.Specifica"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/EventDispatchInterceptor.cs",
"chars": 1310,
"preview": "using Microsoft.EntityFrameworkCore.Diagnostics;\nusing NimblePros.SharedKernel;\n\nnamespace NimblePros.SampleToDo.Infras"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListContributorsQueryService.cs",
"chars": 830,
"preview": "using NimblePros.SampleToDo.Core.ContributorAggregate;\nusing NimblePros.SampleToDo.UseCases;\nusing NimblePros.SampleToD"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListIncompleteItemsQueryService.cs",
"chars": 603,
"preview": "using NimblePros.SampleToDo.Core.ProjectAggregate;\nusing NimblePros.SampleToDo.UseCases.Projects;\nusing NimblePros.Samp"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListProjectsShallowQueryService.cs",
"chars": 469,
"preview": "using NimblePros.SampleToDo.UseCases.Projects;\nusing NimblePros.SampleToDo.UseCases.Projects.ListShallow;\n\nnamespace Ni"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListContributorsQueryService.cs",
"chars": 1079,
"preview": "using NimblePros.SampleToDo.UseCases;\nusing NimblePros.SampleToDo.UseCases.Contributors;\nusing NimblePros.SampleToDo.Us"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListIncompleteItemsQueryService.cs",
"chars": 898,
"preview": "using NimblePros.SampleToDo.UseCases.Projects;\nusing NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems;\n\nname"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListProjectsShallowQueryService.cs",
"chars": 619,
"preview": "using NimblePros.SampleToDo.UseCases.Projects;\nusing NimblePros.SampleToDo.UseCases.Projects.ListShallow;\n\nnamespace Ni"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Email/FakeEmailSender.cs",
"chars": 536,
"preview": "using NimblePros.SampleToDo.Core.Interfaces;\n\nnamespace NimblePros.SampleToDo.Infrastructure.Email;\n\npublic class FakeE"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Email/MailserverConfiguration.cs",
"chars": 242,
"preview": "namespace NimblePros.SampleToDo.Infrastructure.Email;\n\npublic class MailserverConfiguration()\n{\n public const string S"
},
{
"path": "sample/src/NimblePros.SampleToDo.Infrastructure/Email/MimeKitEmailSender.cs",
"chars": 1488,
"preview": "using Microsoft.Extensions.Options;\nusing MimeKit;\nusing NimblePros.SampleToDo.Core.Interfaces;\n\nnamespace NimblePros.S"
}
]
// ... and 295 more files (download for full content)
About this extraction
This page contains the full source code of the ardalis/CleanArchitecture GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 495 files (2.1 MB), approximately 574.1k tokens, and a symbol index with 2016 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.