├── .editorconfig
├── .github
└── workflows
│ ├── build-and-push-nuget.yaml
│ └── build-and-test.yml
├── .gitignore
├── Directory.Build.props
├── Directory.Packages.props
├── LICENSE
├── README.md
├── Resrcify.SharedKernel.sln
├── samples
└── Resrcify.SharedKernel.WebApiExample
│ ├── .dockerignore
│ ├── .editorconfig
│ ├── .gitignore
│ ├── Directory.Build.props
│ ├── Dockerfile
│ ├── README.md
│ ├── Resrcify.SharedKernel.WebApiExample.sln
│ ├── docker-compose.override.yml
│ ├── docker-compose.yml
│ ├── images
│ ├── ArchitecturalTests.PNG
│ ├── CompanyDatastore.PNG
│ ├── ContactDatastore.PNG
│ ├── ManualCachingOfQueries.PNG
│ ├── ManualCreateCompany.PNG
│ ├── ManualCreateContact.PNG
│ ├── ManualGetAllCompanies.PNG
│ ├── ManualGetCompanyById.PNG
│ ├── ManualRemoveContactByEmail.PNG
│ ├── ManualSendEventOnCompanyCreation.PNG
│ ├── ManualSendEventOnCompanyNameChange.PNG
│ ├── ManualUpdateCompanyName.PNG
│ ├── ManualUpdateContactByEmail.PNG
│ └── UnitTests.PNG
│ ├── src
│ ├── Resrcify.SharedKernel.WebApiExample.Application
│ │ ├── Abstractions
│ │ │ └── Repositories
│ │ │ │ └── ICompanyRepository.cs
│ │ ├── ApplicationServiceRegistration.cs
│ │ ├── Features
│ │ │ └── Companies
│ │ │ │ ├── AddContact
│ │ │ │ ├── AddContactCommand.cs
│ │ │ │ ├── AddContactCommandHandler.cs
│ │ │ │ └── AddContactCommandRequest.cs
│ │ │ │ ├── CompanyCreated
│ │ │ │ └── CompanyCreatedEventHandler.cs
│ │ │ │ ├── CompanyNameUpdated
│ │ │ │ └── CompanyNameUpdatedEventHandler.cs
│ │ │ │ ├── CreateCompany
│ │ │ │ ├── CreateCompanyCommand.cs
│ │ │ │ ├── CreateCompanyCommandHandler.cs
│ │ │ │ └── CreateCompanyCommandRequest.cs
│ │ │ │ ├── GetAllCompanies
│ │ │ │ ├── GetAllCompaniesQuery.cs
│ │ │ │ ├── GetAllCompaniesQueryHandler.cs
│ │ │ │ └── GetAllCompaniesQueryResponse.cs
│ │ │ │ ├── GetCompanyById
│ │ │ │ ├── GetCompanyByIdQuery.cs
│ │ │ │ ├── GetCompanyByIdQueryHandler.cs
│ │ │ │ └── GetCompanyByIdQueryResponse.cs
│ │ │ │ ├── RemoveContact
│ │ │ │ ├── RemoveContactCommand.cs
│ │ │ │ ├── RemoveContactCommandHandler.cs
│ │ │ │ └── RemoveContactCommandRequest.cs
│ │ │ │ ├── UpdateCompanyName
│ │ │ │ ├── UpdateCompanyNameCommand.cs
│ │ │ │ ├── UpdateCompanyNameCommandHandler.cs
│ │ │ │ └── UpdateCompanyNameCommandRequest.cs
│ │ │ │ └── UpdateContactByEmail
│ │ │ │ ├── UpdateContactByEmailCommand.cs
│ │ │ │ ├── UpdateContactByEmailCommandHandler.cs
│ │ │ │ └── UpdateContactByEmailCommandRequest.cs
│ │ └── Resrcify.SharedKernel.WebApiExample.Application.csproj
│ ├── Resrcify.SharedKernel.WebApiExample.Domain
│ │ ├── AssemblyFlag.cs
│ │ ├── Errors
│ │ │ └── DomainErrors.Company.cs
│ │ ├── Features
│ │ │ └── Companies
│ │ │ │ ├── Company.cs
│ │ │ │ ├── Entities
│ │ │ │ └── Contact.cs
│ │ │ │ ├── Enums
│ │ │ │ └── CompanyType.cs
│ │ │ │ ├── Events
│ │ │ │ ├── CompanyCreatedEvent.cs
│ │ │ │ └── CompanyNameUpdatedEvent.cs
│ │ │ │ └── ValueObjects
│ │ │ │ ├── CompanyId.cs
│ │ │ │ ├── ContactId.cs
│ │ │ │ ├── Email.cs
│ │ │ │ ├── Name.cs
│ │ │ │ └── OrganizationNumber.cs
│ │ └── Resrcify.SharedKernel.WebApiExample.Domain.csproj
│ ├── Resrcify.SharedKernel.WebApiExample.Infrastructure
│ │ ├── InfrastructureServiceRegistration.cs
│ │ └── Resrcify.SharedKernel.WebApiExample.Infrastructure.csproj
│ ├── Resrcify.SharedKernel.WebApiExample.Persistence
│ │ ├── AppDbContext.cs
│ │ ├── AppDbContextFactory.cs
│ │ ├── Configurations
│ │ │ └── Companies
│ │ │ │ ├── CompanyConfiguration.cs
│ │ │ │ └── ContactConfiguration.cs
│ │ ├── Migrations
│ │ │ ├── 20241021160202_InitialMigration.Designer.cs
│ │ │ ├── 20241021160202_InitialMigration.cs
│ │ │ └── AppDbContextModelSnapshot.cs
│ │ ├── PersistenceServiceRegistration.cs
│ │ ├── Repositories
│ │ │ └── CompanyRepository.cs
│ │ └── Resrcify.SharedKernel.WebApiExample.Persistence.csproj
│ ├── Resrcify.SharedKernel.WebApiExample.Presentation
│ │ ├── Controllers
│ │ │ └── CompanyController.cs
│ │ ├── PresentationServiceRegistration.cs
│ │ └── Resrcify.SharedKernel.WebApiExample.Presentation.csproj
│ └── Resrcify.SharedKernel.WebApiExample.Web
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── launchSettings.json
│ │ ├── Resrcify.SharedKernel.WebApiExample.Web.csproj
│ │ ├── Startup.cs
│ │ ├── appsettings.Development.json
│ │ └── appsettings.json
│ └── tests
│ ├── Resrcify.SharedKernel.WebApiExample.ArchitectureTests
│ ├── Extensions
│ │ └── NetArchTestExtensions.cs
│ ├── Helpers
│ │ └── BaseTest.cs
│ ├── Resrcify.SharedKernel.WebApiExample.ArchitectureTests.csproj
│ └── Tests
│ │ ├── ApplicationTests.cs
│ │ ├── DomainTests.cs
│ │ ├── LayerTests.cs
│ │ └── PresentationTests.cs
│ └── Resrcify.SharedKernel.WebApiExample.Domain.UnitTests
│ ├── Companies
│ ├── CompanyIdsTests.cs
│ ├── CompanyTests.cs
│ ├── ContactIdTests.cs
│ ├── ContactTests.cs
│ ├── EmailTests.cs
│ ├── NameTests.cs
│ └── OrganizationNumberTests.cs
│ └── Resrcify.SharedKernel.WebApiExample.Domain.UnitTests.csproj
├── src
├── Resrcify.SharedKernel.Caching
│ ├── Abstractions
│ │ └── ICachingService.cs
│ ├── LICENSE
│ ├── Primitives
│ │ └── InMemoryCachingService.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.Caching.csproj
├── Resrcify.SharedKernel.DomainDrivenDesign
│ ├── Abstractions
│ │ ├── IAggregateRoot.cs
│ │ ├── IAuditableEntity.cs
│ │ ├── IDeletableEntity.cs
│ │ └── IDomainEvent.cs
│ ├── LICENSE
│ ├── Primitives
│ │ ├── AggregateRoot.cs
│ │ ├── DomainEvent.cs
│ │ ├── Entity.cs
│ │ ├── Enumeration.cs
│ │ └── ValueObject.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.DomainDrivenDesign.csproj
├── Resrcify.SharedKernel.Messaging
│ ├── Abstractions
│ │ ├── ICachingQuery.cs
│ │ ├── ICommand.cs
│ │ ├── ICommandHandler.cs
│ │ ├── IDomainEventHandler.cs
│ │ ├── IQuery.cs
│ │ ├── IQueryHandler.cs
│ │ └── ITransactionCommand.cs
│ ├── Behaviors
│ │ ├── CachingPipelineBehavior.cs
│ │ ├── LoggingPipelineBehavior.cs
│ │ ├── TransactionPipelineBehavior.cs
│ │ ├── UnitOfWorkPipelineBehavior.cs
│ │ └── ValidationPipelineBehavior.cs
│ ├── LICENSE
│ ├── README.md
│ └── Resrcify.SharedKernel.Messaging.csproj
├── Resrcify.SharedKernel.Repository
│ ├── Abstractions
│ │ └── IRepository.cs
│ ├── Extensions
│ │ └── QueryableExtensions.cs
│ ├── LICENSE
│ ├── Primitives
│ │ ├── Repository.cs
│ │ ├── ResultRepository.cs
│ │ ├── Specification.cs
│ │ └── SpecificationEvaluator.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.Repository.csproj
├── Resrcify.SharedKernel.ResultFramework
│ ├── LICENSE
│ ├── Primitives
│ │ ├── Error.cs
│ │ ├── ErrorType.cs
│ │ ├── Result.cs
│ │ ├── ResultExtensions.cs
│ │ └── ResultT.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.ResultFramework.csproj
├── Resrcify.SharedKernel.UnitOfWork
│ ├── Abstractions
│ │ └── IUnitOfWork.cs
│ ├── BackgroundJobs
│ │ ├── ProcessOutboxMessagesJob.cs
│ │ ├── ProcessOutboxMessagesJobSetup.cs
│ │ ├── ProcessOutboxMessagesNewtonsoftJob.cs
│ │ └── ProcessOutboxMessagesNewtonsoftJobSetup.cs
│ ├── Converters
│ │ └── DomainEventConverter.cs
│ ├── Extensions
│ │ └── MigrationExtensions.cs
│ ├── Interceptors
│ │ ├── InsertOutboxMessagesInterceptor.cs
│ │ ├── InsertOutboxMessagesNewtonsoftInterceptor.cs
│ │ ├── UpdateAuditableEntitiesInterceptor.cs
│ │ └── UpdateDeletableEntitiesInterceptor.cs
│ ├── LICENSE
│ ├── Outbox
│ │ └── OutboxMessage.cs
│ ├── Primitives
│ │ └── UnitOfWork.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.UnitOfWork.csproj
└── Resrcify.SharedKernel.Web
│ ├── Extensions
│ ├── InternalControllersExtensions.cs
│ └── ResultExtensions.cs
│ ├── LICENSE
│ ├── Primitives
│ └── ApiController.cs
│ ├── README.md
│ └── Resrcify.SharedKernel.Web.csproj
└── tests
├── Resrcify.SharedKernel.Caching.UnitTests
├── Primitives
│ └── DistributedCachingServiceTests.cs
└── Resrcify.SharedKernel.Caching.UnitTests.csproj
├── Resrcify.SharedKernel.DomainDrivenDesign.UnitTests
├── Primitives
│ ├── AggregateRootTests.cs
│ ├── DomainEventTests.cs
│ ├── EntityTests.cs
│ ├── EnumerationTests.cs
│ └── ValueObjectTests.cs
└── Resrcify.SharedKernel.DomainDrivenDesign.UnitTests.csproj
├── Resrcify.SharedKernel.Messaging.UnitTests
├── Behaviors
│ ├── CachingPipelineBehaviorTests.cs
│ ├── LoggingPipelineBehaviorTests.cs
│ ├── TransactionPipelineBehaviorTests.cs
│ ├── UnitOfWorkPipelineBehaviorTests.cs
│ └── ValidationPipelineBehaviorTests.cs
└── Resrcify.SharedKernel.Messaging.UnitTests.csproj
├── Resrcify.SharedKernel.Repository.UnitTests
├── Extensions
│ └── QueryableExtensionsTests.cs
├── Models
│ ├── Child.cs
│ ├── DbSetupBase.cs
│ ├── Person.cs
│ ├── PersonSpecification.cs
│ ├── SocialSecurityNumber.cs
│ ├── TestDbContext.cs
│ └── TestRepository.cs
├── Primitives
│ ├── RepositoryTests.cs
│ ├── SpecificationEvaluatorTests.cs
│ └── SpecificationTests.cs
└── Resrcify.SharedKernel.Repository.UnitTests.csproj
├── Resrcify.SharedKernel.ResultFramework.UnitTests
├── Primitives
│ ├── ErrorTests.cs
│ ├── ResultExtensionsTests.cs
│ ├── ResultTTests.cs
│ └── ResultTests.cs
└── Resrcify.SharedKernel.ResultFramework.UnitTests.csproj
├── Resrcify.SharedKernel.UnitOfWork.UnitTests
├── BackgroundJobs
│ └── ProcessOutboxMessagesJobTests.cs
├── Interceptors
│ ├── InsertOutboxMessagesInterceptorTests.cs
│ ├── UpdateAuditableEntitiesInterceptorTests.cs
│ └── UpdateDeletableEntitiesInterceptorTests.cs
├── Models
│ ├── Child.cs
│ ├── DbSetupBase.cs
│ ├── Person.cs
│ ├── SocialSecurityNumber.cs
│ ├── TestDbContext.cs
│ └── TestDomainEvent.cs
├── Primitives
│ └── UnitOfWorkTests.cs
└── Resrcify.SharedKernel.UnitOfWork.UnitTests.csproj
└── Resrcify.SharedKernel.Web.UnitTests
├── Extensions
├── InternalControllersExtensionTests.cs
└── ResultExtensionsTests.cs
├── Primitives
└── ApiControllerTests.cs
└── Resrcify.SharedKernel.Web.UnitTests.csproj
/.github/workflows/build-and-push-nuget.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | tags:
4 | - "[0-9]+.[0-9]+.[0-9]+"
5 | jobs:
6 | tests:
7 | uses: ./.github/workflows/build-and-test.yml
8 | docker:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 15
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v3
14 |
15 | - name: Verify commit exists in origin/master
16 | run: |
17 | git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
18 | git branch --remote --contains | grep origin/master
19 |
20 | - name: Set VERSION variable from tag
21 | run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
22 | - name: Setup .NET
23 | uses: actions/setup-dotnet@v3
24 | with:
25 | dotnet-version: |
26 | 8.x.x
27 | 9.x.x
28 | - name: Build
29 | run: dotnet build --configuration Release /p:Version=${VERSION}
30 | - name: Pack
31 | run: dotnet pack --configuration Release /p:Version=${VERSION} --no-build --output .
32 | - name: List generated packages
33 | run: ls *.nupkg
34 | - name: Push Packages to NuGet
35 | run: |
36 | for package in *.nupkg; do
37 | dotnet nuget push "$package" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
38 | done
39 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-test.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a .NET project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3 |
4 | name: build-and-test
5 |
6 | on:
7 | push:
8 | branches: ["master"]
9 | pull_request:
10 | branches: ["master"]
11 | workflow_call:
12 |
13 | jobs:
14 | build:
15 | name: test
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - uses: actions/checkout@v3
20 | - name: Setup .NET
21 | uses: actions/setup-dotnet@v3
22 | with:
23 | dotnet-version: |
24 | 8.x.x
25 | 9.x.x
26 | - name: Restore dependencies
27 | run: dotnet restore
28 | - name: Build
29 | run: dotnet build --no-restore
30 | - name: Test
31 | run: dotnet test --no-build --verbosity normal
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # From .NET Core 3.0 you can use the command: `dotnet new gitignore` to generate a customizable .gitignore file
2 |
3 | *.swp
4 | *.*~
5 | project.lock.json
6 | .DS_Store
7 | *.pyc
8 |
9 | # Visual Studio Code
10 | .vscode
11 |
12 | # User-specific files
13 | *.suo
14 | *.user
15 | *.userosscache
16 | *.sln.docstates
17 |
18 | # Build results
19 | [Dd]ebug/
20 | [Dd]ebugPublic/
21 | [Rr]elease/
22 | [Rr]eleases/
23 | x64/
24 | x86/
25 | build/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | msbuild.log
30 | msbuild.err
31 | msbuild.wrn
32 |
33 | # Visual Studio 2015
34 | .vs/
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0;net9.0
4 | Rickard Marjanovic (@rmarjanovic)
5 | Resrcify AB
6 | enable
7 | disable
8 | latest
9 | all
10 | true
11 | true
12 | true
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Resrcify
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Resrcify.SharedKernel
2 |
3 | # Description
4 | Implemented a Clean Architecture Shared Kernel, including the building blocks for Domain Driven Design and the Result pattern, to be used in internal projects.
5 | The different modules are seperated into different NuGet packages using pipelines and published on the public package manager for .NET.
6 |
7 | # Table of Contents
8 | ## Modules
9 | - [Caching](src/Resrcify.SharedKernel.Caching/)
10 | - [Domain-Driven Design](src/Resrcify.SharedKernel.DomainDrivenDesign/)
11 | - [Messaging](src/Resrcify.SharedKernel.Messaging/)
12 | - [Result Framework](src/Resrcify.SharedKernel.ResultFramework/)
13 | - [Repository](src/Resrcify.SharedKernel.Repository/)
14 | - [Unit Of Work](src/Resrcify.SharedKernel.UnitOfWork/)
15 | - [Web](src/Resrcify.SharedKernel.Web/)
16 | ## Samples
17 | - [Web Api Example](samples/Resrcify.SharedKernel.WebApiExample/)
18 |
19 | ## Contributions
20 | First off, thank you for considering contributing to this project. We appreciate any contributions, from reporting issues to writing code, improving documentation, and suggesting new features.
21 |
22 | ### Contribution Process
23 |
24 | 1. **Fork the repository**: Click the "Fork" button at the top of the repository page.
25 | 2. **Clone your fork**:
26 | ```bash
27 | git clone https://github.com/Resrcify/Resrcify.SharedKernel.git
28 | ```
29 | 3. **Create a branch** for your changes:
30 | ```bash
31 | git checkout -b feature/your-feature-name
32 | ```
33 | 4. **Make your changes**: Ensure your code follows the project’s coding style by implementing / using the .editorconfig as provided in this repository.
34 | 5. **Write tests** (if applicable) to ensure the functionality works as expected.
35 | 6. **Commit your changes**: Write clear and concise commit messages.
36 | ```bash
37 | git commit -m "Add feature or fix bug"
38 | ```
39 | 7. **Push your branch**:
40 | ```bash
41 | git push origin feature/your-feature-name
42 | ```
43 | 8. **Create a pull request**: Submit a PR to the `master` branch on the original repository. In your PR description, explain the changes you’ve made and reference any related issues.
44 |
45 | # Credits
46 | Inspired by [Milan Jovanovic](https://www.youtube.com/@MilanJovanovicTech)'s Clean Architecture series to create this Shared Kernel.
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/bin
15 | **/charts
16 | **/docker-compose*
17 | **/compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | README.md
25 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/.gitignore:
--------------------------------------------------------------------------------
1 | # From .NET Core 3.0 you can use the command: `dotnet new gitignore` to generate a customizable .gitignore file
2 |
3 | *.swp
4 | *.*~
5 | project.lock.json
6 | .DS_Store
7 | *.pyc
8 | *.db
9 | # Visual Studio Code
10 | .vscode
11 |
12 | # User-specific files
13 | *.suo
14 | *.user
15 | *.userosscache
16 | *.sln.docstates
17 |
18 | # Build results
19 | [Dd]ebug/
20 | [Dd]ebugPublic/
21 | [Rr]elease/
22 | [Rr]eleases/
23 | x64/
24 | x86/
25 | build/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | msbuild.log
30 | msbuild.err
31 | msbuild.wrn
32 |
33 | # Visual Studio 2015
34 | .vs/
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0
4 | enable
5 | disable
6 | false
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS base
2 | WORKDIR /app
3 | EXPOSE 11000
4 |
5 | ENV ASPNETCORE_URLS=http://+:11000
6 | ENV ASPNETCORE_ENVIRONMENT ASPNETCORE_ENVIRONMENT
7 |
8 | # Creates a non-root user with an explicit UID and adds permission to access the /app folder
9 | # For more info, please refer to https://aka.ms/vscode-docker-dotnet-configure-containers
10 | RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
11 | USER appuser
12 |
13 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
14 |
15 | # copy all the layers' csproj files into respective folders
16 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Domain/Resrcify.SharedKernel.WebApiExample.Domain.csproj", "Resrcify.SharedKernel.WebApiExample.Domain/"]
17 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Application/Resrcify.SharedKernel.WebApiExample.Application.csproj", "Resrcify.SharedKernel.WebApiExample.Application/"]
18 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Infrastructure/Resrcify.SharedKernel.WebApiExample.Infrastructure.csproj", "Resrcify.SharedKernel.WebApiExample.Infrastructure/"]
19 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Persistence/Resrcify.SharedKernel.WebApiExample.Persistence.csproj", "Resrcify.SharedKernel.WebApiExample.Persistence/"]
20 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Presentation/Resrcify.SharedKernel.WebApiExample.Presentation.csproj", "Resrcify.SharedKernel.WebApiExample.Presentation/"]
21 | COPY ["src/Resrcify.SharedKernel.WebApiExample.Web/Resrcify.SharedKernel.WebApiExample.Web.csproj", "Resrcify.SharedKernel.WebApiExample.Web/"]
22 |
23 | RUN dotnet restore "Resrcify.SharedKernel.WebApiExample.Web/Resrcify.SharedKernel.WebApiExample.Web.csproj"
24 |
25 | # WORKDIR /app
26 | COPY . .
27 | RUN dotnet build -c Release --property:OutputPath=/app/build
28 |
29 | FROM build AS publish
30 | RUN dotnet publish -c Release --property:PublishDir=/app/publish
31 |
32 | FROM base AS final
33 | WORKDIR /app
34 | COPY --from=publish /app/publish .
35 | ENTRYPOINT ["dotnet", "Resrcify.SharedKernel.WebApiExample.Web.dll"]
36 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/docker-compose.override.yml:
--------------------------------------------------------------------------------
1 | services:
2 | webapiexample:
3 | environment:
4 | - ASPNETCORE_ENVIRONMENT=Development
5 | build:
6 | context: ./
7 | dockerfile: Dockerfile
8 | ports:
9 | - 11000:11000
10 |
11 | webapiexampledb:
12 | ports:
13 | - 5440:5432
14 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | webapiexample:
3 | image: webapiexample:latest
4 | container_name: Resrcify.WebApiExample
5 | restart: always
6 | depends_on:
7 | - webapiexampledb
8 |
9 | webapiexampledb:
10 | image: postgres:latest
11 | container_name: WebApiExampleDb
12 | cap_add:
13 | - SYS_NICE # CAP_SYS_NICE
14 | environment:
15 | - POSTGRES_DB=AppDb
16 | - POSTGRES_USER=ExampleUser
17 | - POSTGRES_PASSWORD=testingStuffOut
18 | restart: always
19 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ArchitecturalTests.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ArchitecturalTests.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/CompanyDatastore.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/CompanyDatastore.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ContactDatastore.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ContactDatastore.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCachingOfQueries.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCachingOfQueries.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCreateCompany.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCreateCompany.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCreateContact.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualCreateContact.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualGetAllCompanies.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualGetAllCompanies.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualGetCompanyById.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualGetCompanyById.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualRemoveContactByEmail.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualRemoveContactByEmail.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualSendEventOnCompanyCreation.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualSendEventOnCompanyCreation.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualSendEventOnCompanyNameChange.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualSendEventOnCompanyNameChange.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualUpdateCompanyName.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualUpdateCompanyName.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/ManualUpdateContactByEmail.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/ManualUpdateContactByEmail.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/images/UnitTests.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Resrcify/Resrcify.SharedKernel/ab28626ec81563e0cc759a9ed4e4d5d9320bec47/samples/Resrcify.SharedKernel.WebApiExample/images/UnitTests.PNG
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Abstractions/Repositories/ICompanyRepository.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Repository.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
9 | public interface ICompanyRepository
10 | : IRepository
11 | {
12 | Task> GetCompanyAggregateByIdAsync(
13 | CompanyId companyId,
14 | CancellationToken cancellationToken = default);
15 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/ApplicationServiceRegistration.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using FluentValidation;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Resrcify.SharedKernel.Messaging.Behaviors;
5 |
6 | namespace Resrcify.SharedKernel.WebApiExample.Application;
7 |
8 | public static class ApplicationServiceRegistration
9 | {
10 | public static IServiceCollection AddApplicationServices(this IServiceCollection services)
11 | {
12 | services.AddMediatR(config =>
13 | {
14 | config.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly());
15 | config.AddOpenBehavior(typeof(LoggingPipelineBehavior<,>));
16 | config.AddOpenBehavior(typeof(UnitOfWorkPipelineBehavior<,>));
17 | config.AddOpenBehavior(typeof(CachingPipelineBehavior<,>));
18 | });
19 |
20 | services.AddValidatorsFromAssembly(
21 | Assembly.GetExecutingAssembly(),
22 | includeInternalTypes: true);
23 |
24 | return services;
25 | }
26 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/AddContact/AddContactCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.AddContact;
5 |
6 | public sealed record AddContactCommand(
7 | Guid CompanyId,
8 | string FirstName,
9 | string LastName,
10 | string Email)
11 | : ICommand;
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/AddContact/AddContactCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Messaging.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.AddContact;
9 |
10 | internal sealed class AddContactCommandHandler(
11 | ICompanyRepository _companyRepository)
12 | : ICommandHandler
13 | {
14 | public async Task Handle(
15 | AddContactCommand request,
16 | CancellationToken cancellationToken)
17 | => await CompanyId
18 | .Create(request.CompanyId)
19 | .Bind(companyId => _companyRepository.GetCompanyAggregateByIdAsync(
20 | companyId,
21 | cancellationToken))
22 | .Tap(company => company.AddContact(
23 | request.FirstName,
24 | request.LastName,
25 | request.Email));
26 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/AddContact/AddContactCommandRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.AddContact;
2 |
3 | public sealed record AddContactCommandRequest(
4 | string FirstName,
5 | string LastName,
6 | string Email);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/CompanyCreated/CompanyCreatedEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Microsoft.Extensions.Logging;
4 | using Resrcify.SharedKernel.Messaging.Abstractions;
5 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Events;
6 |
7 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.CompanyCreated;
8 |
9 | internal sealed class CompanyCreatedEventHandler(
10 | ILogger _logger)
11 | : IDomainEventHandler
12 | {
13 | public Task Handle(
14 | CompanyCreatedEvent notification,
15 | CancellationToken cancellationToken)
16 | {
17 | _logger.LogInformation("Company created: {CompanyId}", notification.CompanyId);
18 |
19 | return Task.CompletedTask;
20 | }
21 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/CompanyNameUpdated/CompanyNameUpdatedEventHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Microsoft.Extensions.Logging;
4 | using Resrcify.SharedKernel.Messaging.Abstractions;
5 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Events;
6 |
7 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.CompanyNameUpdated;
8 |
9 | internal sealed class CompanyNameUpdatedEventHandler(
10 | ILogger _logger)
11 | : IDomainEventHandler
12 | {
13 | public Task Handle(
14 | CompanyNameUpdatedEvent notification,
15 | CancellationToken cancellationToken)
16 | {
17 | _logger.LogInformation("Company name updated: {CompanyId}", notification.CompanyId);
18 |
19 | return Task.CompletedTask;
20 | }
21 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/CreateCompany/CreateCompanyCommand.cs:
--------------------------------------------------------------------------------
1 | using Resrcify.SharedKernel.Messaging.Abstractions;
2 |
3 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.CreateCompany;
4 |
5 | public sealed record CreateCompanyCommand(
6 | string Name,
7 | string OrganizationNumber)
8 | : ICommand;
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/CreateCompany/CreateCompanyCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Resrcify.SharedKernel.Messaging.Abstractions;
5 | using Resrcify.SharedKernel.ResultFramework.Primitives;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies;
7 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
8 | using Resrcify.SharedKernel.WebApiExample.Domain.Errors;
9 |
10 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.CreateCompany;
11 |
12 | internal sealed class CreateCompanyCommandHandler(
13 | ICompanyRepository _companyRepository)
14 | : ICommandHandler
15 | {
16 | public async Task Handle(
17 | CreateCompanyCommand command,
18 | CancellationToken cancellationToken)
19 | {
20 | var newCompany = Company.Create(
21 | Guid.NewGuid(),
22 | command.Name,
23 | command.OrganizationNumber);
24 |
25 | if (newCompany.IsFailure)
26 | return newCompany;
27 |
28 | var oldCompany = await _companyRepository.FirstOrDefaultAsync(
29 | company => company.OrganizationNumber == newCompany.Value.OrganizationNumber,
30 | cancellationToken);
31 |
32 | if (oldCompany is not null)
33 | return DomainErrors.Company.OrganizationNumberAlreadyExist(command.OrganizationNumber);
34 |
35 | await _companyRepository.AddAsync(newCompany.Value, cancellationToken);
36 |
37 | return Result.Success();
38 | }
39 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/CreateCompany/CreateCompanyCommandRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.CreateCompany;
2 |
3 | public sealed record CreateCompanyCommandRequest(
4 | string Name,
5 | string OrganizationNumber);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetAllCompanies/GetAllCompaniesQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetAllCompanies;
5 |
6 | public sealed record GetAllCompaniesQuery : ICachingQuery
7 | {
8 | public string? CacheKey { get; set; } = "Companies";
9 | public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(5);
10 | }
11 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetAllCompanies/GetAllCompaniesQueryHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Resrcify.SharedKernel.Messaging.Abstractions;
5 | using Resrcify.SharedKernel.ResultFramework.Primitives;
6 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetAllCompanies;
9 |
10 | internal sealed class GetAllCompaniesQueryHandler(
11 | ICompanyRepository _companyRepository)
12 | : IQueryHandler
13 | {
14 | public async Task> Handle(
15 | GetAllCompaniesQuery request,
16 | CancellationToken cancellationToken)
17 | {
18 | var allCompanies = _companyRepository.GetAllAsync();
19 | var allCompaniesMaterialized = await allCompanies.ToListAsync(cancellationToken);
20 | var companyDtos = allCompaniesMaterialized.Select(company => new CompanyDto(
21 | company.Id.Value,
22 | company.Name.Value,
23 | company.OrganizationNumber.Value.ToString()));
24 | return new GetAllCompaniesQueryResponse(companyDtos);
25 | }
26 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetAllCompanies/GetAllCompaniesQueryResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetAllCompanies;
5 |
6 | public sealed record GetAllCompaniesQueryResponse(IEnumerable Companies);
7 |
8 | public sealed record CompanyDto(
9 | Guid Id,
10 | string Name,
11 | string OrganizationNumber);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetCompanyById/GetCompanyByIdQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetCompanyById;
5 |
6 | public sealed record GetCompanyByIdQuery(
7 | Guid CompanyId)
8 | : ICachingQuery
9 | {
10 | public string? CacheKey { get; set; } = $"Company-{CompanyId}";
11 | public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(5);
12 | }
13 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetCompanyById/GetCompanyByIdQueryHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Messaging.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 | using System.Linq;
8 |
9 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetCompanyById;
10 |
11 | internal sealed class GetAllCompaniesQueryHandler(
12 | ICompanyRepository _companyRepository)
13 | : IQueryHandler
14 | {
15 | public async Task> Handle(
16 | GetCompanyByIdQuery request,
17 | CancellationToken cancellationToken)
18 | => await CompanyId
19 | .Create(request.CompanyId)
20 | .Bind(companyId => _companyRepository.GetCompanyAggregateByIdAsync(companyId, cancellationToken))
21 | .Map(company => new GetCompanyByIdQueryResponse(
22 | company!.Id.Value,
23 | company.Name.Value,
24 | company.OrganizationNumber.Value.ToString(),
25 | company.Contacts.Select(contact =>
26 | new ContactDto(
27 | contact.FirstName.Value,
28 | contact.LastName.Value,
29 | contact.Email.Value))));
30 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/GetCompanyById/GetCompanyByIdQueryResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.GetCompanyById;
5 |
6 | public record GetCompanyByIdQueryResponse(
7 | Guid Id,
8 | string Name,
9 | string OrganizationNumber,
10 | IEnumerable Contacts);
11 |
12 | public record ContactDto(
13 | string FirstName,
14 | string LastName,
15 | string Email);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/RemoveContact/RemoveContactCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.RemoveContact;
5 |
6 | public sealed record RemoveContactCommand(
7 | Guid CompanyId,
8 | string Email)
9 | : ICommand;
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/RemoveContact/RemoveContactCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Messaging.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.RemoveContact;
9 |
10 | internal sealed class RemoveContactCommandHandler(
11 | ICompanyRepository _companyRepository)
12 | : ICommandHandler
13 | {
14 | public async Task Handle(
15 | RemoveContactCommand request,
16 | CancellationToken cancellationToken)
17 | => await CompanyId
18 | .Create(request.CompanyId)
19 | .Bind(companyId => _companyRepository.GetCompanyAggregateByIdAsync(
20 | companyId,
21 | cancellationToken))
22 | .Tap(company => company.RemoveContactByEmail(request.Email));
23 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/RemoveContact/RemoveContactCommandRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.RemoveContact;
2 |
3 | public sealed record RemoveContactCommandRequest(
4 | string Email);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateCompanyName/UpdateCompanyNameCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateCompanyName;
5 |
6 | public sealed record UpdateCompanyNameCommand(
7 | Guid CompanyId,
8 | string Name)
9 | : ICommand;
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateCompanyName/UpdateCompanyNameCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Messaging.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateCompanyName;
9 |
10 | internal sealed class UpdateCompanyNameCommandHandler(
11 | ICompanyRepository _companyRepository)
12 | : ICommandHandler
13 | {
14 | public async Task Handle(
15 | UpdateCompanyNameCommand request,
16 | CancellationToken cancellationToken)
17 | => await CompanyId
18 | .Create(request.CompanyId)
19 | .Bind(companyId => _companyRepository.GetCompanyAggregateByIdAsync(
20 | companyId,
21 | cancellationToken))
22 | .Tap(company => company.UpdateName(request.Name));
23 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateCompanyName/UpdateCompanyNameCommandRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateCompanyName;
2 |
3 | public sealed record UpdateCompanyNameCommandRequest(
4 | string Name);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateContactByEmail/UpdateContactByEmailCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.Messaging.Abstractions;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateContactByEmail;
5 |
6 | public sealed record UpdateContactByEmailCommand(
7 | Guid CompanyId,
8 | string NewFirstName,
9 | string NewLastName,
10 | string Email)
11 | : ICommand;
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateContactByEmail/UpdateContactByEmailCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using Resrcify.SharedKernel.Messaging.Abstractions;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Application.Abstractions.Repositories;
6 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
7 |
8 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateContactByEmail;
9 |
10 | internal sealed class UpdateContactByEmailCommandHandler(
11 | ICompanyRepository _companyRepository)
12 | : ICommandHandler
13 | {
14 | public async Task Handle(
15 | UpdateContactByEmailCommand request,
16 | CancellationToken cancellationToken)
17 | => await CompanyId
18 | .Create(request.CompanyId)
19 | .Bind(companyId => _companyRepository.GetCompanyAggregateByIdAsync(
20 | companyId,
21 | cancellationToken))
22 | .Tap(company => company.UpdateContactByEmail(
23 | request.Email,
24 | request.NewFirstName,
25 | request.NewLastName));
26 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Features/Companies/UpdateContactByEmail/UpdateContactByEmailCommandRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Application.Features.Companies.UpdateContactByEmail;
2 |
3 | public sealed record UpdateContactByEmailCommandRequest(
4 | string NewFirstName,
5 | string NewLastName,
6 | string Email);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Application/Resrcify.SharedKernel.WebApiExample.Application.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/AssemblyFlag.cs:
--------------------------------------------------------------------------------
1 | namespace Resrcify.SharedKernel.WebApiExample.Domain;
2 |
3 | public class AssemblyFlag
4 | {
5 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/Features/Companies/Entities/Contact.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.DomainDrivenDesign.Abstractions;
3 | using Resrcify.SharedKernel.DomainDrivenDesign.Primitives;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
6 |
7 | namespace Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Entities;
8 |
9 | public sealed class Contact
10 | : Entity,
11 | IAuditableEntity
12 | {
13 | private Contact(
14 | ContactId id,
15 | CompanyId companyId,
16 | Name firstName,
17 | Name lastName,
18 | Email email)
19 | : base(id)
20 | {
21 | CompanyId = companyId;
22 | FirstName = firstName;
23 | LastName = lastName;
24 | Email = email;
25 | }
26 | public CompanyId CompanyId { get; private set; }
27 | public Name FirstName { get; private set; }
28 | public Name LastName { get; private set; }
29 | public Email Email { get; private set; }
30 | public DateTime CreatedOnUtc { get; }
31 | public DateTime ModifiedOnUtc { get; }
32 |
33 | public static Result Create(
34 | CompanyId companyId,
35 | string firstName,
36 | string lastName,
37 | string email)
38 | => Result
39 | .Combine(
40 | ContactId.Create(Guid.NewGuid()),
41 | Name.Create(firstName),
42 | Name.Create(lastName),
43 | Email.Create(email))
44 | .Map(c => new Contact(
45 | c.Item1,
46 | companyId,
47 | c.Item2,
48 | c.Item3,
49 | c.Item4));
50 | public Result Update(
51 | string firstName,
52 | string lastName)
53 | => Result
54 | .Combine(
55 | Name.Create(firstName),
56 | Name.Create(lastName))
57 | .Tap(c => FirstName = c.Item1)
58 | .Tap(c => LastName = c.Item2);
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/Features/Companies/Enums/CompanyType.cs:
--------------------------------------------------------------------------------
1 | using Resrcify.SharedKernel.DomainDrivenDesign.Primitives;
2 |
3 | namespace Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Enums;
4 |
5 | public sealed class CompanyType : Enumeration
6 | {
7 | public static readonly CompanyType Unknown = new(0, "Unknown");
8 | public static readonly CompanyType DeceasedEstate = new(1, "Deceased estate");
9 | public static readonly CompanyType GovernmentEntity = new(2, "Government entities (State, region, municipalitie, parish)");
10 | public static readonly CompanyType ForeignCompany = new(3, "Foreign company");
11 | public static readonly CompanyType LimitedCompany = new(5, "Limited company");
12 | public static readonly CompanyType EconomicAssociation = new(7, "Economic association, housing cooperative, and community association");
13 | public static readonly CompanyType NonProfitOrganization = new(8, "Non-profit organization");
14 | public static readonly CompanyType Foundations = new(9, "Foundation");
15 |
16 | private CompanyType(int value, string name)
17 | : base(value, name)
18 | {
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/Features/Companies/Events/CompanyCreatedEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.DomainDrivenDesign.Primitives;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Events;
5 |
6 | public sealed record CompanyCreatedEvent(
7 | Guid Id,
8 | Guid CompanyId)
9 | : DomainEvent(Id);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/Features/Companies/Events/CompanyNameUpdatedEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Resrcify.SharedKernel.DomainDrivenDesign.Primitives;
3 |
4 | namespace Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.Events;
5 |
6 | public sealed record CompanyNameUpdatedEvent(
7 | Guid Id,
8 | Guid CompanyId,
9 | string OldName,
10 | string NewName)
11 | : DomainEvent(Id);
--------------------------------------------------------------------------------
/samples/Resrcify.SharedKernel.WebApiExample/src/Resrcify.SharedKernel.WebApiExample.Domain/Features/Companies/ValueObjects/CompanyId.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Resrcify.SharedKernel.DomainDrivenDesign.Primitives;
4 | using Resrcify.SharedKernel.ResultFramework.Primitives;
5 | using Resrcify.SharedKernel.WebApiExample.Domain.Errors;
6 |
7 | namespace Resrcify.SharedKernel.WebApiExample.Domain.Features.Companies.ValueObjects;
8 |
9 | public sealed class CompanyId : ValueObject
10 | {
11 | public Guid Value { get; }
12 | private CompanyId(Guid value)
13 | => Value = value;
14 |
15 | public static Result Create(Guid value)
16 | => Result
17 | .Ensure(
18 | value,
19 | value => !value.Equals(Guid.Empty),
20 | DomainErrors.CompanyId.Empty)
21 | .Map(value => new CompanyId(value));
22 |
23 | public override IEnumerable