Showing preview only (1,410K chars total). Download the full file or copy to clipboard to get everything.
Repository: EduardoPires/EquinoxProject
Branch: master
Commit: fde9a953eb31
Files: 179
Total size: 1.3 MB
Directory structure:
gitextract_ug6sjdzw/
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── custom.md
│ │ └── feature_request.md
│ └── workflows/
│ └── dotnet-core.yml
├── .gitignore
├── AGENTS.md
├── Equinox.sln
├── LICENSE
├── README.md
├── docs/
│ ├── Architecture.dgml
│ ├── _config.yml
│ └── index.md
├── sql/
│ └── GenerateDataBase.sql
├── src/
│ ├── Equinox.Application/
│ │ ├── Equinox.Application.csproj
│ │ ├── EventSourcedNormalizers/
│ │ │ ├── CustomerHistory.cs
│ │ │ └── CustomerHistoryData.cs
│ │ ├── Extensions/
│ │ │ └── CustomerExtensions.cs
│ │ ├── Interfaces/
│ │ │ └── ICustomerAppService.cs
│ │ ├── Services/
│ │ │ └── CustomerAppService.cs
│ │ └── ViewModels/
│ │ └── CustomerViewModel.cs
│ ├── Equinox.Domain/
│ │ ├── Commands/
│ │ │ ├── CustomerCommand.cs
│ │ │ ├── CustomerCommandHandler.cs
│ │ │ ├── RegisterNewCustomerCommand.cs
│ │ │ ├── RemoveCustomerCommand.cs
│ │ │ ├── UpdateCustomerCommand.cs
│ │ │ └── Validations/
│ │ │ ├── CustomerValidation.cs
│ │ │ ├── RegisterNewCustomerCommandValidation.cs
│ │ │ ├── RemoveCustomerCommandValidation.cs
│ │ │ └── UpdateCustomerCommandValidation.cs
│ │ ├── Equinox.Domain.csproj
│ │ ├── Events/
│ │ │ ├── CustomerEventHandler.cs
│ │ │ ├── CustomerRegisteredEvent.cs
│ │ │ ├── CustomerRemovedEvent.cs
│ │ │ └── CustomerUpdatedEvent.cs
│ │ ├── Interfaces/
│ │ │ └── ICustomerRepository.cs
│ │ └── Models/
│ │ └── Customer.cs
│ ├── Equinox.Domain.Core/
│ │ ├── Equinox.Domain.Core.csproj
│ │ └── Events/
│ │ ├── IEventStore.cs
│ │ └── StoredEvent.cs
│ ├── Equinox.Infra.CrossCutting.Bus/
│ │ ├── Equinox.Infra.CrossCutting.Bus.csproj
│ │ └── InMemoryBus.cs
│ ├── Equinox.Infra.CrossCutting.Identity/
│ │ ├── API/
│ │ │ ├── AppJwtSettings.cs
│ │ │ └── JwtBuilder.cs
│ │ ├── Authorization/
│ │ │ ├── CustomAuthorizationValidation.cs
│ │ │ ├── CustomAuthorizeAttribute.cs
│ │ │ └── RequerimentClaimFilter.cs
│ │ ├── Configuration/
│ │ │ └── AspNetIdentityConfig.cs
│ │ ├── Data/
│ │ │ └── EquinoxIdentityContext.cs
│ │ ├── Equinox.Infra.CrossCutting.Identity.csproj
│ │ ├── Extensions/
│ │ │ └── ClaimsPrincipalExtensions.cs
│ │ ├── Migrations/
│ │ │ ├── 20250408033115_SQLite.Designer.cs
│ │ │ ├── 20250408033115_SQLite.cs
│ │ │ └── EquinoxIdentityContextModelSnapshot.cs
│ │ ├── Models/
│ │ │ ├── LoginUser.cs
│ │ │ ├── RegisterUser.cs
│ │ │ ├── UserClaim.cs
│ │ │ ├── UserResponse.cs
│ │ │ └── UserToken.cs
│ │ └── User/
│ │ ├── AspNetUser.cs
│ │ └── IAspNetUser.cs
│ ├── Equinox.Infra.CrossCutting.IoC/
│ │ ├── Equinox.Infra.CrossCutting.IoC.csproj
│ │ └── NativeInjectorBootStrapper.cs
│ ├── Equinox.Infra.Data/
│ │ ├── Context/
│ │ │ ├── EquinoxContext.cs
│ │ │ └── EventStoreSQLContext.cs
│ │ ├── Equinox.Infra.Data.csproj
│ │ ├── EventSourcing/
│ │ │ └── SqlEventStore.cs
│ │ ├── Mappings/
│ │ │ ├── CustomerMap.cs
│ │ │ └── StoredEventMap.cs
│ │ ├── Migrations/
│ │ │ ├── 20250408031104_SQLite.Designer.cs
│ │ │ ├── 20250408031104_SQLite.cs
│ │ │ ├── EquinoxContextModelSnapshot.cs
│ │ │ ├── EventStoreSQL/
│ │ │ │ └── EventStoreSQLContextModelSnapshot.cs
│ │ │ └── EventStoreSql/
│ │ │ ├── 20250408031128_SQLite.Designer.cs
│ │ │ └── 20250408031128_SQLite.cs
│ │ ├── Repository/
│ │ │ ├── CustomerRepository.cs
│ │ │ └── EventSourcing/
│ │ │ ├── EventStoreSQLRepository.cs
│ │ │ └── IEventStoreRepository.cs
│ │ └── appsettings.json
│ ├── Equinox.Services.Api/
│ │ ├── Configurations/
│ │ │ ├── ApiConfig.cs
│ │ │ ├── DatabaseConfig.cs
│ │ │ ├── DependencyInjectionConfig.cs
│ │ │ └── SwaggerConfig.cs
│ │ ├── Controllers/
│ │ │ ├── AccountController.cs
│ │ │ ├── ApiController.cs
│ │ │ └── CustomerController.cs
│ │ ├── Dockerfile
│ │ ├── Equinox.Services.Api.csproj
│ │ ├── Program.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.Staging.json
│ │ ├── appsettings.Testing.json
│ │ └── appsettings.json
│ └── Equinox.UI.Web/
│ ├── Areas/
│ │ └── Identity/
│ │ ├── IdentityHostingStartup.cs
│ │ └── Pages/
│ │ ├── Account/
│ │ │ ├── Login.cshtml
│ │ │ ├── Login.cshtml.cs
│ │ │ ├── Logout.cshtml
│ │ │ ├── Logout.cshtml.cs
│ │ │ ├── Register.cshtml
│ │ │ ├── Register.cshtml.cs
│ │ │ └── _ViewImports.cshtml
│ │ ├── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── Configurations/
│ │ ├── DatabaseConfig.cs
│ │ ├── DbMigrationHelpers.cs
│ │ ├── DependencyInjectionConfig.cs
│ │ └── MvcConfig.cs
│ ├── Controllers/
│ │ ├── BaseController.cs
│ │ ├── CustomerController.cs
│ │ └── HomeController.cs
│ ├── Data/
│ │ ├── ApplicationDbContext.cs
│ │ └── Migrations/
│ │ ├── 00000000000000_CreateIdentitySchema.Designer.cs
│ │ ├── 00000000000000_CreateIdentitySchema.cs
│ │ └── ApplicationDbContextModelSnapshot.cs
│ ├── Dockerfile
│ ├── Equinox.UI.Web.csproj
│ ├── Models/
│ │ └── ErrorViewModel.cs
│ ├── Program.cs
│ ├── Properties/
│ │ ├── launchSettings.json
│ │ ├── serviceDependencies.json
│ │ └── serviceDependencies.local.json
│ ├── ScaffoldingReadMe.txt
│ ├── ViewComponents/
│ │ └── SummaryViewComponent.cs
│ ├── Views/
│ │ ├── Customer/
│ │ │ ├── Create.cshtml
│ │ │ ├── Delete.cshtml
│ │ │ ├── Details.cshtml
│ │ │ ├── Edit.cshtml
│ │ │ └── Index.cshtml
│ │ ├── Home/
│ │ │ ├── Index.cshtml
│ │ │ └── Privacy.cshtml
│ │ ├── Shared/
│ │ │ ├── Components/
│ │ │ │ └── Summary/
│ │ │ │ └── Default.cshtml
│ │ │ ├── Error.cshtml
│ │ │ ├── _CookieConsentPartial.cshtml
│ │ │ ├── _Layout.cshtml
│ │ │ ├── _LoginPartial.cshtml
│ │ │ └── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── appsettings.Development.json
│ ├── appsettings.Staging.json
│ ├── appsettings.Testing.json
│ ├── appsettings.json
│ ├── bundleconfig.json
│ └── wwwroot/
│ ├── _references.js
│ ├── css/
│ │ └── site.css
│ ├── js/
│ │ └── site.js
│ └── lib/
│ ├── bootstrap/
│ │ ├── .bower.json
│ │ ├── LICENSE
│ │ └── dist/
│ │ ├── css/
│ │ │ ├── bootstrap-grid.css
│ │ │ ├── bootstrap-reboot.css
│ │ │ ├── bootstrap-theme.css
│ │ │ └── bootstrap.css
│ │ └── js/
│ │ ├── bootstrap.bundle.js
│ │ ├── bootstrap.js
│ │ └── npm.js
│ ├── jquery/
│ │ ├── .bower.json
│ │ ├── LICENSE.txt
│ │ └── dist/
│ │ └── jquery.js
│ ├── jquery-validation/
│ │ ├── .bower.json
│ │ ├── LICENSE.md
│ │ └── dist/
│ │ ├── additional-methods.js
│ │ └── jquery.validate.js
│ ├── jquery-validation-unobtrusive/
│ │ ├── .bower.json
│ │ ├── LICENSE.txt
│ │ └── jquery.validate.unobtrusive.js
│ └── qrcode.js
└── tests/
└── Equinox.Tests.Architecture/
├── DataBaseTests.cs
├── DomainTests.cs
├── Equinox.Tests.Architecture.csproj
├── GeneralPatternTests.cs
├── Support/
│ ├── ShouldUseDependencyInjectionRule.cs
│ ├── TestOutputHelperTextWriter.cs
│ └── TestsSupport.cs
└── WebApplicationTests.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
================================================
FILE: .editorconfig
================================================
# Remove unused using directives
dotnet_diagnostic.CS8019.severity = error
# Unused variables
dotnet_diagnostic.IDE0059.severity = error
# Unused expressions (e.g., method call with no effect)
dotnet_diagnostic.IDE0058.severity = error
# Parameter is never used
dotnet_diagnostic.IDE0060.severity = warning
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
patreon: eduardopires
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/custom.md
================================================
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
**ONLY IN ENGLISH**
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/dotnet-core.yml
================================================
name: .NET Core
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal
================================================
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/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# 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
# 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
# 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: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# 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 directory
AppPackages/
BundleArtifacts/
# 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/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
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
# 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
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
================================================
FILE: AGENTS.md
================================================
# AGENTS Setup Guide
This repository requires specific environment configuration to build and run .NET 9.0 projects. **All dependencies must be installed during the setup script phase,** especially in restricted environments (e.g., OpenAI Codex).
## Setup Steps (`setup.sh`)
1. **Update and upgrade the system:**
`apt-get update && apt-get upgrade -y`
2. **Install essential dependencies (`wget`, `apt-transport-https`, `ca-certificates`):**
`apt-get install -y wget apt-transport-https ca-certificates`
3. **Configure Microsoft package source and update package lists:**
`wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb`
`dpkg -i packages-microsoft-prod.deb`
`rm packages-microsoft-prod.deb`
`apt-get update`
4. **Install .NET SDK 9.0:**
`apt-get install -y dotnet-sdk-9.0`
5. **Verify installation:**
`dotnet --version`
6. **(Optional) Remove obsolete packages:**
`apt-get autoremove -y`
---
## ⚠️ Notes for Codex and Similar Cloud Environments
- **Internet access is only available during the setup script phase.** All dependencies must be installed in this initial script.
- **A network proxy is always active:** Standard environment variables like `http_proxy`, `https_proxy`, and the proxy certificate (`$CODEX_PROXY_CERT`) are automatically set. These should be respected by all package managers and CLI tools.
- **If you encounter connectivity issues:**
- Ensure your setup script is running during the setup/initialization phase (not in the regular terminal).
- Check that all required dependencies are installed up front.
- Make sure environment variables for the proxy/certificate are being used by your tools.
---
## General Recommendations
- Use the latest version of **Visual Studio** or **Visual Studio Code** for development.
- Always install the correct SDK and runtime versions as required by this project.
- The project can be built and run in Visual Studio Code on Windows, Linux, or macOS.
---
**IMPORTANT:**
If using a cloud development platform or automated environment, ensure all tools and dependencies are installed during the setup script phase. No additional internet access will be available after environment initialization. Plan accordingly.
================================================
FILE: Equinox.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Presentation", "1 - Presentation", "{BA4C44CC-65BC-4CE0-9B44-68BA231FAC73}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Services", "2 - Services", "{A5DF9A6E-87DC-49E9-A437-04C399572BD4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 - Application", "3 - Application", "{FD1B5301-2A07-47B3-8773-839429800B2F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4 - Domain", "4 - Domain", "{0C6FAB88-2741-4295-B6B6-F397DBA958F0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5 - Infra", "5 - Infra", "{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5.1 - Data", "5.1 - Data", "{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5.2 - CrossCutting", "5.2 - CrossCutting", "{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.UI.Web", "src\Equinox.UI.Web\Equinox.UI.Web.csproj", "{490517BA-F3C3-44B4-82F8-1E3A4ED6777A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Services.Api", "src\Equinox.Services.Api\Equinox.Services.Api.csproj", "{EA966EC3-85A6-4B57-82C1-5120E3390243}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Application", "src\Equinox.Application\Equinox.Application.csproj", "{851E7338-2397-4E8D-8199-FD1EAD109418}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Domain", "src\Equinox.Domain\Equinox.Domain.csproj", "{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Domain.Core", "src\Equinox.Domain.Core\Equinox.Domain.Core.csproj", "{9CC884B7-FA70-49E1-92A6-2B566E00FAB9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Infra.Data", "src\Equinox.Infra.Data\Equinox.Infra.Data.csproj", "{F0DDF87D-98A4-4237-91C9-FD865ED78ABB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Infra.CrossCutting.Bus", "src\Equinox.Infra.CrossCutting.Bus\Equinox.Infra.CrossCutting.Bus.csproj", "{91F0D76D-2BEA-43D2-B123-DC29F2E87792}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Infra.CrossCutting.Identity", "src\Equinox.Infra.CrossCutting.Identity\Equinox.Infra.CrossCutting.Identity.csproj", "{788030D0-561B-4136-96B4-D5ABFB5CFD07}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Equinox.Infra.CrossCutting.IoC", "src\Equinox.Infra.CrossCutting.IoC\Equinox.Infra.CrossCutting.IoC.csproj", "{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "6 - Tests", "6 - Tests", "{7426F6BA-3DAD-411E-9956-3980D42DC36F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Equinox.Tests.Architecture", "tests\Equinox.Tests.Architecture\Equinox.Tests.Architecture.csproj", "{C4036D98-A669-440C-9970-05DB45815949}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{490517BA-F3C3-44B4-82F8-1E3A4ED6777A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{490517BA-F3C3-44B4-82F8-1E3A4ED6777A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{490517BA-F3C3-44B4-82F8-1E3A4ED6777A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{490517BA-F3C3-44B4-82F8-1E3A4ED6777A}.Release|Any CPU.Build.0 = Release|Any CPU
{EA966EC3-85A6-4B57-82C1-5120E3390243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA966EC3-85A6-4B57-82C1-5120E3390243}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA966EC3-85A6-4B57-82C1-5120E3390243}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA966EC3-85A6-4B57-82C1-5120E3390243}.Release|Any CPU.Build.0 = Release|Any CPU
{851E7338-2397-4E8D-8199-FD1EAD109418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{851E7338-2397-4E8D-8199-FD1EAD109418}.Debug|Any CPU.Build.0 = Debug|Any CPU
{851E7338-2397-4E8D-8199-FD1EAD109418}.Release|Any CPU.ActiveCfg = Release|Any CPU
{851E7338-2397-4E8D-8199-FD1EAD109418}.Release|Any CPU.Build.0 = Release|Any CPU
{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA}.Release|Any CPU.Build.0 = Release|Any CPU
{9CC884B7-FA70-49E1-92A6-2B566E00FAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9CC884B7-FA70-49E1-92A6-2B566E00FAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CC884B7-FA70-49E1-92A6-2B566E00FAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CC884B7-FA70-49E1-92A6-2B566E00FAB9}.Release|Any CPU.Build.0 = Release|Any CPU
{F0DDF87D-98A4-4237-91C9-FD865ED78ABB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0DDF87D-98A4-4237-91C9-FD865ED78ABB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0DDF87D-98A4-4237-91C9-FD865ED78ABB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0DDF87D-98A4-4237-91C9-FD865ED78ABB}.Release|Any CPU.Build.0 = Release|Any CPU
{91F0D76D-2BEA-43D2-B123-DC29F2E87792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91F0D76D-2BEA-43D2-B123-DC29F2E87792}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91F0D76D-2BEA-43D2-B123-DC29F2E87792}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91F0D76D-2BEA-43D2-B123-DC29F2E87792}.Release|Any CPU.Build.0 = Release|Any CPU
{788030D0-561B-4136-96B4-D5ABFB5CFD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{788030D0-561B-4136-96B4-D5ABFB5CFD07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{788030D0-561B-4136-96B4-D5ABFB5CFD07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{788030D0-561B-4136-96B4-D5ABFB5CFD07}.Release|Any CPU.Build.0 = Release|Any CPU
{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0}.Release|Any CPU.Build.0 = Release|Any CPU
{C4036D98-A669-440C-9970-05DB45815949}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4036D98-A669-440C-9970-05DB45815949}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4036D98-A669-440C-9970-05DB45815949}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4036D98-A669-440C-9970-05DB45815949}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF} = {BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}
{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F} = {BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}
{490517BA-F3C3-44B4-82F8-1E3A4ED6777A} = {BA4C44CC-65BC-4CE0-9B44-68BA231FAC73}
{EA966EC3-85A6-4B57-82C1-5120E3390243} = {A5DF9A6E-87DC-49E9-A437-04C399572BD4}
{851E7338-2397-4E8D-8199-FD1EAD109418} = {FD1B5301-2A07-47B3-8773-839429800B2F}
{BF28C988-9C1B-41F5-BD58-D2FCAD7E80BA} = {0C6FAB88-2741-4295-B6B6-F397DBA958F0}
{9CC884B7-FA70-49E1-92A6-2B566E00FAB9} = {0C6FAB88-2741-4295-B6B6-F397DBA958F0}
{F0DDF87D-98A4-4237-91C9-FD865ED78ABB} = {0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}
{91F0D76D-2BEA-43D2-B123-DC29F2E87792} = {DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}
{788030D0-561B-4136-96B4-D5ABFB5CFD07} = {DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}
{B3000AD2-5EAA-49A2-8FC4-10DF329B15B0} = {DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}
{C4036D98-A669-440C-9970-05DB45815949} = {7426F6BA-3DAD-411E-9956-3980D42DC36F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4050E145-6791-440A-A2E5-75B05ACD4AFE}
EndGlobalSection
EndGlobal
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2016 Eduardo Pires
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: README.md
================================================
<img src="https://github.com/user-attachments/assets/f078a9b9-bf99-48f6-a7a4-50403f33a4b0" alt="Equinox Project" width="45%">
What is the Equinox Project?
=====================
The Equinox Project is a open-source project written in .NET Core
The goal of this project is implement the most common used technologies and share with the technical community the best way to develop great applications with .NET
[](LICENSE)
[](https://huboard.com/EduardoPires/EquinoxProject/)
## Give a Star! :star:
If you liked the project or if Equinox helped you, please give a star ;)
## Want to learn everything? :mortar_board:
Check my online courses at [desenvolvedor.io](https://desenvolvedor.io)
## How to use:
- You will need the latest version of Visual Studio and the latest .NET Core SDK.
- ***Please check if you have installed the runtime version***
- The latest SDK and tools can be downloaded from https://dot.net/core.
Also you can run the Equinox Project in Visual Studio Code (Windows, Linux or MacOS).
To know more about how to setup your enviroment visit the [Microsoft .NET Download Guide](https://www.microsoft.com/net/download)
## Technologies implemented:
- ASP.NET 9.0
- ASP.NET MVC Core
- ASP.NET WebApi Core with JWT Bearer Authentication
- ASP.NET Identity Core
- Entity Framework Core 9.0
- Custom Automatic Mapping (no more AutoMapper)
- FluentValidator
- NetDevPack.SimpleMediator (no more MediatR)
- NetDevPack (DDD, CQRS, UOW and more)
- Swagger UI with JWT support
## Architecture:
- Full architecture with responsibility separation concerns, SOLID and Clean Code
- Domain Driven Design (Layers and Domain Model Pattern)
- Domain Events
- Domain Notification
- Domain Validations
- CQRS (Imediate Consistency)
- Event Sourcing
- Unit of Work
- Repository
## News
**v1.10 - 04/08/2025**
- Migrated to .NET 9.0
- Replaced MediatR with [NetDevPack.SimpleMediator](https://github.com/NetDevPack/SimpleMediator) for lighter and native CQRS handling
- Removed AutoMapper in favor of lightweight custom mapping extensions
- Architecture Tests with [NetArchTest.Rules](https://github.com/BenMorris/NetArchTest)
- Added built-in SQLite support with automatic EF Core migrations (just run and go — no setup required)
- Updated all dependencies to the latest stable versions
**v1.9 - 06/31/2024**
- Migrated for .NET 8.0
- Full refactoring of Web and Api configuration
- Now all ASP.NET Identity configurations are inside the project, without external dependencies
- All dependencies is up to date
**v1.8 - 03/22/2022**
- Migrated for .NET 6.0
- All dependencies is up to date
**v1.7 - 04/06/2021**
- Migrated for .NET 5.0
- All dependencies is up to date
**v1.6 - 06/09/2020**
- Full Refactoring (consistency, events, validation, identity)
- Added [NetDevPack](https://github.com/NetDevPack) and saving a hundreds of code lines
- All dependencies is up to date
**v1.5 - 01/22/2020**
- Migrated for .NET Core 3.1.1
- All dependencies is up to date
- Added JWT (Bearer) authentication for WebAPI
- Added JWT support in Swagger
**v1.4 - 02/14/2019**
- Migrated for .NET Core 2.2.1
- All dependencies is up to date
- Improvements for last version of MediatR (Notifications and Request)
**v1.3 - 05/22/2018**
- Migrated for .NET Core 2.1.2
- All dependencies is up to date
- Improvements in Automapper Setup
- Improvements for last version of MediatR (Notifications and Request)
- Code improvements in general
**v1.2 - 08/15/2017**
- Migrated for .NET Core 2.0 and ASP.NET Core 2.0
- Adaptations for the new Identity Authentication Model
**v1.1 - 08/09/2017**
- Adding WebAPI service exposing the application features
- Adding Swagger UI for better viewing and testing
- Adding MediatR for Memory Bus Messaging
## Disclaimer:
- **NOT** intended to be a definitive solution
- Beware to use in production way
- Maybe you don't need a lot of implementations that is included, try avoid the **over engineering**
## Pull-Requests
Make a contact! Don't submit PRs for extra features, all the new features are planned
## Why Equinox?
The Equinox is an astronomical event in which the plane of Earth's equator passes through the center of the Sun, which occurs twice each year, around 20 March and 23 September. [Wikipedia](https://en.wikipedia.org/wiki/Equinox)
Equinox is also a series of publications (subtitle: "The Review of Scientific Illuminism") in book form that serves as the official organ of the A∴A∴, a magical order founded by Aleister Crowley :) [Wikipedia](https://en.wikipedia.org/wiki/The_Equinox)
## We are Online:
See the project running on <a href="http://equinoxproject.azurewebsites.net" target="_blank">Azure</a>
## About:
The Equinox Project was developed by [Eduardo Pires](http://eduardopires.net.br) under the [MIT license](LICENSE).
================================================
FILE: docs/Architecture.dgml
================================================
<?xml version="1.0" encoding="utf-8"?>
<DirectedGraph DataVirtualized="True" Layout="Sugiyama" ZoomLevel="-1" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
<Nodes>
<Node Id="(@7 @22 @24 Member=.ctor)" Category="CodeSchema_Method" Bounds="256.172218942968,490.01069796443,99.5466666666666,25.9600000000001" CodeSchemaProperty_IsConstructor="True" CodeSchemaProperty_IsProtected="True" CodeSchemaProperty_IsSpecialName="True" DelayedCrossGroupLinksState="Fetched" Label="ValueObject" UseManualLocation="True" />
<Node Id="1 - Presentation{BA4C44CC-65BC-4CE0-9B44-68BA231FAC73}" Category="CodeMap_SolutionFolder" Bounds="126.270298493392,14.5537131977793,198.346666666666,85.0002" Group="Expanded" Label="1 - Presentation" />
<Node Id="2 - Services{A5DF9A6E-87DC-49E9-A437-04C399572BD4}" Category="CodeMap_SolutionFolder" Bounds="-126.659801506608,14.5537131977793,222.93,85.0002" Group="Expanded" Label="2 - Services" />
<Node Id="3 - Application{FD1B5301-2A07-47B3-8773-839429800B2F}" Category="CodeMap_SolutionFolder" Bounds="72.0843508618859,129.554013197779,220.343333333333,85.0002" Group="Expanded" Label="3 - Application" />
<Node Id="4 - Domain{0C6FAB88-2741-4295-B6B6-F397DBA958F0}" Category="CodeMap_SolutionFolder" Bounds="260.949364285782,324.885093222508,229.333333333333,164.149426587692" Group="Expanded" Label="4 - Domain" UseManualLocation="True" />
<Node Id="5 - Infra{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}" Category="CodeMap_SolutionFolder" Bounds="-307.645063894958,244.554313197779,486.865,371.639162390044" Group="Expanded" Label="5 - Infra" UseManualLocation="True" />
<Node Id="5.1 - Data{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}" Category="CodeMap_SolutionFolder" Bounds="-169.989230561624,284.554413197779,211.553333333333,85.0001999999999" Group="Expanded" Label="5.1 - Data" />
<Node Id="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" Category="CodeMap_SolutionFolder" Bounds="-287.645063894958,401.192975587824,446.865,195.0004" Group="Expanded" Label="5.2 - CrossCutting" />
<Node Id="@10" Category="CodeSchema_Assembly" Bounds="-190.749082471448,169.554113197779,212.833333333333,25" CodeSchemaProperty_StrongName="Equinox.Tests.Architecture, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(c4036d98-a669-440c-9970-05db45815949.OutputPath)" Group="Collapsed" Label="Equinox.Tests.Architecture.dll" />
<Node Id="@12" Category="CodeSchema_Assembly" Bounds="-106.659801506608,54.5538131977793,182.93,25" CodeSchemaProperty_StrongName="Equinox.Services.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(ea966ec3-85a6-4b57-82c1-5120e3390243.OutputPath)" Group="Collapsed" Label="Equinox.Services.Api.dll" />
<Node Id="@14" Category="CodeSchema_Assembly" Bounds="287.541263459239,364.885193222508,161.823333333333,25" CodeSchemaProperty_StrongName="Equinox.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(bf28c988-9c1b-41f5-bd58-d2fcad7e80ba.OutputPath)" Group="Collapsed" Label="Equinox.Domain.dll" UseManualLocation="True" />
<Node Id="@16" Category="CodeSchema_Assembly" Bounds="92.0843508618858,169.554113197779,180.343333333333,25" CodeSchemaProperty_StrongName="Equinox.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(851e7338-2397-4e8d-8199-fd1ead109418.OutputPath)" Group="Collapsed" Label="Equinox.Application.dll" />
<Node Id="@18" Category="CodeSchema_Assembly" Bounds="-267.645063894958,551.193275587823,236.16,25" CodeSchemaProperty_StrongName="Equinox.Infra.CrossCutting.Bus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(91f0d76d-2bea-43d2-b123-dc29f2e87792.OutputPath)" Group="Collapsed" Label="Equinox.Infra.CrossCutting.Bus.dll" />
<Node Id="@2" Category="CodeSchema_Assembly" Bounds="-149.989230561624,324.554513197779,171.553333333333,25" CodeSchemaProperty_StrongName="Equinox.Infra.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(f0ddf87d-98a4-4237-91c9-fd865ed78abb.OutputPath)" Group="Collapsed" Label="Equinox.Infra.Data.dll" />
<Node Id="@20" Category="CodeSchema_Assembly" Bounds="-118.350063894958,496.193175587824,257.57,24.9999999999999" CodeSchemaProperty_StrongName="Equinox.Infra.CrossCutting.Identity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(788030d0-561b-4136-96b4-d5abfb5cfd07.OutputPath)" Group="Collapsed" Label="Equinox.Infra.CrossCutting.Identity.dll" />
<Node Id="@21" Category="CodeSchema_Namespace" Bounds="383.86748198156,370.776923465066,207.496666666667,140.0003" DelayedChildNodesState="Fetched" DelayedCrossGroupLinksState="Fetched" FetchedChildrenCount="2" Group="Expanded" Label="Equinox.Domain.Core.Events" UseManualLocation="True" />
<Node Id="@23" Category="CodeSchema_Namespace" Bounds="75.8924827092052,485.197022391087,212.603333333333,85" DelayedChildNodesState="Fetched" DelayedCrossGroupLinksState="Fetched" FetchedChildrenCount="1" Group="Expanded" Label="Equinox.Domain.Core.Models" UseManualLocation="True" />
<Node Id="@25" Category="CodeSchema_Class" Bounds="108.567482709205,525.197022391087,147.253333333333,25" CodeSchemaProperty_IsAbstract="True" CodeSchemaProperty_IsGeneric="True" CodeSchemaProperty_IsPublic="True" DelayedChildNodesState="Fetched" DelayedCrossGroupLinksState="Fetched" FetchedChildrenCount="7" Group="Collapsed" Label="ValueObject<T>" UseManualLocation="True" />
<Node Id="@26" Category="CodeSchema_Interface" Bounds="425.340815314893,410.777073465066,120.676666666667,25" CodeSchemaProperty_IsAbstract="True" CodeSchemaProperty_IsPublic="True" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" Group="Collapsed" Label="IEventStore" />
<Node Id="@27" Category="CodeSchema_Class" Bounds="425.340815314893,465.777073465066,124.55,25" CodeSchemaProperty_IsPublic="True" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" Group="Collapsed" Label="StoredEvent" />
<Node Id="@29" Category="CodeSchema_Method" Bounds="104.827216298111,378.090707424879,70.0333333333333,25.9600000000001" CodeSchemaProperty_IsPublic="True" CodeSchemaProperty_IsVirtual="True" DelayedCrossGroupLinksState="Fetched" Label="Equals" UseManualLocation="True" />
<Node Id="@30" Category="CodeSchema_Method" Bounds="92.3722086687169,434.050706509352,94.9433333333334,25.96" CodeSchemaProperty_IsAbstract="True" CodeSchemaProperty_IsProtected="True" CodeSchemaProperty_IsVirtual="True" DelayedCrossGroupLinksState="Fetched" Label="EqualsCore" UseManualLocation="True" />
<Node Id="@31" Category="CodeSchema_Method" Bounds="222.410536915787,434.050706509352,96.7833333333334,25.96" CodeSchemaProperty_IsPublic="True" CodeSchemaProperty_IsStatic="True" DelayedCrossGroupLinksState="Fetched" Label="op_Equality" UseManualLocation="True" />
<Node Id="@32" Category="CodeSchema_Method" Bounds="217.315536915787,378.090707424879,106.973333333333,25.9600000000001" CodeSchemaProperty_IsPublic="True" CodeSchemaProperty_IsStatic="True" DelayedCrossGroupLinksState="Fetched" Label="op_Inequality" UseManualLocation="True" />
<Node Id="@33" Category="CodeSchema_Method" Bounds="104.827212432552,490.01069796443,108.89,25.9600000000001" CodeSchemaProperty_IsPublic="True" CodeSchemaProperty_IsVirtual="True" DelayedCrossGroupLinksState="Fetched" Label="GetHashCode" UseManualLocation="True" />
<Node Id="@34" Category="CodeSchema_Method" Bounds="92.3722124325515,545.970689419509,133.8,25.96" CodeSchemaProperty_IsAbstract="True" CodeSchemaProperty_IsProtected="True" CodeSchemaProperty_IsVirtual="True" DelayedCrossGroupLinksState="Fetched" Label="GetHashCodeCore" UseManualLocation="True" />
<Node Id="@4" Category="CodeSchema_Assembly" Bounds="146.270298493392,54.5538131977793,158.346666666666,25" CodeSchemaProperty_StrongName="Equinox.UI.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(490517ba-f3c3-44b4-82f8-1e3a4ed6777a.OutputPath)" Group="Collapsed" Label="Equinox.UI.Web.dll" />
<Node Id="@6" Category="CodeSchema_Assembly" Bounds="-267.090063894958,441.193075587824,235.05,25" CodeSchemaProperty_StrongName="Equinox.Infra.CrossCutting.IoC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="NotFetched" DelayedCrossGroupLinksState="Fetched" FilePath="$(b3000ad2-5eaa-49a2-8fc4-10df329b15b0.OutputPath)" Group="Collapsed" Label="Equinox.Infra.CrossCutting.IoC.dll" />
<Node Id="@8" Category="CodeSchema_Assembly" Bounds="280.949364285782,444.0344198102,189.333333333333,25" CodeSchemaProperty_StrongName="Equinox.Domain.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" DelayedChildNodesState="Fetched" DelayedCrossGroupLinksState="Fetched" FetchedChildrenCount="2" FilePath="$(9cc884b7-fa70-49e1-92a6-2b566e00fab9.OutputPath)" Group="Collapsed" Label="Equinox.Domain.Core.dll" UseManualLocation="True" />
<Node Id="NewFolder1{7426F6BA-3DAD-411E-9956-3980D42DC36F}" Category="CodeMap_SolutionFolder" Bounds="-210.749082471448,129.554013197779,252.833333333333,85.0002" Group="Expanded" Label="6 - Tests" />
</Nodes>
<Links>
<Link Source="1 - Presentation{BA4C44CC-65BC-4CE0-9B44-68BA231FAC73}" Target="@4" Category="Contains" FetchingParent="1 - Presentation{BA4C44CC-65BC-4CE0-9B44-68BA231FAC73}" />
<Link Source="2 - Services{A5DF9A6E-87DC-49E9-A437-04C399572BD4}" Target="@12" Category="Contains" FetchingParent="2 - Services{A5DF9A6E-87DC-49E9-A437-04C399572BD4}" />
<Link Source="3 - Application{FD1B5301-2A07-47B3-8773-839429800B2F}" Target="@16" Category="Contains" FetchingParent="3 - Application{FD1B5301-2A07-47B3-8773-839429800B2F}" />
<Link Source="4 - Domain{0C6FAB88-2741-4295-B6B6-F397DBA958F0}" Target="@14" Category="Contains" FetchingParent="4 - Domain{0C6FAB88-2741-4295-B6B6-F397DBA958F0}" />
<Link Source="4 - Domain{0C6FAB88-2741-4295-B6B6-F397DBA958F0}" Target="@8" Category="Contains" FetchingParent="4 - Domain{0C6FAB88-2741-4295-B6B6-F397DBA958F0}" />
<Link Source="5 - Infra{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}" Target="5.1 - Data{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}" Category="Contains" FetchingParent="5 - Infra{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}" />
<Link Source="5 - Infra{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}" Target="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" Category="Contains" FetchingParent="5 - Infra{BAC12BD1-13B1-416E-A4B8-D889C6FFACCC}" />
<Link Source="5.1 - Data{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}" Target="@2" Category="Contains" FetchingParent="5.1 - Data{0CA11832-7E0F-4038-9DB6-FF1E6D14D0DF}" />
<Link Source="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" Target="@18" Category="Contains" FetchingParent="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" />
<Link Source="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" Target="@20" Category="Contains" FetchingParent="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" />
<Link Source="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" Target="@6" Category="Contains" FetchingParent="5.2 - CrossCutting{DF6C4BDE-F3C5-4E53-A5D5-9D27B2D3E38F}" />
<Link Source="@10" Target="@14" Category="CodeMap_ProjectReference" Bounds="-47.577363389232,194.566223023468,323.800205047103,110.120984656154" />
<Link Source="@10" Target="@18" Category="CodeMap_ExternalReference" />
<Link Source="@10" Target="@8" Category="CodeMap_ProjectReference" Bounds="-63.3860839698208,194.554113197779,410.327332445883,244.868251681802" />
<Link Source="@12" Target="@14" Category="CodeMap_ExternalReference" Bounds="1.43901544836485,79.5662549461349,296.230902918529,222.61194147472" />
<Link Source="@12" Target="@16" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="54">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@12" Target="@18" Category="CodeMap_ProjectReference" />
<Link Source="@12" Target="@2" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="2">
<Category Ref="CodeMap_ExternalReference" />
</Link>
<Link Source="@12" Target="@20" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="25">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_AttributeUse" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@12" Target="@6" Category="CodeSchema_Calls" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="1">
<Category Ref="CodeMap_ProjectReference" />
</Link>
<Link Source="@12" Target="@8" Category="CodeMap_ExternalReference" Bounds="-2.65210920614254,79.5538131977793,359.350646932472,358.127503972113" />
<Link Source="@14" Target="@18" Category="CodeMap_ProjectReference" Bounds="-117.399613163457,332.585014314614,414.727052916697,214.473963755023" />
<Link Source="@14" Target="@8" Category="CodeMap_ProjectReference" Bounds="369.58419525877,389.885193222508,4.08937492700574,45.185858825311" />
<Link Source="@16" Target="@14" Category="References" Bounds="194.866830350749,194.565957485335,107.628991032217,106.683241347834" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="34">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@16" Target="@18" Category="CodeMap_ExternalReference" />
<Link Source="@16" Target="@2" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="3">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@16" Target="@20" Category="CodeMap_ExternalReference" />
<Link Source="@16" Target="@27" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="15">
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@16" Target="@8" Category="CodeMap_ExternalReference" Bounds="154.227330982847,185.776802036459,89.7721847575576,137.465067359332" />
<Link Source="@18" Target="@26" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="3">
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@18" Target="@8" Category="CodeMap_ProjectReference" Bounds="-140.611190501101,280.77728346509,188.087672807635,71.274646541285" />
<Link Source="@2" Target="@14" Category="References" Bounds="21.564102771709,324.028945962714,210.031495032539,9.21381583300018" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="68">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="Implements" />
</Link>
<Link Source="@2" Target="@18" Category="CodeMap_ExternalReference" />
<Link Source="@2" Target="@20" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="4">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@2" Target="@26" Category="Implements" IsSourceVirtualized="True" Weight="1" />
<Link Source="@2" Target="@27" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="33">
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@2" Target="@8" Category="CodeMap_ExternalReference" Bounds="-120.124283957462,441.80867530402,167.024382476442,6.87554966105625" />
<Link Source="@20" Target="@14" Category="CodeMap_ProjectReference" Bounds="31.0506718352239,337.251262582601,262.136357997213,158.941913005222" />
<Link Source="@20" Target="@18" Category="CodeMap_ExternalReference" Bounds="-104.690315888496,521.193175587823,78.7616817454847,27.0743773260615" />
<Link Source="@20" Target="@8" Category="CodeMap_ExternalReference" Bounds="97.9516649368087,470.306973586494,181.238057682772,25.8862020013291" />
<Link Source="@21" Target="@26" Category="Contains" FetchingParent="@21" />
<Link Source="@21" Target="@27" Category="Contains" FetchingParent="@21" />
<Link Source="@23" Target="@25" Category="Contains" FetchingParent="@23" />
<Link Source="@25" Target="(@7 @22 @24 Member=.ctor)" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@29" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@30" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@31" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@32" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@33" Category="Contains" FetchingParent="@25" />
<Link Source="@25" Target="@34" Category="Contains" FetchingParent="@25" />
<Link Source="@29" Target="@30" Category="CodeSchema_Calls" Bounds="139.843872070313,404.050689697266,0,21" Weight="1" />
<Link Source="@31" Target="@25" Category="References" Bounds="319.193878173828,447.030609130859,70.0249938964844,12.322265625" Weight="2" />
<Link Source="@32" Target="@25" Category="References" Bounds="270.802215576172,324.590606689453,12.322265625,53.4999084472656" Weight="2" />
<Link Source="@32" Target="@31" Category="CodeSchema_Calls" Bounds="270.802215576172,404.050689697266,0,21" Weight="1" />
<Link Source="@33" Target="@34" Category="CodeSchema_Calls" Bounds="159.272216796875,515.970703125,0,21" Weight="1" />
<Link Source="@4" Target="@14" Category="CodeMap_ExternalReference" Bounds="230.189079618185,79.5662549461349,83.3698073279606,219.604690093754" />
<Link Source="@4" Target="@16" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="140">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@4" Target="@18" Category="CodeMap_ExternalReference" />
<Link Source="@4" Target="@2" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="2">
<Category Ref="CodeMap_ExternalReference" />
</Link>
<Link Source="@4" Target="@20" Category="CodeSchema_AttributeUse" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="7">
<Category Ref="CodeMap_ProjectReference" />
<Category Ref="CodeSchema_Calls" />
</Link>
<Link Source="@4" Target="@6" Category="CodeSchema_Calls" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="1">
<Category Ref="CodeMap_ProjectReference" />
</Link>
<Link Source="@4" Target="@8" Category="CodeMap_ExternalReference" Bounds="230.263268433022,79.5538131977793,137.295325249313,356.08318755289" />
<Link Source="@6" Target="@14" Category="References" Bounds="-105.493684173451,335.040821454581,374.262456587038,106.152354133242" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="13">
<Category Ref="CodeMap_ProjectReference" />
</Link>
<Link Source="@6" Target="@16" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="2">
<Category Ref="CodeMap_ProjectReference" />
</Link>
<Link Source="@6" Target="@18" Category="References" Bounds="-149.565063894958,466.193075587823,5.6843418860808E-14,76.0002" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="1">
<Category Ref="CodeMap_ExternalReference" />
</Link>
<Link Source="@6" Target="@2" Category="References" IsSourceVirtualized="True" IsTargetVirtualized="True" Weight="6">
<Category Ref="CodeMap_ProjectReference" />
</Link>
<Link Source="@6" Target="@20" Category="CodeMap_ExternalReference" Bounds="-113.201493646904,466.193075587824,78.7616817454849,27.0743773260614" />
<Link Source="@6" Target="@26" Category="References" IsSourceVirtualized="True" Weight="1" />
<Link Source="@6" Target="@8" Category="CodeMap_ExternalReference" Bounds="-148.477051149248,225.77718346509,207.583073668638,101.060611733082" />
<Link Source="@8" Target="@21" Category="Contains" FetchingParent="@8" />
<Link Source="@8" Target="@23" Category="Contains" FetchingParent="@8" />
<Link Source="NewFolder1{7426F6BA-3DAD-411E-9956-3980D42DC36F}" Target="@10" Category="Contains" FetchingParent="NewFolder1{7426F6BA-3DAD-411E-9956-3980D42DC36F}" />
</Links>
<Categories>
<Category Id="CodeMap_ExternalReference" Label="External Reference" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Referenced By" OutgoingActionLabel="References" />
<Category Id="CodeMap_ProjectReference" Label="Project Reference" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Referenced By" OutgoingActionLabel="References" />
<Category Id="CodeMap_SolutionFolder" Label="Solution Folder" CanBeDataDriven="True" IsProviderRoot="False" NavigationActionLabel="Solution Folder" />
<Category Id="CodeSchema_Assembly" Label="Assembly" BasedOn="File" CanBeDataDriven="True" DefaultAction="Microsoft.Contains" Icon="CodeSchema_Assembly" NavigationActionLabel="Assemblies" />
<Category Id="CodeSchema_AttributeUse" Label="Uses Attribute" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Used by" OutgoingActionLabel="Uses Attribute" />
<Category Id="CodeSchema_Calls" Label="Calls" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Called By" OutgoingActionLabel="Calls" />
<Category Id="CodeSchema_Class" Label="Class" BasedOn="CodeSchema_Type" CanBeDataDriven="True" DefaultAction="Node:Both:CodeSchema_Member" Icon="CodeSchema_Class" NavigationActionLabel="Classes" />
<Category Id="CodeSchema_Interface" Label="Interface" BasedOn="CodeSchema_Type" CanBeDataDriven="True" DefaultAction="Node:Both:CodeSchema_Member" Icon="CodeSchema_Interface" NavigationActionLabel="Interfaces" />
<Category Id="CodeSchema_Member" Label="Member" CanBeDataDriven="True" DefaultAction="Microsoft.Contains" Icon="CodeSchema_Field" NavigationActionLabel="Members" />
<Category Id="CodeSchema_Method" Label="Method" BasedOn="CodeSchema_Member" CanBeDataDriven="True" DefaultAction="Link:Forward:CodeSchema_Calls" Icon="CodeSchema_Method" NavigationActionLabel="Methods" />
<Category Id="CodeSchema_Namespace" Label="Namespace" CanBeDataDriven="True" DefaultAction="Node:Both:CodeSchema_Type" Icon="CodeSchema_Namespace" NavigationActionLabel="Namespaces" />
<Category Id="CodeSchema_Type" Label="Type" CanBeDataDriven="True" DefaultAction="Node:Both:CodeSchema_Member" Icon="CodeSchema_Class" NavigationActionLabel="Types" />
<Category Id="Contains" Label="Contains" Description="Whether the source of the link contains the target object" CanBeDataDriven="False" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Contained By" IsContainment="True" OutgoingActionLabel="Contains" />
<Category Id="File" Label="File" CanBeDataDriven="True" DefaultAction="Microsoft.Contains" Icon="File" NavigationActionLabel="Files" />
<Category Id="Implements" Label="Implements" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Implemented by" OutgoingActionLabel="Implements" />
<Category Id="References" Label="References" CanBeDataDriven="True" CanLinkedNodesBeDataDriven="True" IncomingActionLabel="Referenced By" OutgoingActionLabel="References" />
</Categories>
<Properties>
<Property Id="Bounds" DataType="System.Windows.Rect" />
<Property Id="CanBeDataDriven" Label="CanBeDataDriven" Description="CanBeDataDriven" DataType="System.Boolean" />
<Property Id="CanLinkedNodesBeDataDriven" Label="CanLinkedNodesBeDataDriven" Description="CanLinkedNodesBeDataDriven" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsAbstract" Label="Is Abstract" Description="Flag to indicate member is 'Abstract' does not provide a full implementation" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsConstructor" Label="Is Constructor" Description="Flag to indicate the method is a constructor" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsGeneric" Label="Is Generic" Description="Flag to indicate the member is 'Generic'" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsProtected" Label="Is Protected" Description="Flag to indicate the scope is Protected" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsPublic" Label="Is Public" Description="Flag to indicate the scope is Public" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsSpecialName" Label="Is Special Name" Description="Flag to indicate the method is treated in a special way by some compilers" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsStatic" Label="Is Static" Description="Flag to indicate the member is a static member" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_IsVirtual" Label="Is Virtual" Description="Flag to indicate the method can be overridden" DataType="System.Boolean" />
<Property Id="CodeSchemaProperty_StrongName" Label="StrongName" Description="StrongName" DataType="System.String" />
<Property Id="DataVirtualized" Label="Data Virtualized" Description="If true, the graph can contain nodes and links that represent data for virtualized nodes/links (i.e. not actually created in the graph)." DataType="System.Boolean" />
<Property Id="DefaultAction" Label="DefaultAction" Description="DefaultAction" DataType="System.String" />
<Property Id="DelayedChildNodesState" Label="Delayed Child Nodes State" Description="Unspecified if the delayed child nodes state is not specified. NotFetched if the group contains child nodes that are not fetched into the graph yet. Fetched if the group has all its delayed child nodes already fetched." DataType="Microsoft.VisualStudio.GraphModel.DelayedDataState" />
<Property Id="DelayedCrossGroupLinksState" Label="Delayed Cross-Group Links State" Description="Unspecified if the delayed cross-group links state is not specified. NotFetched if delayed cross-group links on this node are not fetched into the graph yet. Fetched if all delayed cross-group links have already fetched." DataType="Microsoft.VisualStudio.GraphModel.DelayedDataState" />
<Property Id="Expression" DataType="System.String" />
<Property Id="FetchedChildrenCount" DataType="System.Int32" />
<Property Id="FetchingParent" DataType="Microsoft.VisualStudio.GraphModel.GraphNodeId" />
<Property Id="FilePath" Label="File Path" Description="File Path" DataType="System.String" />
<Property Id="Group" Label="Group" Description="Display the node as a group" DataType="Microsoft.VisualStudio.GraphModel.GraphGroupStyle" />
<Property Id="GroupLabel" DataType="System.String" />
<Property Id="Icon" Label="Icon" Description="Icon" DataType="System.String" />
<Property Id="IncomingActionLabel" Label="IncomingActionLabel" Description="IncomingActionLabel" DataType="System.String" />
<Property Id="IsContainment" DataType="System.Boolean" />
<Property Id="IsEnabled" DataType="System.Boolean" />
<Property Id="IsProviderRoot" Label="IsProviderRoot" Description="IsProviderRoot" DataType="System.Boolean" />
<Property Id="IsSourceVirtualized" Label="Link Source Virtualized" Description="If true, the link source end contains data for virtualized nodes/links (i.e. not actually created in the graph)." DataType="System.Boolean" />
<Property Id="IsTargetVirtualized" Label="Link Target Virtualized" Description="If true, the link target end contains data for virtualized nodes/links (i.e. not actually created in the graph)." DataType="System.Boolean" />
<Property Id="Label" Label="Label" Description="Displayable label of an Annotatable object" DataType="System.String" />
<Property Id="Layout" DataType="System.String" />
<Property Id="NavigationActionLabel" Label="NavigationActionLabel" Description="NavigationActionLabel" DataType="System.String" />
<Property Id="OutgoingActionLabel" Label="OutgoingActionLabel" Description="OutgoingActionLabel" DataType="System.String" />
<Property Id="TargetType" DataType="System.Type" />
<Property Id="UseManualLocation" DataType="System.Boolean" />
<Property Id="Value" DataType="System.String" />
<Property Id="ValueLabel" DataType="System.String" />
<Property Id="Visibility" Label="Visibility" Description="Defines whether a node in the graph is visible or not" DataType="System.Windows.Visibility" />
<Property Id="Weight" Label="Weight" Description="Weight" DataType="System.Double" />
<Property Id="ZoomLevel" DataType="System.String" />
</Properties>
<QualifiedNames>
<Name Id="Assembly" Label="Assembly" ValueType="Uri" />
<Name Id="GenericArguments" Label="Generic Arguments" ValueType="Microsoft.VisualStudio.GraphModel.GraphNodeIdCollection" />
<Name Id="GenericParameterCount" Label="Generic Parameter Count" ValueType="System.String" />
<Name Id="Member" Label="Member" ValueType="System.Object" />
<Name Id="Name" Label="Name" ValueType="System.String" />
<Name Id="Namespace" Label="Namespace" ValueType="System.String" />
<Name Id="OverloadingParameters" Label="Parameter" ValueType="Microsoft.VisualStudio.GraphModel.GraphNodeIdCollection" Formatter="NameValueNoEscape" />
<Name Id="ParameterIdentifier" Label="Parameter Identifier" ValueType="System.String" />
<Name Id="Type" Label="Type" ValueType="System.Object" />
</QualifiedNames>
<IdentifierAliases>
<Alias n="1" Uri="Assembly=$(f0ddf87d-98a4-4237-91c9-fd865ed78abb.OutputPathUri)" />
<Alias n="2" Id="(@1)" />
<Alias n="3" Uri="Assembly=$(490517ba-f3c3-44b4-82f8-1e3a4ed6777a.OutputPathUri)" />
<Alias n="4" Id="(@3)" />
<Alias n="5" Uri="Assembly=$(b3000ad2-5eaa-49a2-8fc4-10df329b15b0.OutputPathUri)" />
<Alias n="6" Id="(@5)" />
<Alias n="7" Uri="Assembly=$(9cc884b7-fa70-49e1-92a6-2b566e00fab9.OutputPathUri)" />
<Alias n="8" Id="(@7)" />
<Alias n="9" Uri="Assembly=$(c4036d98-a669-440c-9970-05db45815949.OutputPathUri)" />
<Alias n="10" Id="(@9)" />
<Alias n="11" Uri="Assembly=$(ea966ec3-85a6-4b57-82c1-5120e3390243.OutputPathUri)" />
<Alias n="12" Id="(@11)" />
<Alias n="13" Uri="Assembly=$(bf28c988-9c1b-41f5-bd58-d2fcad7e80ba.OutputPathUri)" />
<Alias n="14" Id="(@13)" />
<Alias n="15" Uri="Assembly=$(851e7338-2397-4e8d-8199-fd1ead109418.OutputPathUri)" />
<Alias n="16" Id="(@15)" />
<Alias n="17" Uri="Assembly=$(91f0d76d-2bea-43d2-b123-dc29f2e87792.OutputPathUri)" />
<Alias n="18" Id="(@17)" />
<Alias n="19" Uri="Assembly=$(788030d0-561b-4136-96b4-d5abfb5cfd07.OutputPathUri)" />
<Alias n="20" Id="(@19)" />
<Alias n="21" Id="(@7 Namespace=Equinox.Domain.Core.Events)" />
<Alias n="22" Id="Namespace=Equinox.Domain.Core.Models" />
<Alias n="23" Id="(@7 @22)" />
<Alias n="24" Id="Type=(Name=ValueObject GenericParameterCount=1)" />
<Alias n="25" Id="(@7 @22 @24)" />
<Alias n="26" Id="(@7 Namespace=Equinox.Domain.Core.Events Type=IEventStore)" />
<Alias n="27" Id="(@7 Namespace=Equinox.Domain.Core.Events Type=StoredEvent)" />
<Alias n="28" Uri="Assembly=$(ProgramFilesUri)/dotnet/packs/Microsoft.NETCore.App.Ref/8.0.3/ref/net8.0/System.Runtime.dll" />
<Alias n="29" Id="(@7 @22 @24 Member=(Name=Equals OverloadingParameters=[(@28 Namespace=System Type=Object)]))" />
<Alias n="30" Id="(@7 @22 @24 Member=(Name=EqualsCore OverloadingParameters=[(@7 @22 @24 ParameterIdentifier=0)]))" />
<Alias n="31" Id="(@7 @22 @24 Member=(Name=op_Equality OverloadingParameters=[(@7 @22 Type=(Name=ValueObject GenericParameterCount=1 GenericArguments=[(@7 @22 @24 ParameterIdentifier=0)])),(@7 @22 Type=(Name=ValueObject GenericParameterCount=1 GenericArguments=[(@7 @22 @24 ParameterIdentifier=0)]))]))" />
<Alias n="32" Id="(@7 @22 @24 Member=(Name=op_Inequality OverloadingParameters=[(@7 @22 Type=(Name=ValueObject GenericParameterCount=1 GenericArguments=[(@7 @22 @24 ParameterIdentifier=0)])),(@7 @22 Type=(Name=ValueObject GenericParameterCount=1 GenericArguments=[(@7 @22 @24 ParameterIdentifier=0)]))]))" />
<Alias n="33" Id="(@7 @22 @24 Member=GetHashCode)" />
<Alias n="34" Id="(@7 @22 @24 Member=GetHashCodeCore)" />
</IdentifierAliases>
<Styles>
<Style TargetType="Node" GroupLabel="Results" ValueLabel="True">
<Condition Expression="HasCategory('QueryResult')" />
<Setter Property="Background" Value="#FFBCFFBE" />
</Style>
<Style TargetType="Node" GroupLabel="Test Project" ValueLabel="Test Project">
<Condition Expression="HasCategory('CodeMap_TestProject')" />
<Setter Property="Icon" Value="CodeMap_TestProject" />
<Setter Property="Background" Value="#FF307A69" />
</Style>
<Style TargetType="Node" GroupLabel="Web Project" ValueLabel="Web Project">
<Condition Expression="HasCategory('CodeMap_WebProject')" />
<Setter Property="Icon" Value="CodeMap_WebProject" />
</Style>
<Style TargetType="Node" GroupLabel="Windows Store Project" ValueLabel="Windows Store Project">
<Condition Expression="HasCategory('CodeMap_WindowsStoreProject')" />
<Setter Property="Icon" Value="CodeMap_WindowsStoreProject" />
</Style>
<Style TargetType="Node" GroupLabel="Phone Project" ValueLabel="Phone Project">
<Condition Expression="HasCategory('CodeMap_PhoneProject')" />
<Setter Property="Icon" Value="CodeMap_PhoneProject" />
</Style>
<Style TargetType="Node" GroupLabel="Portable Library" ValueLabel="Portable Library">
<Condition Expression="HasCategory('CodeMap_PortableLibraryProject')" />
<Setter Property="Icon" Value="CodeMap_PortableLibraryProject" />
</Style>
<Style TargetType="Node" GroupLabel="WPF Project" ValueLabel="WPF Project">
<Condition Expression="HasCategory('CodeMap_WpfProject')" />
<Setter Property="Icon" Value="CodeMap_WpfProject" />
</Style>
<Style TargetType="Node" GroupLabel="VSIX Project" ValueLabel="VSIX Project">
<Condition Expression="HasCategory('CodeMap_VsixProject')" />
<Setter Property="Icon" Value="CodeMap_VsixProject" />
</Style>
<Style TargetType="Node" GroupLabel="Modeling Project" ValueLabel="Modeling Project">
<Condition Expression="HasCategory('CodeMap_ModelingProject')" />
<Setter Property="Icon" Value="CodeMap_ModelingProject" />
</Style>
<Style TargetType="Node" GroupLabel="Assembly" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Assembly')" />
<Setter Property="Background" Value="#FF094167" />
<Setter Property="Stroke" Value="#FF094167" />
<Setter Property="Icon" Value="CodeSchema_Assembly" />
</Style>
<Style TargetType="Node" GroupLabel="Namespace" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Namespace')" />
<Setter Property="Background" Value="#FF0E619A" />
<Setter Property="Stroke" Value="#FF0E619A" />
<Setter Property="Icon" Value="CodeSchema_Namespace" />
</Style>
<Style TargetType="Node" GroupLabel="Interface" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Interface')" />
<Setter Property="Background" Value="#FF1382CE" />
<Setter Property="Stroke" Value="#FF1382CE" />
<Setter Property="Icon" Value="CodeSchema_Interface" />
</Style>
<Style TargetType="Node" GroupLabel="Struct" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Struct')" />
<Setter Property="Background" Value="#FF1382CE" />
<Setter Property="Stroke" Value="#FF1382CE" />
<Setter Property="Icon" Value="CodeSchema_Struct" />
</Style>
<Style TargetType="Node" GroupLabel="Enumeration" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Enum')" />
<Setter Property="Background" Value="#FF1382CE" />
<Setter Property="Stroke" Value="#FF1382CE" />
<Setter Property="Icon" Value="CodeSchema_Enum" />
<Setter Property="LayoutSettings" Value="List" />
</Style>
<Style TargetType="Node" GroupLabel="Delegate" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Delegate')" />
<Setter Property="Background" Value="#FF1382CE" />
<Setter Property="Stroke" Value="#FF1382CE" />
<Setter Property="Icon" Value="CodeSchema_Delegate" />
</Style>
<Style TargetType="Node" GroupLabel="Class" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Type')" />
<Setter Property="Background" Value="#FF0E70C0" />
<Setter Property="Stroke" Value="#FF0E70C0" />
<Setter Property="Icon" Value="CodeSchema_Class" />
</Style>
<Style TargetType="Node" GroupLabel="Property" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Property')" />
<Setter Property="Background" Value="#FFE0E0E0" />
<Setter Property="Stroke" Value="#FFE0E0E0" />
<Setter Property="Icon" Value="CodeSchema_Property" />
</Style>
<Style TargetType="Node" GroupLabel="Method" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Method') Or HasCategory('CodeSchema_CallStackUnresolvedMethod')" />
<Setter Property="Background" Value="#FFE0E0E0" />
<Setter Property="Stroke" Value="#FFE0E0E0" />
<Setter Property="Icon" Value="CodeSchema_Method" />
<Setter Property="LayoutSettings" Value="List" />
</Style>
<Style TargetType="Node" GroupLabel="Event" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Event')" />
<Setter Property="Background" Value="#FFE0E0E0" />
<Setter Property="Stroke" Value="#FFE0E0E0" />
<Setter Property="Icon" Value="CodeSchema_Event" />
</Style>
<Style TargetType="Node" GroupLabel="Field" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Field')" />
<Setter Property="Background" Value="#FFE0E0E0" />
<Setter Property="Stroke" Value="#FFE0E0E0" />
<Setter Property="Icon" Value="CodeSchema_Field" />
</Style>
<Style TargetType="Node" GroupLabel="Out Parameter" ValueLabel="Has category">
<Condition Expression="CodeSchemaProperty_IsOut = 'True'" />
<Setter Property="Icon" Value="CodeSchema_OutParameter" />
</Style>
<Style TargetType="Node" GroupLabel="Parameter" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_Parameter')" />
<Setter Property="Icon" Value="CodeSchema_Parameter" />
</Style>
<Style TargetType="Node" GroupLabel="Local Variable" ValueLabel="Has category">
<Condition Expression="HasCategory('CodeSchema_LocalExpression')" />
<Setter Property="Icon" Value="CodeSchema_LocalExpression" />
</Style>
<Style TargetType="Node" GroupLabel="Externals" ValueLabel="Has category">
<Condition Expression="HasCategory('Externals')" />
<Setter Property="Background" Value="#FF424242" />
<Setter Property="Stroke" Value="#FF424242" />
</Style>
<Style TargetType="Link" GroupLabel="Inherits From" ValueLabel="True">
<Condition Expression="HasCategory('InheritsFrom')" />
<Setter Property="Stroke" Value="#FF00A600" />
<Setter Property="StrokeDashArray" Value="2 0" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="Implements" ValueLabel="True">
<Condition Expression="HasCategory('Implements')" />
<Setter Property="Stroke" Value="#8000A600" />
<Setter Property="StrokeDashArray" Value="2 2" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="Calls" ValueLabel="True">
<Condition Expression="HasCategory('CodeSchema_Calls')" />
<Setter Property="Stroke" Value="#FFFF00FF" />
<Setter Property="StrokeDashArray" Value="2 0" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="Function Pointer" ValueLabel="True">
<Condition Expression="HasCategory('CodeSchema_FunctionPointer')" />
<Setter Property="Stroke" Value="#FFFF00FF" />
<Setter Property="StrokeDashArray" Value="2 2" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="Field Read" ValueLabel="True">
<Condition Expression="HasCategory('CodeSchema_FieldRead')" />
<Setter Property="Stroke" Value="#FF00AEEF" />
<Setter Property="StrokeDashArray" Value="2 2" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="Field Write" ValueLabel="True">
<Condition Expression="HasCategory('CodeSchema_FieldWrite')" />
<Setter Property="Stroke" Value="#FF00AEEF" />
<Setter Property="DrawArrow" Value="true" />
<Setter Property="IsHidden" Value="false" />
</Style>
<Style TargetType="Link" GroupLabel="Inherits From" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('InheritsFrom') And Target.HasCategory('CodeSchema_Class')" />
<Setter Property="TargetDecorator" Value="OpenArrow" />
</Style>
<Style TargetType="Link" GroupLabel="Implements" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('Implements') And Target.HasCategory('CodeSchema_Interface')" />
<Setter Property="TargetDecorator" Value="OpenArrow" />
</Style>
<Style TargetType="Link" GroupLabel="Comment Link" ValueLabel="True" Visibility="Hidden">
<Condition Expression="Source.HasCategory('Comment')" />
<Setter Property="Stroke" Value="#FFE5C365" />
</Style>
<Style TargetType="Node" GroupLabel="Cursor Location Changed" ValueLabel="True" Visibility="Hidden">
<Condition Expression="IsCursorLocation" />
<Setter Property="IndicatorWest" Value="WestIndicator" />
</Style>
<Style TargetType="Node" GroupLabel="Disabled Breakpoint Location Changed" ValueLabel="True" Visibility="Hidden">
<Condition Expression="DisabledBreakpointCount" />
<Setter Property="IndicatorWest" Value="WestIndicator" />
</Style>
<Style TargetType="Node" GroupLabel="Enabled Breakpoint Location Changed" ValueLabel="True" Visibility="Hidden">
<Condition Expression="EnabledBreakpointCount" />
<Setter Property="IndicatorWest" Value="WestIndicator" />
</Style>
<Style TargetType="Node" GroupLabel="Instruction Pointer Location Changed" ValueLabel="True" Visibility="Hidden">
<Condition Expression="IsInstructionPointerLocation" />
<Setter Property="IndicatorWest" Value="WestIndicator" />
</Style>
<Style TargetType="Node" GroupLabel="Current Callstack Changed" ValueLabel="True" Visibility="Hidden">
<Condition Expression="IsCurrentCallstackFrame" />
<Setter Property="IndicatorWest" Value="WestIndicator" />
</Style>
<Style TargetType="Link" GroupLabel="Return" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('CodeSchema_ReturnTypeLink')" />
</Style>
<Style TargetType="Link" GroupLabel="References" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('References')" />
</Style>
<Style TargetType="Link" GroupLabel="Uses Attribute" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('CodeSchema_AttributeUse')" />
</Style>
<Style TargetType="Node" GroupLabel="Solution Folder" ValueLabel="True" Visibility="Hidden">
<Condition Expression="HasCategory('CodeMap_SolutionFolder')" />
<Setter Property="Background" Value="#FFDEBA83" />
</Style>
<Style TargetType="Link" GroupLabel="Project Reference" ValueLabel="Project Reference">
<Condition Expression="HasCategory('CodeMap_ProjectReference')" />
<Setter Property="Stroke" Value="#9A9A9A" />
<Setter Property="StrokeDashArray" Value="2 2" />
<Setter Property="DrawArrow" Value="true" />
</Style>
<Style TargetType="Link" GroupLabel="External Reference" ValueLabel="External Reference">
<Condition Expression="HasCategory('CodeMap_ExternalReference')" />
<Setter Property="Stroke" Value="#9A9A9A" />
<Setter Property="StrokeDashArray" Value="2 2" />
<Setter Property="DrawArrow" Value="true" />
</Style>
</Styles>
<Paths>
<Path Id="490517ba-f3c3-44b4-82f8-1e3a4ed6777a.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.UI.Web\bin\Debug\net8.0\Equinox.UI.Web.dll" />
<Path Id="490517ba-f3c3-44b4-82f8-1e3a4ed6777a.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.UI.Web/bin/Debug/net8.0/Equinox.UI.Web.dll" />
<Path Id="788030d0-561b-4136-96b4-d5abfb5cfd07.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Infra.CrossCutting.Identity\bin\Debug\net8.0\Equinox.Infra.CrossCutting.Identity.dll" />
<Path Id="788030d0-561b-4136-96b4-d5abfb5cfd07.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Infra.CrossCutting.Identity/bin/Debug/net8.0/Equinox.Infra.CrossCutting.Identity.dll" />
<Path Id="851e7338-2397-4e8d-8199-fd1ead109418.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Application\bin\Debug\net8.0\Equinox.Application.dll" />
<Path Id="851e7338-2397-4e8d-8199-fd1ead109418.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Application/bin/Debug/net8.0/Equinox.Application.dll" />
<Path Id="91f0d76d-2bea-43d2-b123-dc29f2e87792.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Infra.CrossCutting.Bus\bin\Debug\net8.0\Equinox.Infra.CrossCutting.Bus.dll" />
<Path Id="91f0d76d-2bea-43d2-b123-dc29f2e87792.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Infra.CrossCutting.Bus/bin/Debug/net8.0/Equinox.Infra.CrossCutting.Bus.dll" />
<Path Id="9cc884b7-fa70-49e1-92a6-2b566e00fab9.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Domain.Core\bin\Debug\net8.0\Equinox.Domain.Core.dll" />
<Path Id="9cc884b7-fa70-49e1-92a6-2b566e00fab9.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Domain.Core/bin/Debug/net8.0/Equinox.Domain.Core.dll" />
<Path Id="b3000ad2-5eaa-49a2-8fc4-10df329b15b0.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Infra.CrossCutting.IoC\bin\Debug\net8.0\Equinox.Infra.CrossCutting.IoC.dll" />
<Path Id="b3000ad2-5eaa-49a2-8fc4-10df329b15b0.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Infra.CrossCutting.IoC/bin/Debug/net8.0/Equinox.Infra.CrossCutting.IoC.dll" />
<Path Id="bf28c988-9c1b-41f5-bd58-d2fcad7e80ba.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Domain\bin\Debug\net8.0\Equinox.Domain.dll" />
<Path Id="bf28c988-9c1b-41f5-bd58-d2fcad7e80ba.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Domain/bin/Debug/net8.0/Equinox.Domain.dll" />
<Path Id="c4036d98-a669-440c-9970-05db45815949.OutputPath" Value="D:\Projetos\EquinoxProject\tests\Equinox.Tests.Architecture\bin\Debug\net8.0\Equinox.Tests.Architecture.dll" />
<Path Id="c4036d98-a669-440c-9970-05db45815949.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/tests/Equinox.Tests.Architecture/bin/Debug/net8.0/Equinox.Tests.Architecture.dll" />
<Path Id="ea966ec3-85a6-4b57-82c1-5120e3390243.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Services.Api\bin\Debug\net8.0\Equinox.Services.Api.dll" />
<Path Id="ea966ec3-85a6-4b57-82c1-5120e3390243.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Services.Api/bin/Debug/net8.0/Equinox.Services.Api.dll" />
<Path Id="f0ddf87d-98a4-4237-91c9-fd865ed78abb.OutputPath" Value="D:\Projetos\EquinoxProject\src\Equinox.Infra.Data\bin\Debug\net8.0\Equinox.Infra.Data.dll" />
<Path Id="f0ddf87d-98a4-4237-91c9-fd865ed78abb.OutputPathUri" Value="file:///D:/Projetos/EquinoxProject/src/Equinox.Infra.Data/bin/Debug/net8.0/Equinox.Infra.Data.dll" />
<Path Id="ProgramFilesUri" Value="file:///C:/Program Files" />
</Paths>
</DirectedGraph>
================================================
FILE: docs/_config.yml
================================================
title: The Equinox Project
description: Full ASP.NET Core 3.1 application with DDD, CQRS and Event Sourcing
google_analytics:
show_downloads: true
theme: jekyll-theme-cayman
gems:
- jekyll-mentions
================================================
FILE: docs/index.md
================================================
<img src="https://www.eduardopires.net.br/imagens/EquinoxLogoPequenoFundoBranco.png" alt="Equinox Project">
What is the Equinox Project?
=====================
The Equinox Project is a open-source project written in .NET Core
The goal of this project is implement the most common used technologies and share with the technical community the best way to develop great applications with .NET
[](LICENSE)
[](https://huboard.com/EduardoPires/EquinoxProject/)
## Give a Star! :star:
If you liked the project or if Equinox helped you, please give a star ;)
## Want to learn everything? :mortar_board:
Check my online courses at [desenvolvedor.io](https://desenvolvedor.io)
## How to use:
- You will need the latest Visual Studio 2019 and the latest .NET Core SDK.
- ***Please check if you have installed the same runtime version (SDK) described in global.json***
- The latest SDK and tools can be downloaded from https://dot.net/core.
Also you can run the Equinox Project in Visual Studio Code (Windows, Linux or MacOS).
To know more about how to setup your enviroment visit the [Microsoft .NET Download Guide](https://www.microsoft.com/net/download)
## Technologies implemented:
- ASP.NET Core 3.1 (with .NET Core 3.1)
- ASP.NET MVC Core
- ASP.NET WebApi Core with JWT Bearer Authentication
- ASP.NET Identity Core
- Entity Framework Core 3.1
- .NET Core Native DI
- AutoMapper
- FluentValidator
- MediatR
- Swagger UI with JWT support
## Architecture:
- Full architecture with responsibility separation concerns, SOLID and Clean Code
- Domain Driven Design (Layers and Domain Model Pattern)
- Domain Events
- Domain Notification
- CQRS (Imediate Consistency)
- Event Sourcing
- Unit of Work
- Repository and Generic Repository
## News
**v1.5 - 01/22/2020**
- Migrated for .NET Core 3.1.1
- All dependencies is up to date
- Added JWT (Bearer) authentication for WebAPI
- Added JWT support in Swagger
**v1.4 - 02/14/2019**
- Migrated for .NET Core 2.2.1
- All dependencies is up to date
- Improvements for last version of MediatR (Notifications and Request)
**v1.3 - 05/22/2018**
- Migrated for .NET Core 2.1.2
- All dependencies is up to date
- Improvements in Automapper Setup
- Improvements for last version of MediatR (Notifications and Request)
- Code improvements in general
**v1.2 - 08/15/2017**
- Migrated for .NET Core 2.0 and ASP.NET Core 2.0
- Adaptations for the new Identity Authentication Model
**v1.1 - 08/09/2017**
- Adding WebAPI service exposing the application features
- Adding Swagger UI for better viewing and testing
- Adding MediatR for Memory Bus Messaging
## Disclaimer:
- **NOT** intended to be a definitive solution
- Beware to use in production way
- Maybe you don't need a lot of implementations that is included, try avoid the **over engineering**
## About the next versions
Watch our [RoadMap](https://github.com/EduardoPires/EquinoxProject/wiki/RoadMap) to know the new changes
## Pull-Requests
Make a contact! Don't submit PRs for extra features, all new features is coming in V2
## Why Equinox?
The Equinox is an astronomical event in which the plane of Earth's equator passes through the center of the Sun, which occurs twice each year, around 20 March and 23 September. [Wikipedia](https://en.wikipedia.org/wiki/Equinox)
Equinox is also a series of publications (subtitle: "The Review of Scientific Illuminism") in book form that serves as the official organ of the A∴A∴, a magical order founded by Aleister Crowley :) [Wikipedia](https://en.wikipedia.org/wiki/The_Equinox)
## We are Online:
See the project running on <a href="http://equinoxproject.azurewebsites.net" target="_blank">Azure</a>
## About:
The Equinox Project was developed by [Eduardo Pires](http://eduardopires.net.br) under the [MIT license](LICENSE).
================================================
FILE: src/Equinox.Application/Equinox.Application.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj" />
<ProjectReference Include="..\Equinox.Infra.Data\Equinox.Infra.Data.csproj" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Application/EventSourcedNormalizers/CustomerHistory.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Equinox.Domain.Core.Events;
namespace Equinox.Application.EventSourcedNormalizers
{
public static class CustomerHistory
{
public static IList<CustomerHistoryData> HistoryData { get; set; }
public static IList<CustomerHistoryData> ToJavaScriptCustomerHistory(IList<StoredEvent> storedEvents)
{
HistoryData = new List<CustomerHistoryData>();
CustomerHistoryDeserializer(storedEvents);
var sorted = HistoryData.OrderBy(c => c.Timestamp);
var list = new List<CustomerHistoryData>();
var last = new CustomerHistoryData();
foreach (var change in sorted)
{
var jsSlot = new CustomerHistoryData
{
Id = change.Id == Guid.Empty.ToString() || change.Id == last.Id
? ""
: change.Id,
Name = string.IsNullOrWhiteSpace(change.Name) || change.Name == last.Name
? ""
: change.Name,
Email = string.IsNullOrWhiteSpace(change.Email) || change.Email == last.Email
? ""
: change.Email,
BirthDate = string.IsNullOrWhiteSpace(change.BirthDate) || change.BirthDate == last.BirthDate
? ""
: change.BirthDate.Substring(0,10),
Action = string.IsNullOrWhiteSpace(change.Action) ? "" : change.Action,
Timestamp = change.Timestamp,
Who = change.Who
};
list.Add(jsSlot);
last = change;
}
return list;
}
private static void CustomerHistoryDeserializer(IEnumerable<StoredEvent> storedEvents)
{
foreach (var e in storedEvents)
{
var historyData = JsonSerializer.Deserialize<CustomerHistoryData>(e.Data);
historyData.Timestamp = DateTime.Parse(historyData.Timestamp).ToString("yyyy'-'MM'-'dd' - 'HH':'mm':'ss");
switch (e.MessageType)
{
case "CustomerRegisteredEvent":
historyData.Action = "Registered";
historyData.Who = e.User;
break;
case "CustomerUpdatedEvent":
historyData.Action = "Updated";
historyData.Who = e.User;
break;
case "CustomerRemovedEvent":
historyData.Action = "Removed";
historyData.Who = e.User;
break;
default:
historyData.Action = "Unrecognized";
historyData.Who = e.User ?? "Anonymous";
break;
}
HistoryData.Add(historyData);
}
}
}
}
================================================
FILE: src/Equinox.Application/EventSourcedNormalizers/CustomerHistoryData.cs
================================================
namespace Equinox.Application.EventSourcedNormalizers
{
public class CustomerHistoryData
{
public string Action { get; set; }
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string BirthDate { get; set; }
public string Timestamp { get; set; }
public string Who { get; set; }
}
}
================================================
FILE: src/Equinox.Application/Extensions/CustomerExtensions.cs
================================================
using Equinox.Application.ViewModels;
using Equinox.Domain.Commands;
using Equinox.Domain.Models;
using System.Collections.Generic;
using System.Linq;
namespace Equinox.Application.Extensions
{
public static class CustomerExtensions
{
public static CustomerViewModel ToViewModel(this Customer customer)
{
if (customer == null) return null;
return new CustomerViewModel
{
Id = customer.Id,
Name = customer.Name,
Email = customer.Email,
BirthDate = customer.BirthDate
};
}
public static IEnumerable<CustomerViewModel> ToViewModel(this IEnumerable<Customer> customers)
{
return customers?.Select(c => c.ToViewModel());
}
public static Customer ToEntity(this CustomerViewModel customer)
{
if (customer == null) return null;
return new Customer(customer.Id, customer.Name, customer.Email, customer.BirthDate);
}
public static RegisterNewCustomerCommand ToRegisterCommand(this CustomerViewModel customer)
{
if (customer == null) return null;
return new RegisterNewCustomerCommand(customer.Name, customer.Email, customer.BirthDate);
}
public static UpdateCustomerCommand ToUpdateCommand(this CustomerViewModel customer)
{
if (customer == null) return null;
return new UpdateCustomerCommand(customer.Id, customer.Name, customer.Email, customer.BirthDate);
}
}
}
================================================
FILE: src/Equinox.Application/Interfaces/ICustomerAppService.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Application.EventSourcedNormalizers;
using Equinox.Application.ViewModels;
using FluentValidation.Results;
namespace Equinox.Application.Interfaces
{
public interface ICustomerAppService : IDisposable
{
Task<IEnumerable<CustomerViewModel>> GetAll();
Task<CustomerViewModel> GetById(Guid id);
Task<ValidationResult> Register(CustomerViewModel customerViewModel);
Task<ValidationResult> Update(CustomerViewModel customerViewModel);
Task<ValidationResult> Remove(Guid id);
Task<IList<CustomerHistoryData>> GetAllHistory(Guid id);
}
}
================================================
FILE: src/Equinox.Application/Services/CustomerAppService.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Application.EventSourcedNormalizers;
using Equinox.Application.Extensions;
using Equinox.Application.Interfaces;
using Equinox.Application.ViewModels;
using Equinox.Domain.Commands;
using Equinox.Domain.Interfaces;
using Equinox.Infra.Data.Repository.EventSourcing;
using FluentValidation.Results;
using NetDevPack.Mediator;
namespace Equinox.Application.Services
{
public class CustomerAppService(ICustomerRepository customerRepository,
IMediatorHandler mediator,
IEventStoreRepository eventStoreRepository) : ICustomerAppService
{
private readonly ICustomerRepository _customerRepository = customerRepository;
private readonly IEventStoreRepository _eventStoreRepository = eventStoreRepository;
private readonly IMediatorHandler _mediator = mediator;
public async Task<IEnumerable<CustomerViewModel>> GetAll()
{
return (await _customerRepository.GetAll()).ToViewModel();
}
public async Task<CustomerViewModel> GetById(Guid id)
{
return (await _customerRepository.GetById(id)).ToViewModel();
}
public async Task<ValidationResult> Register(CustomerViewModel customerViewModel)
{
var registerCommand = customerViewModel.ToRegisterCommand();
return await _mediator.SendCommand(registerCommand);
}
public async Task<ValidationResult> Update(CustomerViewModel customerViewModel)
{
var updateCommand = customerViewModel.ToUpdateCommand();
return await _mediator.SendCommand(updateCommand);
}
public async Task<ValidationResult> Remove(Guid id)
{
var removeCommand = new RemoveCustomerCommand(id);
return await _mediator.SendCommand(removeCommand);
}
public async Task<IList<CustomerHistoryData>> GetAllHistory(Guid id)
{
return CustomerHistory.ToJavaScriptCustomerHistory(await _eventStoreRepository.All(id));
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}
================================================
FILE: src/Equinox.Application/ViewModels/CustomerViewModel.cs
================================================
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Equinox.Application.ViewModels
{
public class CustomerViewModel
{
[Key]
public Guid Id { get; set; }
[Required(ErrorMessage = "The Name is Required")]
[MinLength(2)]
[MaxLength(100)]
[DisplayName("Name")]
public string Name { get; set; }
[Required(ErrorMessage = "The E-mail is Required")]
[EmailAddress]
[DisplayName("E-mail")]
public string Email { get; set; }
[Required(ErrorMessage = "The BirthDate is Required")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
[DataType(DataType.Date, ErrorMessage = "Data em formato inválido")]
[DisplayName("Birth Date")]
public DateTime BirthDate { get; set; }
}
}
================================================
FILE: src/Equinox.Domain/Commands/CustomerCommand.cs
================================================
using System;
using NetDevPack.Messaging;
namespace Equinox.Domain.Commands
{
public abstract class CustomerCommand : Command
{
public Guid Id { get; protected set; }
public string Name { get; protected set; }
public string Email { get; protected set; }
public DateTime BirthDate { get; protected set; }
}
}
================================================
FILE: src/Equinox.Domain/Commands/CustomerCommandHandler.cs
================================================
using System;
using System.Threading;
using System.Threading.Tasks;
using Equinox.Domain.Events;
using Equinox.Domain.Interfaces;
using Equinox.Domain.Models;
using FluentValidation.Results;
using NetDevPack.Messaging;
using NetDevPack.SimpleMediator.Core.Interfaces;
namespace Equinox.Domain.Commands
{
public class CustomerCommandHandler(ICustomerRepository customerRepository) : CommandHandler,
IRequestHandler<RegisterNewCustomerCommand, ValidationResult>,
IRequestHandler<UpdateCustomerCommand, ValidationResult>,
IRequestHandler<RemoveCustomerCommand, ValidationResult>
{
private readonly ICustomerRepository _customerRepository = customerRepository;
public async Task<ValidationResult> Handle(RegisterNewCustomerCommand message, CancellationToken cancellationToken)
{
if (!message.IsValid()) return message.ValidationResult;
var customer = new Customer(Guid.NewGuid(), message.Name, message.Email, message.BirthDate);
if (await _customerRepository.GetByEmail(customer.Email) != null)
{
AddError("The customer e-mail has already been taken.");
return ValidationResult;
}
customer.AddDomainEvent(new CustomerRegisteredEvent(customer.Id, customer.Name, customer.Email, customer.BirthDate));
_customerRepository.Add(customer);
return await Commit(_customerRepository.UnitOfWork);
}
public async Task<ValidationResult> Handle(UpdateCustomerCommand message, CancellationToken cancellationToken)
{
if (!message.IsValid()) return message.ValidationResult;
var customer = new Customer(message.Id, message.Name, message.Email, message.BirthDate);
var existingCustomer = await _customerRepository.GetByEmail(customer.Email);
if (existingCustomer != null && existingCustomer.Id != customer.Id)
{
if (!existingCustomer.Equals(customer))
{
AddError("The customer e-mail has already been taken.");
return ValidationResult;
}
}
customer.AddDomainEvent(new CustomerUpdatedEvent(customer.Id, customer.Name, customer.Email, customer.BirthDate));
_customerRepository.Update(customer);
return await Commit(_customerRepository.UnitOfWork);
}
public async Task<ValidationResult> Handle(RemoveCustomerCommand message, CancellationToken cancellationToken)
{
if (!message.IsValid()) return message.ValidationResult;
var customer = await _customerRepository.GetById(message.Id);
if (customer is null)
{
AddError("The customer doesn't exists.");
return ValidationResult;
}
customer.AddDomainEvent(new CustomerRemovedEvent(message.Id));
_customerRepository.Remove(customer);
return await Commit(_customerRepository.UnitOfWork);
}
public void Dispose()
{
_customerRepository.Dispose();
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/RegisterNewCustomerCommand.cs
================================================
using System;
using Equinox.Domain.Commands.Validations;
namespace Equinox.Domain.Commands
{
public class RegisterNewCustomerCommand : CustomerCommand
{
public RegisterNewCustomerCommand(string name, string email, DateTime birthDate)
{
Name = name;
Email = email;
BirthDate = birthDate;
}
public override bool IsValid()
{
ValidationResult = new RegisterNewCustomerCommandValidation().Validate(this);
return ValidationResult.IsValid;
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/RemoveCustomerCommand.cs
================================================
using System;
using Equinox.Domain.Commands.Validations;
namespace Equinox.Domain.Commands
{
public class RemoveCustomerCommand : CustomerCommand
{
public RemoveCustomerCommand(Guid id)
{
Id = id;
AggregateId = id;
}
public override bool IsValid()
{
ValidationResult = new RemoveCustomerCommandValidation().Validate(this);
return ValidationResult.IsValid;
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/UpdateCustomerCommand.cs
================================================
using System;
using Equinox.Domain.Commands.Validations;
namespace Equinox.Domain.Commands
{
public class UpdateCustomerCommand : CustomerCommand
{
public UpdateCustomerCommand(Guid id, string name, string email, DateTime birthDate)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
}
public override bool IsValid()
{
ValidationResult = new UpdateCustomerCommandValidation().Validate(this);
return ValidationResult.IsValid;
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/Validations/CustomerValidation.cs
================================================
using System;
using FluentValidation;
namespace Equinox.Domain.Commands.Validations
{
public abstract class CustomerValidation<T> : AbstractValidator<T> where T : CustomerCommand
{
protected void ValidateName()
{
RuleFor(c => c.Name)
.NotEmpty().WithMessage("Please ensure you have entered the Name")
.Length(2, 150).WithMessage("The Name must have between 2 and 150 characters");
}
protected void ValidateBirthDate()
{
RuleFor(c => c.BirthDate)
.NotEmpty()
.Must(HaveMinimumAge)
.WithMessage("The customer must have 18 years or more");
}
protected void ValidateEmail()
{
RuleFor(c => c.Email)
.NotEmpty()
.EmailAddress();
}
protected void ValidateId()
{
RuleFor(c => c.Id)
.NotEqual(Guid.Empty);
}
protected static bool HaveMinimumAge(DateTime birthDate)
{
return birthDate <= DateTime.Now.AddYears(-18);
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/Validations/RegisterNewCustomerCommandValidation.cs
================================================
namespace Equinox.Domain.Commands.Validations
{
public class RegisterNewCustomerCommandValidation : CustomerValidation<RegisterNewCustomerCommand>
{
public RegisterNewCustomerCommandValidation()
{
ValidateName();
ValidateBirthDate();
ValidateEmail();
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/Validations/RemoveCustomerCommandValidation.cs
================================================
namespace Equinox.Domain.Commands.Validations
{
public class RemoveCustomerCommandValidation : CustomerValidation<RemoveCustomerCommand>
{
public RemoveCustomerCommandValidation()
{
ValidateId();
}
}
}
================================================
FILE: src/Equinox.Domain/Commands/Validations/UpdateCustomerCommandValidation.cs
================================================
namespace Equinox.Domain.Commands.Validations
{
public class UpdateCustomerCommandValidation : CustomerValidation<UpdateCustomerCommand>
{
public UpdateCustomerCommandValidation()
{
ValidateId();
ValidateName();
ValidateBirthDate();
ValidateEmail();
}
}
}
================================================
FILE: src/Equinox.Domain/Equinox.Domain.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Domain.Core\Equinox.Domain.Core.csproj" />
<ProjectReference Include="..\Equinox.Infra.CrossCutting.Bus\Equinox.Infra.CrossCutting.Bus.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.11.0" />
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Domain/Events/CustomerEventHandler.cs
================================================
using NetDevPack.SimpleMediator.Core.Interfaces;
using System.Threading;
using System.Threading.Tasks;
namespace Equinox.Domain.Events
{
public class CustomerEventHandler :
INotificationHandler<CustomerRegisteredEvent>,
INotificationHandler<CustomerUpdatedEvent>,
INotificationHandler<CustomerRemovedEvent>
{
public Task Handle(CustomerUpdatedEvent message, CancellationToken cancellationToken)
{
// Send some notification e-mail
return Task.CompletedTask;
}
public Task Handle(CustomerRegisteredEvent message, CancellationToken cancellationToken)
{
// Send some greetings e-mail
return Task.CompletedTask;
}
public Task Handle(CustomerRemovedEvent message, CancellationToken cancellationToken)
{
// Send some see you soon e-mail
return Task.CompletedTask;
}
}
}
================================================
FILE: src/Equinox.Domain/Events/CustomerRegisteredEvent.cs
================================================
using System;
using NetDevPack.Messaging;
namespace Equinox.Domain.Events
{
public class CustomerRegisteredEvent : Event
{
public CustomerRegisteredEvent(Guid id, string name, string email, DateTime birthDate)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
AggregateId = id;
}
public Guid Id { get; set; }
public string Name { get; private set; }
public string Email { get; private set; }
public DateTime BirthDate { get; private set; }
}
}
================================================
FILE: src/Equinox.Domain/Events/CustomerRemovedEvent.cs
================================================
using System;
using NetDevPack.Messaging;
namespace Equinox.Domain.Events
{
public class CustomerRemovedEvent : Event
{
public CustomerRemovedEvent(Guid id)
{
Id = id;
AggregateId = id;
}
public Guid Id { get; set; }
}
}
================================================
FILE: src/Equinox.Domain/Events/CustomerUpdatedEvent.cs
================================================
using System;
using NetDevPack.Messaging;
namespace Equinox.Domain.Events
{
public class CustomerUpdatedEvent : Event
{
public CustomerUpdatedEvent(Guid id, string name, string email, DateTime birthDate)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
AggregateId = id;
}
public Guid Id { get; set; }
public string Name { get; private set; }
public string Email { get; private set; }
public DateTime BirthDate { get; private set; }
}
}
================================================
FILE: src/Equinox.Domain/Interfaces/ICustomerRepository.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Domain.Models;
using NetDevPack.Data;
namespace Equinox.Domain.Interfaces
{
public interface ICustomerRepository : IRepository<Customer>
{
Task<Customer> GetById(Guid id);
Task<Customer> GetByEmail(string email);
Task<IEnumerable<Customer>> GetAll();
void Add(Customer customer);
void Update(Customer customer);
void Remove(Customer customer);
}
}
================================================
FILE: src/Equinox.Domain/Models/Customer.cs
================================================
using System;
using NetDevPack.Domain;
namespace Equinox.Domain.Models
{
public class Customer : Entity, IAggregateRoot
{
public Customer(Guid id, string name, string email, DateTime birthDate)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
}
// Empty constructor for EF
protected Customer() { }
public string Name { get; private set; }
public string Email { get; private set; }
public DateTime BirthDate { get; private set; }
}
}
================================================
FILE: src/Equinox.Domain.Core/Equinox.Domain.Core.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NetDevPack" Version="8.0.2" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Domain.Core/Events/IEventStore.cs
================================================
using NetDevPack.Messaging;
namespace Equinox.Domain.Core.Events
{
public interface IEventStore
{
void Save<T>(T theEvent) where T : Event;
}
}
================================================
FILE: src/Equinox.Domain.Core/Events/StoredEvent.cs
================================================
using System;
using NetDevPack.Messaging;
namespace Equinox.Domain.Core.Events
{
public class StoredEvent : Event
{
public StoredEvent(Event theEvent, string data, string user)
{
Id = Guid.NewGuid();
AggregateId = theEvent.AggregateId;
MessageType = theEvent.MessageType;
Data = data;
User = user;
}
// EF Constructor
protected StoredEvent() { }
public Guid Id { get; private set; }
public string Data { get; private set; }
public string User { get; private set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Bus/Equinox.Infra.CrossCutting.Bus.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Domain.Core\Equinox.Domain.Core.csproj" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Infra.CrossCutting.Bus/InMemoryBus.cs
================================================
using System.Threading.Tasks;
using Equinox.Domain.Core.Events;
using FluentValidation.Results;
using NetDevPack.Mediator;
using NetDevPack.Messaging;
using NetDevPack.SimpleMediator.Core.Interfaces;
namespace Equinox.Infra.CrossCutting.Bus
{
public sealed class InMemoryBus(IEventStore eventStore, IMediator mediator) : IMediatorHandler
{
private readonly IMediator _mediator = mediator;
private readonly IEventStore _eventStore = eventStore;
public async Task PublishEvent<T>(T @event) where T : Event
{
if (!@event.MessageType.Equals("DomainNotification"))
_eventStore?.Save(@event);
await _mediator.Publish(@event);
}
public async Task<ValidationResult> SendCommand<T>(T command) where T : Command
{
return await _mediator.Send(command);
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/API/AppJwtSettings.cs
================================================
namespace Equinox.Infra.CrossCutting.Identity.API
{
public class AppJwtSettings
{
public string SecretKey { get; set; }
public int Expiration { get; set; } = 1;
public string Issuer { get; set; } = "Equinox.Api";
public string Audience { get; set; } = "Api";
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/API/JwtBuilder.cs
================================================
using Equinox.Infra.CrossCutting.Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
namespace Equinox.Infra.CrossCutting.Identity.API
{
public class JwtBuilder<TIdentityUser, TKey> where TIdentityUser : IdentityUser<TKey> where TKey : IEquatable<TKey>
{
private UserManager<TIdentityUser> _userManager;
private AppJwtSettings _appJwtSettings;
private TIdentityUser _user;
private ICollection<Claim> _userClaims;
private ICollection<Claim> _jwtClaims;
private ClaimsIdentity _identityClaims;
public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TIdentityUser> userManager)
{
_userManager = userManager ?? throw new ArgumentException(nameof(userManager));
return this;
}
public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings appJwtSettings)
{
_appJwtSettings = appJwtSettings ?? throw new ArgumentException(nameof(appJwtSettings));
return this;
}
public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
{
if (string.IsNullOrEmpty(email)) throw new ArgumentException(nameof(email));
_user = _userManager.FindByEmailAsync(email).Result;
_userClaims = new List<Claim>();
_jwtClaims = new List<Claim>();
_identityClaims = new ClaimsIdentity();
return this;
}
public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
{
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Sub, _user.Id.ToString()));
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Email, _user.Email));
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Nbf, ToUnixEpochDate(DateTime.UtcNow).ToString()));
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(DateTime.UtcNow).ToString(), ClaimValueTypes.Integer64));
_identityClaims.AddClaims(_jwtClaims);
return this;
}
public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
{
_userClaims = _userManager.GetClaimsAsync(_user).Result;
_identityClaims.AddClaims(_userClaims);
return this;
}
public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
{
var userRoles = _userManager.GetRolesAsync(_user).Result;
userRoles.ToList().ForEach(r => _identityClaims.AddClaim(new Claim("role", r)));
return this;
}
public string BuildToken()
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appJwtSettings.SecretKey);
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
{
Issuer = _appJwtSettings.Issuer,
Audience = _appJwtSettings.Audience,
Subject = _identityClaims,
Expires = DateTime.UtcNow.AddHours(_appJwtSettings.Expiration),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
});
return tokenHandler.WriteToken(token);
}
public UserResponse BuildUserResponse()
{
var user = new UserResponse
{
AccessToken = BuildToken(),
ExpiresIn = TimeSpan.FromHours(_appJwtSettings.Expiration).TotalSeconds,
UserToken = new UserToken
{
Id = _user.Id,
Email = _user.Email,
Claims = _userClaims.Select(c => new UserClaim { Type = c.Type, Value = c.Value })
}
};
return user;
}
private static long ToUnixEpochDate(DateTime date)
=> (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
.TotalSeconds);
}
public class JwtBuilder<TIdentityUser> : JwtBuilder<TIdentityUser, string> where TIdentityUser : IdentityUser<string> { }
public sealed class JwtBuilder : JwtBuilder<IdentityUser> { }
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizationValidation.cs
================================================
using System.Linq;
using Microsoft.AspNetCore.Http;
namespace Equinox.Infra.CrossCutting.Identity.Authorization
{
public static class CustomAuthorizationValidation
{
public static bool UserHasValidClaim(HttpContext context, string claimName, string claimValue)
{
return context.User.Identity.IsAuthenticated &&
context.User.Claims.Any(c =>
c.Type == claimName &&
c.Value.Split(',').Select(v => v.Trim()).Contains(claimValue));
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizeAttribute.cs
================================================
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
namespace Equinox.Infra.CrossCutting.Identity.Authorization
{
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
public CustomAuthorizeAttribute(string claimName, string claimValue) : base(typeof(RequerimentClaimFilter))
{
Arguments = new object[] { new Claim(claimName, claimValue) };
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/RequerimentClaimFilter.cs
================================================
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Equinox.Infra.CrossCutting.Identity.Authorization
{
internal class RequerimentClaimFilter : IAuthorizationFilter
{
private readonly Claim _claim;
public RequerimentClaimFilter(Claim claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new StatusCodeResult(401);
return;
}
if (!CustomAuthorizationValidation.UserHasValidClaim(context.HttpContext, _claim.Type, _claim.Value))
{
context.Result = new StatusCodeResult(403);
}
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Configuration/AspNetIdentityConfig.cs
================================================
using Equinox.Infra.CrossCutting.Identity.API;
using Equinox.Infra.CrossCutting.Identity.Data;
using Equinox.Infra.CrossCutting.Identity.User;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;
namespace Equinox.Infra.CrossCutting.Identity.Configuration
{
public static class AspNetIdentityConfig
{
public static WebApplicationBuilder AddApiIdentityConfiguration(this WebApplicationBuilder builder)
{
builder.AddIdentityDbContext()
.AddIdentityApiSupport()
.AddJwtSupport()
.AddAspNetUserSupport();
return builder;
}
public static WebApplicationBuilder AddWebIdentityConfiguration(this WebApplicationBuilder builder)
{
builder.AddIdentityDbContext()
.AddIdentityWebUISupport()
.AddAspNetUserSupport()
.AddSocialAuthenticationSupport();
return builder;
}
private static WebApplicationBuilder AddIdentityDbContext(this WebApplicationBuilder builder)
{
if (builder.Environment.IsDevelopment())
{
builder.Services.AddDbContext<EquinoxIdentityContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
return builder;
}
builder.Services.AddDbContext<EquinoxIdentityContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
return builder;
}
private static WebApplicationBuilder AddIdentityApiSupport(this WebApplicationBuilder builder)
{
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<EquinoxIdentityContext>()
.AddSignInManager()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultTokenProviders();
return builder;
}
private static WebApplicationBuilder AddIdentityWebUISupport(this WebApplicationBuilder builder)
{
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<EquinoxIdentityContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
return builder;
}
private static WebApplicationBuilder AddJwtSupport(this WebApplicationBuilder builder)
{
var appSettingsSection = builder.Configuration.GetSection("AppSettings");
builder.Services.Configure<AppJwtSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppJwtSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.SecretKey);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = true;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = appSettings.Audience,
ValidIssuer = appSettings.Issuer
};
});
return builder;
}
public static WebApplicationBuilder AddAspNetUserSupport(this WebApplicationBuilder builder)
{
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IAspNetUser, AspNetUser>();
return builder;
}
public static WebApplicationBuilder AddSocialAuthenticationSupport(this WebApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
builder.Services.AddAuthentication()
.AddFacebook(o =>
{
o.AppId = builder.Configuration["Authentication:Facebook:AppId"];
o.AppSecret = builder.Configuration["Authentication:Facebook:AppSecret"];
})
.AddGoogle(googleOptions =>
{
googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"];
googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
});
return builder;
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Data/EquinoxIdentityContext.cs
================================================
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;
using System;
namespace Equinox.Infra.CrossCutting.Identity.Data
{
public class EquinoxIdentityContext : IdentityDbContext
{
public EquinoxIdentityContext(DbContextOptions<EquinoxIdentityContext> options) : base(options) { }
}
public class EquinoxIdentityContextFactory : IDesignTimeDbContextFactory<EquinoxIdentityContext>
{
public EquinoxIdentityContext CreateDbContext(string[] args)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development";
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.AddJsonFile($"appsettings.{environment}.json", optional: true)
.Build();
var builder = new DbContextOptionsBuilder<EquinoxIdentityContext>();
var connectionString = configuration.GetConnectionString("DefaultConnection");
if (environment == "Development")
{
builder.UseSqlite(connectionString);
}
else
{
builder.UseSqlServer(connectionString);
}
return new EquinoxIdentityContext(builder.Options);
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Equinox.Infra.CrossCutting.Identity.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.13.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Extensions/ClaimsPrincipalExtensions.cs
================================================
using System.Security.Claims;
using System;
using System.IdentityModel.Tokens.Jwt;
namespace Equinox.Infra.CrossCutting.Identity.Extensions
{
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentException(nameof(principal));
}
var claim = principal.FindFirst(JwtRegisteredClaimNames.Sub);
if (claim is null)
claim = principal.FindFirst(ClaimTypes.NameIdentifier);
return claim?.Value;
}
public static string GetUserEmail(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentException(nameof(principal));
}
var claim = principal.FindFirst(JwtRegisteredClaimNames.Sub);
if (claim is null)
claim = principal.FindFirst(ClaimTypes.Email);
return claim?.Value;
}
public static string GetUserId(this ClaimsIdentity principal)
{
if (principal == null)
{
throw new ArgumentException(nameof(principal));
}
var claim = principal.FindFirst(JwtRegisteredClaimNames.Sub);
if (claim is null)
claim = principal.FindFirst(ClaimTypes.NameIdentifier);
return claim?.Value;
}
public static string GetUserEmail(this ClaimsIdentity principal)
{
if (principal == null)
{
throw new ArgumentException(nameof(principal));
}
var claim = principal.FindFirst(JwtRegisteredClaimNames.Sub);
if (claim is null)
claim = principal.FindFirst(ClaimTypes.Email);
return claim?.Value;
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.Designer.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.CrossCutting.Identity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.CrossCutting.Identity.Migrations
{
[DbContext(typeof(EquinoxIdentityContext))]
[Migration("20250408033115_SQLite")]
partial class SQLite
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Equinox.Infra.CrossCutting.Identity.Migrations
{
/// <inheritdoc />
public partial class SQLite : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
UserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
PasswordHash = table.Column<string>(type: "TEXT", nullable: true),
SecurityStamp = table.Column<string>(type: "TEXT", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "TEXT", nullable: true),
LockoutEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
AccessFailedCount = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
RoleId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
UserId = table.Column<string>(type: "TEXT", nullable: false),
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
ProviderKey = table.Column<string>(type: "TEXT", nullable: false),
ProviderDisplayName = table.Column<string>(type: "TEXT", nullable: true),
UserId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
RoleId = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "TEXT", nullable: false),
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: false),
Value = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/EquinoxIdentityContextModelSnapshot.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.CrossCutting.Identity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.CrossCutting.Identity.Migrations
{
[DbContext(typeof(EquinoxIdentityContext))]
partial class EquinoxIdentityContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/LoginUser.cs
================================================
using System.ComponentModel.DataAnnotations;
namespace Equinox.Infra.CrossCutting.Identity.Models
{
public class LoginUser
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(100, MinimumLength = 6)]
public string Password { get; set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/RegisterUser.cs
================================================
using System.ComponentModel.DataAnnotations;
namespace Equinox.Infra.CrossCutting.Identity.Models
{
public class RegisterUser
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(100, MinimumLength = 6)]
public string Password { get; set; }
[Compare("Password")]
public string ConfirmPassword { get; set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserClaim.cs
================================================
namespace Equinox.Infra.CrossCutting.Identity.Models
{
public class UserClaim
{
public string Value { get; set; }
public string Type { get; set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserResponse.cs
================================================
namespace Equinox.Infra.CrossCutting.Identity.Models
{
public class UserResponse
{
public string AccessToken { get; set; }
public double ExpiresIn { get; set; }
public UserToken UserToken { get; set; }
public string RefreshToken { get; set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserToken.cs
================================================
using System.Collections.Generic;
namespace Equinox.Infra.CrossCutting.Identity.Models
{
public class UserToken
{
public dynamic Id { get; set; }
public string Email { get; set; }
public IEnumerable<UserClaim> Claims { get; set; }
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/User/AspNetUser.cs
================================================
using System;
using System.Collections.Generic;
using System.Security.Claims;
using Equinox.Infra.CrossCutting.Identity.Extensions;
using Microsoft.AspNetCore.Http;
namespace Equinox.Infra.CrossCutting.Identity.User
{
public class AspNetUser : IAspNetUser
{
private readonly IHttpContextAccessor _accessor;
public AspNetUser(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public string Name => _accessor.HttpContext.User.Identity.Name;
public Guid GetUserId()
{
return IsAuthenticated() ? Guid.Parse(_accessor.HttpContext.User.GetUserId()) : Guid.Empty;
}
public string GetUserEmail()
{
return IsAuthenticated() ? _accessor.HttpContext.User.GetUserEmail() : "";
}
public bool IsAuthenticated()
{
return _accessor.HttpContext.User.Identity.IsAuthenticated;
}
public bool IsInRole(string role)
{
return _accessor.HttpContext.User.IsInRole(role);
}
public IEnumerable<Claim> GetUserClaims()
{
return _accessor.HttpContext.User.Claims;
}
public HttpContext GetHttpContext()
{
return _accessor.HttpContext;
}
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.Identity/User/IAspNetUser.cs
================================================
using System;
using System.Collections.Generic;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
namespace Equinox.Infra.CrossCutting.Identity.User
{
public interface IAspNetUser
{
string Name { get; }
Guid GetUserId();
string GetUserEmail();
bool IsAuthenticated();
bool IsInRole(string role);
IEnumerable<Claim> GetUserClaims();
HttpContext GetHttpContext();
}
}
================================================
FILE: src/Equinox.Infra.CrossCutting.IoC/Equinox.Infra.CrossCutting.IoC.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Application\Equinox.Application.csproj" />
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj" />
<ProjectReference Include="..\Equinox.Infra.Data\Equinox.Infra.Data.csproj" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Infra.CrossCutting.IoC/NativeInjectorBootStrapper.cs
================================================
using Equinox.Application.Interfaces;
using Equinox.Application.Services;
using Equinox.Domain.Commands;
using Equinox.Domain.Core.Events;
using Equinox.Domain.Events;
using Equinox.Domain.Interfaces;
using Equinox.Infra.CrossCutting.Bus;
using Equinox.Infra.Data.Context;
using Equinox.Infra.Data.EventSourcing;
using Equinox.Infra.Data.Repository;
using Equinox.Infra.Data.Repository.EventSourcing;
using FluentValidation.Results;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using NetDevPack.Mediator;
using NetDevPack.SimpleMediator.Core.Implementation;
using NetDevPack.SimpleMediator.Core.Interfaces;
namespace Equinox.Infra.CrossCutting.IoC
{
public static class NativeInjectorBootStrapper
{
public static void RegisterServices(WebApplicationBuilder builder)
{
// Domain Bus (Mediator)
builder.Services.AddScoped<IMediator, Mediator>();
builder.Services.AddScoped<IMediatorHandler, InMemoryBus>();
// Application
builder.Services.AddScoped<ICustomerAppService, CustomerAppService>();
// Domain - Events
builder.Services.AddScoped<INotificationHandler<CustomerRegisteredEvent>, CustomerEventHandler>();
builder.Services.AddScoped<INotificationHandler<CustomerUpdatedEvent>, CustomerEventHandler>();
builder.Services.AddScoped<INotificationHandler<CustomerRemovedEvent>, CustomerEventHandler>();
// Domain - Commands
builder.Services.AddScoped<IRequestHandler<RegisterNewCustomerCommand, ValidationResult>, CustomerCommandHandler>();
builder.Services.AddScoped<IRequestHandler<UpdateCustomerCommand, ValidationResult>, CustomerCommandHandler>();
builder.Services.AddScoped<IRequestHandler<RemoveCustomerCommand, ValidationResult>, CustomerCommandHandler>();
// Infra - Data
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
builder.Services.AddScoped<EquinoxContext>();
// Infra - Data EventSourcing
builder.Services.AddScoped<IEventStoreRepository, EventStoreSqlRepository>();
builder.Services.AddScoped<IEventStore, SqlEventStore>();
builder.Services.AddScoped<EventStoreSqlContext>();
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Context/EquinoxContext.cs
================================================
using System.Linq;
using System.Threading.Tasks;
using Equinox.Domain.Models;
using Equinox.Infra.Data.Mappings;
using FluentValidation.Results;
using Microsoft.EntityFrameworkCore;
using NetDevPack.Data;
using NetDevPack.Domain;
using NetDevPack.Mediator;
using NetDevPack.Messaging;
namespace Equinox.Infra.Data.Context
{
public sealed class EquinoxContext : DbContext, IUnitOfWork
{
private readonly IMediatorHandler _mediatorHandler;
public EquinoxContext(DbContextOptions<EquinoxContext> options, IMediatorHandler mediatorHandler) : base(options)
{
_mediatorHandler = mediatorHandler;
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
ChangeTracker.AutoDetectChangesEnabled = false;
}
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<ValidationResult>();
modelBuilder.Ignore<Event>();
foreach (var property in modelBuilder.Model.GetEntityTypes().SelectMany(
e => e.GetProperties().Where(p => p.ClrType == typeof(string))))
property.SetColumnType("varchar(100)");
modelBuilder.ApplyConfiguration(new CustomerMap());
base.OnModelCreating(modelBuilder);
}
public async Task<bool> Commit()
{
// Dispatch Domain Events collection.
// Choices:
// A) Right BEFORE committing data (EF SaveChanges) into the DB will make a single transaction including
// side effects from the domain event handlers which are using the same DbContext with "InstancePerLifetimeScope" or "scoped" lifetime
// B) Right AFTER committing data (EF SaveChanges) into the DB will make multiple transactions.
// You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers.
await _mediatorHandler.PublishDomainEvents(this).ConfigureAwait(false);
// After executing this line all the changes (from the Command Handler and Domain Event Handlers)
// performed through the DbContext will be committed
var success = await SaveChangesAsync() > 0;
return success;
}
}
public static class MediatorExtension
{
public static async Task PublishDomainEvents<T>(this IMediatorHandler mediator, T ctx) where T : DbContext
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());
var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList();
domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents());
var tasks = domainEvents
.Select(async (domainEvent) => {
await mediator.PublishEvent(domainEvent);
});
await Task.WhenAll(tasks);
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Context/EventStoreSQLContext.cs
================================================
using Equinox.Domain.Core.Events;
using Equinox.Infra.Data.Mappings;
using Microsoft.EntityFrameworkCore;
namespace Equinox.Infra.Data.Context
{
public class EventStoreSqlContext : DbContext
{
public EventStoreSqlContext(DbContextOptions<EventStoreSqlContext> options) : base(options) { }
public DbSet<StoredEvent> StoredEvent { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new StoredEventMap());
base.OnModelCreating(modelBuilder);
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Equinox.Infra.Data.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj" />
<ProjectReference Include="..\Equinox.Infra.CrossCutting.Identity\Equinox.Infra.CrossCutting.Identity.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.13.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Formats.Asn1" Version="9.0.3" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.3" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project>
================================================
FILE: src/Equinox.Infra.Data/EventSourcing/SqlEventStore.cs
================================================
using Equinox.Domain.Core.Events;
using Equinox.Infra.CrossCutting.Identity.User;
using Equinox.Infra.Data.Repository.EventSourcing;
using NetDevPack.Messaging;
using Newtonsoft.Json;
namespace Equinox.Infra.Data.EventSourcing
{
public class SqlEventStore : IEventStore
{
private readonly IEventStoreRepository _eventStoreRepository;
private readonly IAspNetUser _user;
public SqlEventStore(IEventStoreRepository eventStoreRepository, IAspNetUser user)
{
_eventStoreRepository = eventStoreRepository;
_user = user;
}
public void Save<T>(T theEvent) where T : Event
{
// Using Newtonsoft.Json because System.Text.Json
// is a sad joke to be considered "Done"
// The System.Text don't know how serialize a
// object with inherited properties, I said is sad...
// Yes! I tried: options = new JsonSerializerOptions { WriteIndented = true };
var serializedData = JsonConvert.SerializeObject(theEvent);
var storedEvent = new StoredEvent(
theEvent,
serializedData,
_user.Name ?? _user.GetUserEmail());
_eventStoreRepository.Store(storedEvent);
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Mappings/CustomerMap.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Equinox.Domain.Models;
namespace Equinox.Infra.Data.Mappings
{
public class CustomerMap : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.Property(c => c.Id)
.HasColumnName("Id");
builder.Property(c => c.Name)
.HasColumnType("varchar(100)")
.HasMaxLength(100)
.IsRequired();
builder.Property(c => c.Email)
.HasColumnType("varchar(100)")
.HasMaxLength(100)
.IsRequired();
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Mappings/StoredEventMap.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Equinox.Domain.Core.Events;
namespace Equinox.Infra.Data.Mappings
{
public class StoredEventMap : IEntityTypeConfiguration<StoredEvent>
{
public void Configure(EntityTypeBuilder<StoredEvent> builder)
{
builder.Property(c => c.Timestamp)
.HasColumnName("CreationDate");
builder.Property(c => c.MessageType)
.HasColumnName("Action")
.HasColumnType("varchar(100)");
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.Designer.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.Data.Migrations
{
[DbContext(typeof(EquinoxContext))]
[Migration("20250408031104_SQLite")]
partial class SQLite
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Equinox.Domain.Models.Customer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
.HasColumnName("Id");
b.Property<DateTime>("BirthDate")
.HasColumnType("TEXT");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.HasKey("Id");
b.ToTable("Customers");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Equinox.Infra.Data.Migrations
{
/// <inheritdoc />
public partial class SQLite : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Customers",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: false),
Email = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: false),
BirthDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Customers", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Customers");
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/EquinoxContextModelSnapshot.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.Data.Migrations
{
[DbContext(typeof(EquinoxContext))]
partial class EquinoxContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Equinox.Domain.Models.Customer", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT")
.HasColumnName("Id");
b.Property<DateTime>("BirthDate")
.HasColumnType("TEXT");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.HasKey("Id");
b.ToTable("Customers");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSQL/EventStoreSQLContextModelSnapshot.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.Data.Migrations.EventStoreSql
{
[DbContext(typeof(EventStoreSqlContext))]
partial class EventStoreSqlContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Equinox.Domain.Core.Events.StoredEvent", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("AggregateId")
.HasColumnType("TEXT");
b.Property<string>("Data")
.HasColumnType("TEXT");
b.Property<string>("MessageType")
.HasColumnType("varchar(100)")
.HasColumnName("Action");
b.Property<DateTime>("Timestamp")
.HasColumnType("TEXT")
.HasColumnName("CreationDate");
b.Property<string>("User")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("StoredEvent");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.Designer.cs
================================================
// <auto-generated />
using System;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Equinox.Infra.Data.Migrations.EventStoreSql
{
[DbContext(typeof(EventStoreSqlContext))]
[Migration("20250408031128_SQLite")]
partial class SQLite
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.3");
modelBuilder.Entity("Equinox.Domain.Core.Events.StoredEvent", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid>("AggregateId")
.HasColumnType("TEXT");
b.Property<string>("Data")
.HasColumnType("TEXT");
b.Property<string>("MessageType")
.HasColumnType("varchar(100)")
.HasColumnName("Action");
b.Property<DateTime>("Timestamp")
.HasColumnType("TEXT")
.HasColumnName("CreationDate");
b.Property<string>("User")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("StoredEvent");
});
#pragma warning restore 612, 618
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Equinox.Infra.Data.Migrations.EventStoreSql
{
/// <inheritdoc />
public partial class SQLite : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "StoredEvent",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Data = table.Column<string>(type: "TEXT", nullable: true),
User = table.Column<string>(type: "TEXT", nullable: true),
Action = table.Column<string>(type: "varchar(100)", nullable: true),
AggregateId = table.Column<Guid>(type: "TEXT", nullable: false),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_StoredEvent", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "StoredEvent");
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Repository/CustomerRepository.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Domain.Interfaces;
using Equinox.Domain.Models;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using NetDevPack.Data;
namespace Equinox.Infra.Data.Repository
{
public class CustomerRepository : ICustomerRepository
{
protected readonly EquinoxContext Db;
protected readonly DbSet<Customer> DbSet;
public CustomerRepository(EquinoxContext context)
{
Db = context;
DbSet = Db.Set<Customer>();
}
public IUnitOfWork UnitOfWork => Db;
public async Task<Customer> GetById(Guid id)
{
return await DbSet.FindAsync(id);
}
public async Task<IEnumerable<Customer>> GetAll()
{
return await DbSet.ToListAsync();
}
public async Task<Customer> GetByEmail(string email)
{
return await DbSet.AsNoTracking().FirstOrDefaultAsync(c => c.Email == email);
}
public void Add(Customer customer)
{
DbSet.Add(customer);
}
public void Update(Customer customer)
{
DbSet.Update(customer);
}
public void Remove(Customer customer)
{
DbSet.Remove(customer);
}
public void Dispose()
{
Db.Dispose();
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Repository/EventSourcing/EventStoreSQLRepository.cs
================================================
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Domain.Core.Events;
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
namespace Equinox.Infra.Data.Repository.EventSourcing
{
public class EventStoreSqlRepository : IEventStoreRepository
{
private readonly EventStoreSqlContext _context;
public EventStoreSqlRepository(EventStoreSqlContext context)
{
_context = context;
}
public async Task<IList<StoredEvent>> All(Guid aggregateId)
{
return await (from e in _context.StoredEvent where e.AggregateId == aggregateId select e).ToListAsync();
}
public void Store(StoredEvent theEvent)
{
_context.StoredEvent.Add(theEvent);
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
}
================================================
FILE: src/Equinox.Infra.Data/Repository/EventSourcing/IEventStoreRepository.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Equinox.Domain.Core.Events;
namespace Equinox.Infra.Data.Repository.EventSourcing
{
public interface IEventStoreRepository : IDisposable
{
void Store(StoredEvent theEvent);
Task<IList<StoredEvent>> All(Guid aggregateId);
}
}
================================================
FILE: src/Equinox.Infra.Data/appsettings.json
================================================
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=Equinox;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: src/Equinox.Services.Api/Configurations/ApiConfig.cs
================================================
namespace Equinox.Services.Api.Configurations
{
public static class ApiConfig
{
public static WebApplicationBuilder AddApiConfiguration(this WebApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
builder.Configuration
.SetBasePath(builder.Environment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true)
.AddEnvironmentVariables();
builder.Services.AddControllers();
return builder;
}
}
}
================================================
FILE: src/Equinox.Services.Api/Configurations/DatabaseConfig.cs
================================================
using Equinox.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
namespace Equinox.Services.Api.Configurations
{
public static class DatabaseConfig
{
public static WebApplicationBuilder AddDatabaseConfiguration(this WebApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
builder.Services.AddDbContext<EquinoxContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddDbContext<EventStoreSqlContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
return builder;
}
}
}
================================================
FILE: src/Equinox.Services.Api/Configurations/DependencyInjectionConfig.cs
================================================
using Equinox.Infra.CrossCutting.IoC;
namespace Equinox.Services.Api.Configurations
{
public static class DependencyInjectionConfig
{
public static WebApplicationBuilder AddDependencyInjectionConfiguration(this WebApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
NativeInjectorBootStrapper.RegisterServices(builder);
return builder;
}
}
}
================================================
FILE: src/Equinox.Services.Api/Configurations/SwaggerConfig.cs
================================================
using Microsoft.OpenApi.Models;
namespace Equinox.Services.Api.Configurations
{
public static class SwaggerConfig
{
public static WebApplicationBuilder AddSwaggerConfiguration(this WebApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(s =>
{
s.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "Equinox Project",
Description = "Equinox API Swagger surface",
Contact = new OpenApiContact { Name = "Eduardo Pires", Email = "contato@eduardopires.net.br", Url = new Uri("http://www.eduardopires.net.br") },
License = new OpenApiLicense { Name = "MIT", Url = new Uri("https://github.com/EduardoPires/EquinoxProject/blob/master/LICENSE") }
});
s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "Input the JWT like: Bearer {your token}",
Name = "Authorization",
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
s.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
// Excluding ASP.NET Identity endpoints
s.DocInclusionPredicate((docName, apiDesc) =>
{
var relativePath = apiDesc.RelativePath;
// List of avoid patches
var identityEndpoints = new[]
{
"register",
"manage",
"refresh",
"login",
"confirmEmail",
"resendConfirmationEmail",
"forgotPassword",
"resetPassword"
};
// Validating if the endpoint is avoided
foreach (var endpoint in identityEndpoints)
{
if (relativePath.Contains(endpoint, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
return true;
});
});
return builder;
}
public static IApplicationBuilder UseSwaggerSetup(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});
return app;
}
}
}
================================================
FILE: src/Equinox.Services.Api/Controllers/AccountController.cs
================================================
using Equinox.Infra.CrossCutting.Identity.API;
using Equinox.Infra.CrossCutting.Identity.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Equinox.Services.Api.Controllers
{
[Route("account")]
[ApiController]
public class AccountController : ApiController
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly AppJwtSettings _appJwtSettings;
public AccountController(
SignInManager<IdentityUser> signInManager,
UserManager<IdentityUser> userManager,
IOptions<AppJwtSettings> appJwtSettings)
{
_userManager = userManager;
_signInManager = signInManager;
_appJwtSettings = appJwtSettings.Value;
}
[HttpPost]
[Route("new")]
public async Task<ActionResult> Register(RegisterUser registerUser)
{
if (!ModelState.IsValid) return CustomResponse(ModelState);
var user = new IdentityUser
{
UserName = registerUser.Email,
Email = registerUser.Email,
EmailConfirmed = true
};
var result = await _userManager.CreateAsync(user, registerUser.Password);
if (result.Succeeded)
{
return CustomResponse(GetFullJwt(user.Email));
}
foreach (var error in result.Errors)
{
AddError(error.Description);
}
return CustomResponse();
}
[HttpPost]
[Route("enter")]
public async Task<IActionResult> Login(LoginUser loginUser)
{
if (!ModelState.IsValid) return CustomResponse(ModelState);
var result = await _signInManager.PasswordSignInAsync(loginUser.Email, loginUser.Password, false, true);
if (result.Succeeded)
{
var fullJwt = GetFullJwt(loginUser.Email);
return CustomResponse(fullJwt);
}
if (result.IsLockedOut)
{
AddError("This user is temporarily blocked");
return CustomResponse();
}
AddError("Incorrect user or password");
return CustomResponse();
}
private string GetFullJwt(string email)
{
return new JwtBuilder()
.WithUserManager(_userManager)
.WithJwtSettings(_appJwtSettings)
.WithEmail(email)
.WithJwtClaims()
.WithUserClaims()
.WithUserRoles()
.BuildToken();
}
}
}
================================================
FILE: src/Equinox.Services.Api/Controllers/ApiController.cs
================================================
using FluentValidation.Results;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Equinox.Services.Api.Controllers
{
[ApiController]
public abstract class ApiController : ControllerBase
{
private readonly ICollection<string> _errors = new List<string>();
protected ActionResult CustomResponse(object result = null)
{
if (IsOperationValid())
{
return Ok(result);
}
return BadRequest(new ValidationProblemDetails(new Dictionary<string, string[]>
{
{ "Messages", _errors.ToArray() }
}));
}
protected ActionResult CustomResponse(ModelStateDictionary modelState)
{
var errors = modelState.Values.SelectMany(e => e.Errors);
foreach (var error in errors)
{
AddError(error.ErrorMessage);
}
return CustomResponse();
}
protected ActionResult CustomResponse(ValidationResult validationResult)
{
foreach (var error in validationResult.Errors)
{
AddError(error.ErrorMessage);
}
return CustomResponse();
}
protected bool IsOperationValid()
{
return !_errors.Any();
}
protected void AddError(string erro)
{
_errors.Add(erro);
}
protected void ClearErrors()
{
_errors.Clear();
}
}
}
================================================
FILE: src/Equinox.Services.Api/Controllers/CustomerController.cs
================================================
using Equinox.Application.EventSourcedNormalizers;
using Equinox.Application.Interfaces;
using Equinox.Application.ViewModels;
using Equinox.Infra.CrossCutting.Identity.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Equinox.Services.Api.Controllers
{
[Authorize]
public class CustomerController : ApiController
{
private readonly ICustomerAppService _customerAppService;
public CustomerController(ICustomerAppService customerAppService)
{
_customerAppService = customerAppService;
}
[AllowAnonymous]
[HttpGet("customer")]
public async Task<IEnumerable<CustomerViewModel>> Get()
{
return await _customerAppService.GetAll();
}
[AllowAnonymous]
[HttpGet("customer/{id:guid}")]
public async Task<CustomerViewModel> Get(Guid id)
{
return await _customerAppService.GetById(id);
}
[CustomAuthorize("Customers", "Write")]
[HttpPost("customer")]
public async Task<IActionResult> Post([FromBody]CustomerViewModel customerViewModel)
{
return !ModelState.IsValid ? CustomResponse(ModelState) : CustomResponse(await _customerAppService.Register(customerViewModel));
}
[CustomAuthorize("Customers", "Write")]
[HttpPut("customer")]
public async Task<IActionResult> Put([FromBody]CustomerViewModel customerViewModel)
{
return !ModelState.IsValid ? CustomResponse(ModelState) : CustomResponse(await _customerAppService.Update(customerViewModel));
}
[CustomAuthorize("Customers", "Remove")]
[HttpDelete("customer")]
public async Task<IActionResult> Delete(Guid id)
{
return CustomResponse(await _customerAppService.Remove(id));
}
[AllowAnonymous]
[HttpGet("customer/history/{id:guid}")]
public async Task<IList<CustomerHistoryData>> History(Guid id)
{
return await _customerAppService.GetAllHistory(id);
}
}
}
================================================
FILE: src/Equinox.Services.Api/Dockerfile
================================================
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["src/Equinox.Services.Api/Equinox.Services.Api.csproj", "src/Equinox.Services.Api/"]
RUN dotnet restore "src/Equinox.Services.Api/Equinox.Services.Api.csproj"
COPY . .
WORKDIR "/src/src/Equinox.Services.Api"
RUN dotnet build "Equinox.Services.Api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Equinox.Services.Api.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Equinox.Services.Api.dll"]
================================================
FILE: src/Equinox.Services.Api/Equinox.Services.Api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>disable</Nullable>
<UserSecretsId>b543be42-f7ab-48b6-b633-72d6fb529fb7</UserSecretsId>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="8.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="8.1.0"
gitextract_ug6sjdzw/
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── custom.md
│ │ └── feature_request.md
│ └── workflows/
│ └── dotnet-core.yml
├── .gitignore
├── AGENTS.md
├── Equinox.sln
├── LICENSE
├── README.md
├── docs/
│ ├── Architecture.dgml
│ ├── _config.yml
│ └── index.md
├── sql/
│ └── GenerateDataBase.sql
├── src/
│ ├── Equinox.Application/
│ │ ├── Equinox.Application.csproj
│ │ ├── EventSourcedNormalizers/
│ │ │ ├── CustomerHistory.cs
│ │ │ └── CustomerHistoryData.cs
│ │ ├── Extensions/
│ │ │ └── CustomerExtensions.cs
│ │ ├── Interfaces/
│ │ │ └── ICustomerAppService.cs
│ │ ├── Services/
│ │ │ └── CustomerAppService.cs
│ │ └── ViewModels/
│ │ └── CustomerViewModel.cs
│ ├── Equinox.Domain/
│ │ ├── Commands/
│ │ │ ├── CustomerCommand.cs
│ │ │ ├── CustomerCommandHandler.cs
│ │ │ ├── RegisterNewCustomerCommand.cs
│ │ │ ├── RemoveCustomerCommand.cs
│ │ │ ├── UpdateCustomerCommand.cs
│ │ │ └── Validations/
│ │ │ ├── CustomerValidation.cs
│ │ │ ├── RegisterNewCustomerCommandValidation.cs
│ │ │ ├── RemoveCustomerCommandValidation.cs
│ │ │ └── UpdateCustomerCommandValidation.cs
│ │ ├── Equinox.Domain.csproj
│ │ ├── Events/
│ │ │ ├── CustomerEventHandler.cs
│ │ │ ├── CustomerRegisteredEvent.cs
│ │ │ ├── CustomerRemovedEvent.cs
│ │ │ └── CustomerUpdatedEvent.cs
│ │ ├── Interfaces/
│ │ │ └── ICustomerRepository.cs
│ │ └── Models/
│ │ └── Customer.cs
│ ├── Equinox.Domain.Core/
│ │ ├── Equinox.Domain.Core.csproj
│ │ └── Events/
│ │ ├── IEventStore.cs
│ │ └── StoredEvent.cs
│ ├── Equinox.Infra.CrossCutting.Bus/
│ │ ├── Equinox.Infra.CrossCutting.Bus.csproj
│ │ └── InMemoryBus.cs
│ ├── Equinox.Infra.CrossCutting.Identity/
│ │ ├── API/
│ │ │ ├── AppJwtSettings.cs
│ │ │ └── JwtBuilder.cs
│ │ ├── Authorization/
│ │ │ ├── CustomAuthorizationValidation.cs
│ │ │ ├── CustomAuthorizeAttribute.cs
│ │ │ └── RequerimentClaimFilter.cs
│ │ ├── Configuration/
│ │ │ └── AspNetIdentityConfig.cs
│ │ ├── Data/
│ │ │ └── EquinoxIdentityContext.cs
│ │ ├── Equinox.Infra.CrossCutting.Identity.csproj
│ │ ├── Extensions/
│ │ │ └── ClaimsPrincipalExtensions.cs
│ │ ├── Migrations/
│ │ │ ├── 20250408033115_SQLite.Designer.cs
│ │ │ ├── 20250408033115_SQLite.cs
│ │ │ └── EquinoxIdentityContextModelSnapshot.cs
│ │ ├── Models/
│ │ │ ├── LoginUser.cs
│ │ │ ├── RegisterUser.cs
│ │ │ ├── UserClaim.cs
│ │ │ ├── UserResponse.cs
│ │ │ └── UserToken.cs
│ │ └── User/
│ │ ├── AspNetUser.cs
│ │ └── IAspNetUser.cs
│ ├── Equinox.Infra.CrossCutting.IoC/
│ │ ├── Equinox.Infra.CrossCutting.IoC.csproj
│ │ └── NativeInjectorBootStrapper.cs
│ ├── Equinox.Infra.Data/
│ │ ├── Context/
│ │ │ ├── EquinoxContext.cs
│ │ │ └── EventStoreSQLContext.cs
│ │ ├── Equinox.Infra.Data.csproj
│ │ ├── EventSourcing/
│ │ │ └── SqlEventStore.cs
│ │ ├── Mappings/
│ │ │ ├── CustomerMap.cs
│ │ │ └── StoredEventMap.cs
│ │ ├── Migrations/
│ │ │ ├── 20250408031104_SQLite.Designer.cs
│ │ │ ├── 20250408031104_SQLite.cs
│ │ │ ├── EquinoxContextModelSnapshot.cs
│ │ │ ├── EventStoreSQL/
│ │ │ │ └── EventStoreSQLContextModelSnapshot.cs
│ │ │ └── EventStoreSql/
│ │ │ ├── 20250408031128_SQLite.Designer.cs
│ │ │ └── 20250408031128_SQLite.cs
│ │ ├── Repository/
│ │ │ ├── CustomerRepository.cs
│ │ │ └── EventSourcing/
│ │ │ ├── EventStoreSQLRepository.cs
│ │ │ └── IEventStoreRepository.cs
│ │ └── appsettings.json
│ ├── Equinox.Services.Api/
│ │ ├── Configurations/
│ │ │ ├── ApiConfig.cs
│ │ │ ├── DatabaseConfig.cs
│ │ │ ├── DependencyInjectionConfig.cs
│ │ │ └── SwaggerConfig.cs
│ │ ├── Controllers/
│ │ │ ├── AccountController.cs
│ │ │ ├── ApiController.cs
│ │ │ └── CustomerController.cs
│ │ ├── Dockerfile
│ │ ├── Equinox.Services.Api.csproj
│ │ ├── Program.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.Staging.json
│ │ ├── appsettings.Testing.json
│ │ └── appsettings.json
│ └── Equinox.UI.Web/
│ ├── Areas/
│ │ └── Identity/
│ │ ├── IdentityHostingStartup.cs
│ │ └── Pages/
│ │ ├── Account/
│ │ │ ├── Login.cshtml
│ │ │ ├── Login.cshtml.cs
│ │ │ ├── Logout.cshtml
│ │ │ ├── Logout.cshtml.cs
│ │ │ ├── Register.cshtml
│ │ │ ├── Register.cshtml.cs
│ │ │ └── _ViewImports.cshtml
│ │ ├── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── Configurations/
│ │ ├── DatabaseConfig.cs
│ │ ├── DbMigrationHelpers.cs
│ │ ├── DependencyInjectionConfig.cs
│ │ └── MvcConfig.cs
│ ├── Controllers/
│ │ ├── BaseController.cs
│ │ ├── CustomerController.cs
│ │ └── HomeController.cs
│ ├── Data/
│ │ ├── ApplicationDbContext.cs
│ │ └── Migrations/
│ │ ├── 00000000000000_CreateIdentitySchema.Designer.cs
│ │ ├── 00000000000000_CreateIdentitySchema.cs
│ │ └── ApplicationDbContextModelSnapshot.cs
│ ├── Dockerfile
│ ├── Equinox.UI.Web.csproj
│ ├── Models/
│ │ └── ErrorViewModel.cs
│ ├── Program.cs
│ ├── Properties/
│ │ ├── launchSettings.json
│ │ ├── serviceDependencies.json
│ │ └── serviceDependencies.local.json
│ ├── ScaffoldingReadMe.txt
│ ├── ViewComponents/
│ │ └── SummaryViewComponent.cs
│ ├── Views/
│ │ ├── Customer/
│ │ │ ├── Create.cshtml
│ │ │ ├── Delete.cshtml
│ │ │ ├── Details.cshtml
│ │ │ ├── Edit.cshtml
│ │ │ └── Index.cshtml
│ │ ├── Home/
│ │ │ ├── Index.cshtml
│ │ │ └── Privacy.cshtml
│ │ ├── Shared/
│ │ │ ├── Components/
│ │ │ │ └── Summary/
│ │ │ │ └── Default.cshtml
│ │ │ ├── Error.cshtml
│ │ │ ├── _CookieConsentPartial.cshtml
│ │ │ ├── _Layout.cshtml
│ │ │ ├── _LoginPartial.cshtml
│ │ │ └── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ ├── appsettings.Development.json
│ ├── appsettings.Staging.json
│ ├── appsettings.Testing.json
│ ├── appsettings.json
│ ├── bundleconfig.json
│ └── wwwroot/
│ ├── _references.js
│ ├── css/
│ │ └── site.css
│ ├── js/
│ │ └── site.js
│ └── lib/
│ ├── bootstrap/
│ │ ├── .bower.json
│ │ ├── LICENSE
│ │ └── dist/
│ │ ├── css/
│ │ │ ├── bootstrap-grid.css
│ │ │ ├── bootstrap-reboot.css
│ │ │ ├── bootstrap-theme.css
│ │ │ └── bootstrap.css
│ │ └── js/
│ │ ├── bootstrap.bundle.js
│ │ ├── bootstrap.js
│ │ └── npm.js
│ ├── jquery/
│ │ ├── .bower.json
│ │ ├── LICENSE.txt
│ │ └── dist/
│ │ └── jquery.js
│ ├── jquery-validation/
│ │ ├── .bower.json
│ │ ├── LICENSE.md
│ │ └── dist/
│ │ ├── additional-methods.js
│ │ └── jquery.validate.js
│ ├── jquery-validation-unobtrusive/
│ │ ├── .bower.json
│ │ ├── LICENSE.txt
│ │ └── jquery.validate.unobtrusive.js
│ └── qrcode.js
└── tests/
└── Equinox.Tests.Architecture/
├── DataBaseTests.cs
├── DomainTests.cs
├── Equinox.Tests.Architecture.csproj
├── GeneralPatternTests.cs
├── Support/
│ ├── ShouldUseDependencyInjectionRule.cs
│ ├── TestOutputHelperTextWriter.cs
│ └── TestsSupport.cs
└── WebApplicationTests.cs
SYMBOL INDEX (515 symbols across 95 files)
FILE: src/Equinox.Application/EventSourcedNormalizers/CustomerHistory.cs
class CustomerHistory (line 9) | public static class CustomerHistory
method ToJavaScriptCustomerHistory (line 13) | public static IList<CustomerHistoryData> ToJavaScriptCustomerHistory(I...
method CustomerHistoryDeserializer (line 49) | private static void CustomerHistoryDeserializer(IEnumerable<StoredEven...
FILE: src/Equinox.Application/EventSourcedNormalizers/CustomerHistoryData.cs
class CustomerHistoryData (line 3) | public class CustomerHistoryData
FILE: src/Equinox.Application/Extensions/CustomerExtensions.cs
class CustomerExtensions (line 9) | public static class CustomerExtensions
method ToViewModel (line 11) | public static CustomerViewModel ToViewModel(this Customer customer)
method ToViewModel (line 24) | public static IEnumerable<CustomerViewModel> ToViewModel(this IEnumera...
method ToEntity (line 29) | public static Customer ToEntity(this CustomerViewModel customer)
method ToRegisterCommand (line 36) | public static RegisterNewCustomerCommand ToRegisterCommand(this Custom...
method ToUpdateCommand (line 43) | public static UpdateCustomerCommand ToUpdateCommand(this CustomerViewM...
FILE: src/Equinox.Application/Interfaces/ICustomerAppService.cs
type ICustomerAppService (line 10) | public interface ICustomerAppService : IDisposable
method GetAll (line 12) | Task<IEnumerable<CustomerViewModel>> GetAll();
method GetById (line 13) | Task<CustomerViewModel> GetById(Guid id);
method Register (line 15) | Task<ValidationResult> Register(CustomerViewModel customerViewModel);
method Update (line 16) | Task<ValidationResult> Update(CustomerViewModel customerViewModel);
method Remove (line 17) | Task<ValidationResult> Remove(Guid id);
method GetAllHistory (line 19) | Task<IList<CustomerHistoryData>> GetAllHistory(Guid id);
FILE: src/Equinox.Application/Services/CustomerAppService.cs
class CustomerAppService (line 16) | public class CustomerAppService(ICustomerRepository customerRepository,
method GetAll (line 24) | public async Task<IEnumerable<CustomerViewModel>> GetAll()
method GetById (line 29) | public async Task<CustomerViewModel> GetById(Guid id)
method Register (line 34) | public async Task<ValidationResult> Register(CustomerViewModel custome...
method Update (line 40) | public async Task<ValidationResult> Update(CustomerViewModel customerV...
method Remove (line 46) | public async Task<ValidationResult> Remove(Guid id)
method GetAllHistory (line 52) | public async Task<IList<CustomerHistoryData>> GetAllHistory(Guid id)
method Dispose (line 57) | public void Dispose()
FILE: src/Equinox.Application/ViewModels/CustomerViewModel.cs
class CustomerViewModel (line 7) | public class CustomerViewModel
FILE: src/Equinox.Domain.Core/Events/IEventStore.cs
type IEventStore (line 5) | public interface IEventStore
method Save (line 7) | void Save<T>(T theEvent) where T : Event;
FILE: src/Equinox.Domain.Core/Events/StoredEvent.cs
class StoredEvent (line 6) | public class StoredEvent : Event
method StoredEvent (line 8) | public StoredEvent(Event theEvent, string data, string user)
method StoredEvent (line 18) | protected StoredEvent() { }
FILE: src/Equinox.Domain/Commands/CustomerCommand.cs
class CustomerCommand (line 6) | public abstract class CustomerCommand : Command
FILE: src/Equinox.Domain/Commands/CustomerCommandHandler.cs
class CustomerCommandHandler (line 13) | public class CustomerCommandHandler(ICustomerRepository customerReposito...
method Handle (line 20) | public async Task<ValidationResult> Handle(RegisterNewCustomerCommand ...
method Handle (line 39) | public async Task<ValidationResult> Handle(UpdateCustomerCommand messa...
method Handle (line 62) | public async Task<ValidationResult> Handle(RemoveCustomerCommand messa...
method Dispose (line 81) | public void Dispose()
FILE: src/Equinox.Domain/Commands/RegisterNewCustomerCommand.cs
class RegisterNewCustomerCommand (line 6) | public class RegisterNewCustomerCommand : CustomerCommand
method RegisterNewCustomerCommand (line 8) | public RegisterNewCustomerCommand(string name, string email, DateTime ...
method IsValid (line 15) | public override bool IsValid()
FILE: src/Equinox.Domain/Commands/RemoveCustomerCommand.cs
class RemoveCustomerCommand (line 6) | public class RemoveCustomerCommand : CustomerCommand
method RemoveCustomerCommand (line 8) | public RemoveCustomerCommand(Guid id)
method IsValid (line 14) | public override bool IsValid()
FILE: src/Equinox.Domain/Commands/UpdateCustomerCommand.cs
class UpdateCustomerCommand (line 6) | public class UpdateCustomerCommand : CustomerCommand
method UpdateCustomerCommand (line 8) | public UpdateCustomerCommand(Guid id, string name, string email, DateT...
method IsValid (line 16) | public override bool IsValid()
FILE: src/Equinox.Domain/Commands/Validations/CustomerValidation.cs
class CustomerValidation (line 6) | public abstract class CustomerValidation<T> : AbstractValidator<T> where...
method ValidateName (line 8) | protected void ValidateName()
method ValidateBirthDate (line 15) | protected void ValidateBirthDate()
method ValidateEmail (line 23) | protected void ValidateEmail()
method ValidateId (line 30) | protected void ValidateId()
method HaveMinimumAge (line 36) | protected static bool HaveMinimumAge(DateTime birthDate)
FILE: src/Equinox.Domain/Commands/Validations/RegisterNewCustomerCommandValidation.cs
class RegisterNewCustomerCommandValidation (line 3) | public class RegisterNewCustomerCommandValidation : CustomerValidation<R...
method RegisterNewCustomerCommandValidation (line 5) | public RegisterNewCustomerCommandValidation()
FILE: src/Equinox.Domain/Commands/Validations/RemoveCustomerCommandValidation.cs
class RemoveCustomerCommandValidation (line 3) | public class RemoveCustomerCommandValidation : CustomerValidation<Remove...
method RemoveCustomerCommandValidation (line 5) | public RemoveCustomerCommandValidation()
FILE: src/Equinox.Domain/Commands/Validations/UpdateCustomerCommandValidation.cs
class UpdateCustomerCommandValidation (line 3) | public class UpdateCustomerCommandValidation : CustomerValidation<Update...
method UpdateCustomerCommandValidation (line 5) | public UpdateCustomerCommandValidation()
FILE: src/Equinox.Domain/Events/CustomerEventHandler.cs
class CustomerEventHandler (line 7) | public class CustomerEventHandler :
method Handle (line 12) | public Task Handle(CustomerUpdatedEvent message, CancellationToken can...
method Handle (line 19) | public Task Handle(CustomerRegisteredEvent message, CancellationToken ...
method Handle (line 26) | public Task Handle(CustomerRemovedEvent message, CancellationToken can...
FILE: src/Equinox.Domain/Events/CustomerRegisteredEvent.cs
class CustomerRegisteredEvent (line 6) | public class CustomerRegisteredEvent : Event
method CustomerRegisteredEvent (line 8) | public CustomerRegisteredEvent(Guid id, string name, string email, Dat...
FILE: src/Equinox.Domain/Events/CustomerRemovedEvent.cs
class CustomerRemovedEvent (line 6) | public class CustomerRemovedEvent : Event
method CustomerRemovedEvent (line 8) | public CustomerRemovedEvent(Guid id)
FILE: src/Equinox.Domain/Events/CustomerUpdatedEvent.cs
class CustomerUpdatedEvent (line 6) | public class CustomerUpdatedEvent : Event
method CustomerUpdatedEvent (line 8) | public CustomerUpdatedEvent(Guid id, string name, string email, DateTi...
FILE: src/Equinox.Domain/Interfaces/ICustomerRepository.cs
type ICustomerRepository (line 9) | public interface ICustomerRepository : IRepository<Customer>
method GetById (line 11) | Task<Customer> GetById(Guid id);
method GetByEmail (line 12) | Task<Customer> GetByEmail(string email);
method GetAll (line 13) | Task<IEnumerable<Customer>> GetAll();
method Add (line 15) | void Add(Customer customer);
method Update (line 16) | void Update(Customer customer);
method Remove (line 17) | void Remove(Customer customer);
FILE: src/Equinox.Domain/Models/Customer.cs
class Customer (line 6) | public class Customer : Entity, IAggregateRoot
method Customer (line 8) | public Customer(Guid id, string name, string email, DateTime birthDate)
method Customer (line 17) | protected Customer() { }
FILE: src/Equinox.Infra.CrossCutting.Bus/InMemoryBus.cs
class InMemoryBus (line 10) | public sealed class InMemoryBus(IEventStore eventStore, IMediator mediat...
method PublishEvent (line 15) | public async Task PublishEvent<T>(T @event) where T : Event
method SendCommand (line 23) | public async Task<ValidationResult> SendCommand<T>(T command) where T ...
FILE: src/Equinox.Infra.CrossCutting.Identity/API/AppJwtSettings.cs
class AppJwtSettings (line 3) | public class AppJwtSettings
FILE: src/Equinox.Infra.CrossCutting.Identity/API/JwtBuilder.cs
class JwtBuilder (line 13) | public class JwtBuilder<TIdentityUser, TKey> where TIdentityUser : Ident...
method WithUserManager (line 22) | public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TId...
method WithJwtSettings (line 28) | public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings ...
method WithEmail (line 34) | public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
method WithJwtClaims (line 46) | public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
method WithUserClaims (line 59) | public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
method WithUserRoles (line 67) | public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
method BuildToken (line 75) | public string BuildToken()
method BuildUserResponse (line 92) | public UserResponse BuildUserResponse()
method ToUnixEpochDate (line 109) | private static long ToUnixEpochDate(DateTime date)
class JwtBuilder (line 114) | public class JwtBuilder<TIdentityUser> : JwtBuilder<TIdentityUser, strin...
method WithUserManager (line 22) | public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TId...
method WithJwtSettings (line 28) | public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings ...
method WithEmail (line 34) | public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
method WithJwtClaims (line 46) | public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
method WithUserClaims (line 59) | public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
method WithUserRoles (line 67) | public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
method BuildToken (line 75) | public string BuildToken()
method BuildUserResponse (line 92) | public UserResponse BuildUserResponse()
method ToUnixEpochDate (line 109) | private static long ToUnixEpochDate(DateTime date)
class JwtBuilder (line 116) | public sealed class JwtBuilder : JwtBuilder<IdentityUser> { }
method WithUserManager (line 22) | public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TId...
method WithJwtSettings (line 28) | public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings ...
method WithEmail (line 34) | public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
method WithJwtClaims (line 46) | public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
method WithUserClaims (line 59) | public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
method WithUserRoles (line 67) | public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
method BuildToken (line 75) | public string BuildToken()
method BuildUserResponse (line 92) | public UserResponse BuildUserResponse()
method ToUnixEpochDate (line 109) | private static long ToUnixEpochDate(DateTime date)
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizationValidation.cs
class CustomAuthorizationValidation (line 6) | public static class CustomAuthorizationValidation
method UserHasValidClaim (line 8) | public static bool UserHasValidClaim(HttpContext context, string claim...
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizeAttribute.cs
class CustomAuthorizeAttribute (line 6) | public class CustomAuthorizeAttribute : TypeFilterAttribute
method CustomAuthorizeAttribute (line 8) | public CustomAuthorizeAttribute(string claimName, string claimValue) :...
FILE: src/Equinox.Infra.CrossCutting.Identity/Authorization/RequerimentClaimFilter.cs
class RequerimentClaimFilter (line 7) | internal class RequerimentClaimFilter : IAuthorizationFilter
method RequerimentClaimFilter (line 11) | public RequerimentClaimFilter(Claim claim)
method OnAuthorization (line 16) | public void OnAuthorization(AuthorizationFilterContext context)
FILE: src/Equinox.Infra.CrossCutting.Identity/Configuration/AspNetIdentityConfig.cs
class AspNetIdentityConfig (line 18) | public static class AspNetIdentityConfig
method AddApiIdentityConfiguration (line 20) | public static WebApplicationBuilder AddApiIdentityConfiguration(this W...
method AddWebIdentityConfiguration (line 30) | public static WebApplicationBuilder AddWebIdentityConfiguration(this W...
method AddIdentityDbContext (line 40) | private static WebApplicationBuilder AddIdentityDbContext(this WebAppl...
method AddIdentityApiSupport (line 57) | private static WebApplicationBuilder AddIdentityApiSupport(this WebApp...
method AddIdentityWebUISupport (line 69) | private static WebApplicationBuilder AddIdentityWebUISupport(this WebA...
method AddJwtSupport (line 79) | private static WebApplicationBuilder AddJwtSupport(this WebApplication...
method AddAspNetUserSupport (line 106) | public static WebApplicationBuilder AddAspNetUserSupport(this WebAppli...
method AddSocialAuthenticationSupport (line 114) | public static WebApplicationBuilder AddSocialAuthenticationSupport(thi...
FILE: src/Equinox.Infra.CrossCutting.Identity/Data/EquinoxIdentityContext.cs
class EquinoxIdentityContext (line 10) | public class EquinoxIdentityContext : IdentityDbContext
method EquinoxIdentityContext (line 12) | public EquinoxIdentityContext(DbContextOptions<EquinoxIdentityContext>...
class EquinoxIdentityContextFactory (line 15) | public class EquinoxIdentityContextFactory : IDesignTimeDbContextFactory...
method CreateDbContext (line 17) | public EquinoxIdentityContext CreateDbContext(string[] args)
FILE: src/Equinox.Infra.CrossCutting.Identity/Extensions/ClaimsPrincipalExtensions.cs
class ClaimsPrincipalExtensions (line 7) | public static class ClaimsPrincipalExtensions
method GetUserId (line 9) | public static string GetUserId(this ClaimsPrincipal principal)
method GetUserEmail (line 23) | public static string GetUserEmail(this ClaimsPrincipal principal)
method GetUserId (line 35) | public static string GetUserId(this ClaimsIdentity principal)
method GetUserEmail (line 49) | public static string GetUserEmail(this ClaimsIdentity principal)
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.Designer.cs
class SQLite (line 13) | [DbContext(typeof(EquinoxIdentityContext))]
method BuildTargetModel (line 18) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.cs
class SQLite (line 9) | public partial class SQLite : Migration
method Up (line 12) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 198) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Equinox.Infra.CrossCutting.Identity/Migrations/EquinoxIdentityContextModelSnapshot.cs
class EquinoxIdentityContextModelSnapshot (line 12) | [DbContext(typeof(EquinoxIdentityContext))]
method BuildModel (line 15) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/LoginUser.cs
class LoginUser (line 5) | public class LoginUser
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/RegisterUser.cs
class RegisterUser (line 5) | public class RegisterUser
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserClaim.cs
class UserClaim (line 3) | public class UserClaim
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserResponse.cs
class UserResponse (line 3) | public class UserResponse
FILE: src/Equinox.Infra.CrossCutting.Identity/Models/UserToken.cs
class UserToken (line 5) | public class UserToken
FILE: src/Equinox.Infra.CrossCutting.Identity/User/AspNetUser.cs
class AspNetUser (line 9) | public class AspNetUser : IAspNetUser
method AspNetUser (line 13) | public AspNetUser(IHttpContextAccessor accessor)
method GetUserId (line 20) | public Guid GetUserId()
method GetUserEmail (line 25) | public string GetUserEmail()
method IsAuthenticated (line 30) | public bool IsAuthenticated()
method IsInRole (line 35) | public bool IsInRole(string role)
method GetUserClaims (line 40) | public IEnumerable<Claim> GetUserClaims()
method GetHttpContext (line 45) | public HttpContext GetHttpContext()
FILE: src/Equinox.Infra.CrossCutting.Identity/User/IAspNetUser.cs
type IAspNetUser (line 8) | public interface IAspNetUser
method GetUserId (line 11) | Guid GetUserId();
method GetUserEmail (line 12) | string GetUserEmail();
method IsAuthenticated (line 13) | bool IsAuthenticated();
method IsInRole (line 14) | bool IsInRole(string role);
method GetUserClaims (line 15) | IEnumerable<Claim> GetUserClaims();
method GetHttpContext (line 16) | HttpContext GetHttpContext();
FILE: src/Equinox.Infra.CrossCutting.IoC/NativeInjectorBootStrapper.cs
class NativeInjectorBootStrapper (line 21) | public static class NativeInjectorBootStrapper
method RegisterServices (line 23) | public static void RegisterServices(WebApplicationBuilder builder)
FILE: src/Equinox.Infra.Data/Context/EquinoxContext.cs
class EquinoxContext (line 14) | public sealed class EquinoxContext : DbContext, IUnitOfWork
method EquinoxContext (line 18) | public EquinoxContext(DbContextOptions<EquinoxContext> options, IMedia...
method OnModelCreating (line 27) | protected override void OnModelCreating(ModelBuilder modelBuilder)
method Commit (line 41) | public async Task<bool> Commit()
class MediatorExtension (line 59) | public static class MediatorExtension
method PublishDomainEvents (line 61) | public static async Task PublishDomainEvents<T>(this IMediatorHandler ...
FILE: src/Equinox.Infra.Data/Context/EventStoreSQLContext.cs
class EventStoreSqlContext (line 8) | public class EventStoreSqlContext : DbContext
method EventStoreSqlContext (line 10) | public EventStoreSqlContext(DbContextOptions<EventStoreSqlContext> opt...
method OnModelCreating (line 14) | protected override void OnModelCreating(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.Data/EventSourcing/SqlEventStore.cs
class SqlEventStore (line 9) | public class SqlEventStore : IEventStore
method SqlEventStore (line 14) | public SqlEventStore(IEventStoreRepository eventStoreRepository, IAspN...
method Save (line 20) | public void Save<T>(T theEvent) where T : Event
FILE: src/Equinox.Infra.Data/Mappings/CustomerMap.cs
class CustomerMap (line 7) | public class CustomerMap : IEntityTypeConfiguration<Customer>
method Configure (line 9) | public void Configure(EntityTypeBuilder<Customer> builder)
FILE: src/Equinox.Infra.Data/Mappings/StoredEventMap.cs
class StoredEventMap (line 7) | public class StoredEventMap : IEntityTypeConfiguration<StoredEvent>
method Configure (line 9) | public void Configure(EntityTypeBuilder<StoredEvent> builder)
FILE: src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.Designer.cs
class SQLite (line 13) | [DbContext(typeof(EquinoxContext))]
method BuildTargetModel (line 18) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.cs
class SQLite (line 9) | public partial class SQLite : Migration
method Up (line 12) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 30) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Equinox.Infra.Data/Migrations/EquinoxContextModelSnapshot.cs
class EquinoxContextModelSnapshot (line 12) | [DbContext(typeof(EquinoxContext))]
method BuildModel (line 15) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSQL/EventStoreSQLContextModelSnapshot.cs
class EventStoreSqlContextModelSnapshot (line 12) | [DbContext(typeof(EventStoreSqlContext))]
method BuildModel (line 15) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.Designer.cs
class SQLite (line 13) | [DbContext(typeof(EventStoreSqlContext))]
method BuildTargetModel (line 18) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.cs
class SQLite (line 9) | public partial class SQLite : Migration
method Up (line 12) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 32) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Equinox.Infra.Data/Repository/CustomerRepository.cs
class CustomerRepository (line 12) | public class CustomerRepository : ICustomerRepository
method CustomerRepository (line 17) | public CustomerRepository(EquinoxContext context)
method GetById (line 25) | public async Task<Customer> GetById(Guid id)
method GetAll (line 30) | public async Task<IEnumerable<Customer>> GetAll()
method GetByEmail (line 35) | public async Task<Customer> GetByEmail(string email)
method Add (line 40) | public void Add(Customer customer)
method Update (line 45) | public void Update(Customer customer)
method Remove (line 50) | public void Remove(Customer customer)
method Dispose (line 55) | public void Dispose()
FILE: src/Equinox.Infra.Data/Repository/EventSourcing/EventStoreSQLRepository.cs
class EventStoreSqlRepository (line 11) | public class EventStoreSqlRepository : IEventStoreRepository
method EventStoreSqlRepository (line 15) | public EventStoreSqlRepository(EventStoreSqlContext context)
method All (line 20) | public async Task<IList<StoredEvent>> All(Guid aggregateId)
method Store (line 25) | public void Store(StoredEvent theEvent)
method Dispose (line 31) | public void Dispose()
FILE: src/Equinox.Infra.Data/Repository/EventSourcing/IEventStoreRepository.cs
type IEventStoreRepository (line 8) | public interface IEventStoreRepository : IDisposable
method Store (line 10) | void Store(StoredEvent theEvent);
method All (line 11) | Task<IList<StoredEvent>> All(Guid aggregateId);
FILE: src/Equinox.Services.Api/Configurations/ApiConfig.cs
class ApiConfig (line 3) | public static class ApiConfig
method AddApiConfiguration (line 5) | public static WebApplicationBuilder AddApiConfiguration(this WebApplic...
FILE: src/Equinox.Services.Api/Configurations/DatabaseConfig.cs
class DatabaseConfig (line 6) | public static class DatabaseConfig
method AddDatabaseConfiguration (line 8) | public static WebApplicationBuilder AddDatabaseConfiguration(this WebA...
FILE: src/Equinox.Services.Api/Configurations/DependencyInjectionConfig.cs
class DependencyInjectionConfig (line 5) | public static class DependencyInjectionConfig
method AddDependencyInjectionConfiguration (line 7) | public static WebApplicationBuilder AddDependencyInjectionConfiguratio...
FILE: src/Equinox.Services.Api/Configurations/SwaggerConfig.cs
class SwaggerConfig (line 5) | public static class SwaggerConfig
method AddSwaggerConfiguration (line 7) | public static WebApplicationBuilder AddSwaggerConfiguration(this WebAp...
method UseSwaggerSetup (line 84) | public static IApplicationBuilder UseSwaggerSetup(this IApplicationBui...
FILE: src/Equinox.Services.Api/Controllers/AccountController.cs
class AccountController (line 9) | [Route("account")]
method AccountController (line 17) | public AccountController(
method Register (line 27) | [HttpPost]
method Login (line 55) | [HttpPost]
method GetFullJwt (line 79) | private string GetFullJwt(string email)
FILE: src/Equinox.Services.Api/Controllers/ApiController.cs
class ApiController (line 7) | [ApiController]
method CustomResponse (line 12) | protected ActionResult CustomResponse(object result = null)
method CustomResponse (line 25) | protected ActionResult CustomResponse(ModelStateDictionary modelState)
method CustomResponse (line 36) | protected ActionResult CustomResponse(ValidationResult validationResult)
method IsOperationValid (line 46) | protected bool IsOperationValid()
method AddError (line 51) | protected void AddError(string erro)
method ClearErrors (line 56) | protected void ClearErrors()
FILE: src/Equinox.Services.Api/Controllers/CustomerController.cs
class CustomerController (line 10) | [Authorize]
method CustomerController (line 15) | public CustomerController(ICustomerAppService customerAppService)
method Get (line 20) | [AllowAnonymous]
method Get (line 27) | [AllowAnonymous]
method Post (line 34) | [CustomAuthorize("Customers", "Write")]
method Put (line 41) | [CustomAuthorize("Customers", "Write")]
method Delete (line 48) | [CustomAuthorize("Customers", "Remove")]
method History (line 55) | [AllowAnonymous]
FILE: src/Equinox.UI.Web/Areas/Identity/IdentityHostingStartup.cs
class IdentityHostingStartup (line 4) | public class IdentityHostingStartup : IHostingStartup
method Configure (line 6) | public void Configure(IWebHostBuilder builder)
FILE: src/Equinox.UI.Web/Areas/Identity/Pages/Account/Login.cshtml.cs
class LoginModel (line 17) | [AllowAnonymous]
method LoginModel (line 24) | public LoginModel(SignInManager<IdentityUser> signInManager,
class InputModel (line 43) | public class InputModel
method OnGetAsync (line 57) | public async Task OnGetAsync(string returnUrl = null)
method OnPostAsync (line 74) | public async Task<IActionResult> OnPostAsync(string returnUrl = null)
FILE: src/Equinox.UI.Web/Areas/Identity/Pages/Account/Logout.cshtml.cs
class LogoutModel (line 13) | [AllowAnonymous]
method LogoutModel (line 19) | public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<...
method OnGet (line 25) | public void OnGet()
method OnPost (line 29) | public async Task<IActionResult> OnPost(string returnUrl = null)
FILE: src/Equinox.UI.Web/Areas/Identity/Pages/Account/Register.cshtml.cs
class RegisterModel (line 13) | [AllowAnonymous]
method RegisterModel (line 20) | public RegisterModel(
class InputModel (line 37) | public class InputModel
method OnGetAsync (line 56) | public async Task OnGetAsync(string returnUrl = null)
method OnPostAsync (line 62) | public async Task<IActionResult> OnPostAsync(string returnUrl = null)
FILE: src/Equinox.UI.Web/Configurations/DatabaseConfig.cs
class DatabaseConfig (line 6) | public static class DatabaseConfig
method AddDatabaseConfiguration (line 8) | public static WebApplicationBuilder AddDatabaseConfiguration(this WebA...
method UseDbSeed (line 35) | public static WebApplication UseDbSeed(this WebApplication app)
FILE: src/Equinox.UI.Web/Configurations/DbMigrationHelpers.cs
class DbMigrationHelpers (line 13) | public static class DbMigrationHelpers
method EnsureSeedData (line 15) | public static async Task EnsureSeedData(WebApplication serviceScope)
method EnsureSeedData (line 21) | public static async Task EnsureSeedData(IServiceProvider serviceProvider)
method EnsureSeedProducts (line 40) | private static async Task EnsureSeedProducts(EquinoxContext context,
FILE: src/Equinox.UI.Web/Configurations/DependencyInjectionConfig.cs
class DependencyInjectionConfig (line 5) | public static class DependencyInjectionConfig
method AddDependencyInjectionConfiguration (line 7) | public static void AddDependencyInjectionConfiguration(this WebApplica...
FILE: src/Equinox.UI.Web/Configurations/MvcConfig.cs
class MvcConfig (line 5) | public static class MvcConfig
method AddMvcConfiguration (line 7) | public static WebApplicationBuilder AddMvcConfiguration(this WebApplic...
FILE: src/Equinox.UI.Web/Controllers/BaseController.cs
class BaseController (line 6) | public abstract class BaseController : Controller
method ResponseHasErrors (line 10) | protected bool ResponseHasErrors(ValidationResult result)
method AddProcessError (line 22) | protected void AddProcessError(string erro)
method IsValidOperation (line 27) | public bool IsValidOperation()
FILE: src/Equinox.UI.Web/Controllers/CustomerController.cs
class CustomerController (line 9) | [Authorize]
method Index (line 14) | [AllowAnonymous]
method Details (line 21) | [AllowAnonymous]
method Create (line 34) | [CustomAuthorize("Customers", "Write")]
method Create (line 41) | [CustomAuthorize("Customers", "Write")]
method Edit (line 55) | [CustomAuthorize("Customers", "Write")]
method Edit (line 68) | [CustomAuthorize("Customers", "Write")]
method Delete (line 84) | [CustomAuthorize("Customers", "Remove")]
method DeleteConfirmed (line 97) | [CustomAuthorize("Customers", "Remove")]
method History (line 108) | [AllowAnonymous]
FILE: src/Equinox.UI.Web/Controllers/HomeController.cs
class HomeController (line 6) | public class HomeController : Controller
method Index (line 8) | public IActionResult Index()
method Errors (line 13) | [Route("error/{id:length(3,3)}")]
FILE: src/Equinox.UI.Web/Data/ApplicationDbContext.cs
class ApplicationDbContext (line 6) | public class ApplicationDbContext : IdentityDbContext
method ApplicationDbContext (line 8) | public ApplicationDbContext(DbContextOptions<ApplicationDbContext> opt...
FILE: src/Equinox.UI.Web/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
class CreateIdentitySchema (line 12) | [DbContext(typeof(ApplicationDbContext))]
method BuildTargetModel (line 16) | protected override void BuildTargetModel(ModelBuilder modelBuilder)
FILE: src/Equinox.UI.Web/Data/Migrations/00000000000000_CreateIdentitySchema.cs
class CreateIdentitySchema (line 6) | public partial class CreateIdentitySchema : Migration
method Up (line 8) | protected override void Up(MigrationBuilder migrationBuilder)
method Down (line 195) | protected override void Down(MigrationBuilder migrationBuilder)
FILE: src/Equinox.UI.Web/Data/Migrations/ApplicationDbContextModelSnapshot.cs
class ApplicationDbContextModelSnapshot (line 11) | [DbContext(typeof(ApplicationDbContext))]
method BuildModel (line 14) | protected override void BuildModel(ModelBuilder modelBuilder)
FILE: src/Equinox.UI.Web/Models/ErrorViewModel.cs
class ErrorViewModel (line 3) | public class ErrorViewModel
FILE: src/Equinox.UI.Web/ViewComponents/SummaryViewComponent.cs
class SummaryViewComponent (line 5) | public class SummaryViewComponent : ViewComponent
method Invoke (line 7) | public IViewComponentResult Invoke()
FILE: src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js
function _defineProperties (line 14) | function _defineProperties(target, props) {
function _createClass (line 24) | function _createClass(Constructor, protoProps, staticProps) {
function _defineProperty (line 30) | function _defineProperty(obj, key, value) {
function _objectSpread (line 45) | function _objectSpread(target) {
function _inheritsLoose (line 64) | function _inheritsLoose(subClass, superClass) {
function toType (line 86) | function toType(obj) {
function getSpecialTransitionEndEvent (line 90) | function getSpecialTransitionEndEvent() {
function transitionEndEmulator (line 104) | function transitionEndEmulator(duration) {
function setTransitionEndSupport (line 119) | function setTransitionEndSupport() {
function Alert (line 260) | function Alert(element) {
function Button (line 428) | function Button(element) {
function Carousel (line 635) | function Carousel(element, config) {
function Collapse (line 1195) | function Collapse(element, config) {
function microtaskDebounce (line 1539) | function microtaskDebounce(fn) {
function taskDebounce (line 1553) | function taskDebounce(fn) {
function isFunction (line 1586) | function isFunction(functionToCheck) {
function getStyleComputedProperty (line 1598) | function getStyleComputedProperty(element, property) {
function getParentNode (line 1615) | function getParentNode(element) {
function getScrollParent (line 1629) | function getScrollParent(element) {
function isIE (line 1667) | function isIE(version) {
function getOffsetParent (line 1684) | function getOffsetParent(element) {
function isOffsetContainer (line 1713) | function isOffsetContainer(element) {
function getRoot (line 1729) | function getRoot(node) {
function findCommonOffsetParent (line 1745) | function findCommonOffsetParent(element1, element2) {
function getScroll (line 1789) | function getScroll(element) {
function includeScroll (line 1813) | function includeScroll(rect, element) {
function getBordersSize (line 1836) | function getBordersSize(styles, axis) {
function getSize (line 1843) | function getSize(axis, body, html, computedStyle) {
function getWindowSizes (line 1847) | function getWindowSizes(document) {
function defineProperties (line 1865) | function defineProperties(target, props) {
function getClientRect (line 1922) | function getClientRect(offsets) {
function getBoundingClientRect (line 1936) | function getBoundingClientRect(element) {
function getOffsetRectRelativeToArbitraryNode (line 1985) | function getOffsetRectRelativeToArbitraryNode(children, parent) {
function getViewportOffsetRectRelativeToArtbitraryNode (line 2037) | function getViewportOffsetRectRelativeToArtbitraryNode(element) {
function isFixed (line 2066) | function isFixed(element) {
function getFixedPositionOffsetParent (line 2089) | function getFixedPositionOffsetParent(element) {
function getBoundaries (line 2112) | function getBoundaries(popper, reference, padding, boundariesElement) {
function getArea (line 2166) | function getArea(_ref) {
function computeAutoPlacement (line 2182) | function computeAutoPlacement(placement, refRect, popper, reference, bou...
function getReferenceOffsets (line 2243) | function getReferenceOffsets(state, popper, reference) {
function getOuterSizes (line 2257) | function getOuterSizes(element) {
function getOppositePlacement (line 2276) | function getOppositePlacement(placement) {
function getPopperOffsets (line 2293) | function getPopperOffsets(popper, referenceOffsets, placement) {
function find (line 2331) | function find(arr, check) {
function findIndex (line 2350) | function findIndex(arr, prop, value) {
function runModifiers (line 2375) | function runModifiers(modifiers, data, ends) {
function update (line 2405) | function update() {
function isModifierEnabled (line 2457) | function isModifierEnabled(modifiers, modifierName) {
function getSupportedPropertyName (line 2472) | function getSupportedPropertyName(property) {
function destroy (line 2491) | function destroy() {
function getWindow (line 2521) | function getWindow(element) {
function attachToScrollParents (line 2526) | function attachToScrollParents(scrollParent, event, callback, scrollPare...
function setupEventListeners (line 2543) | function setupEventListeners(reference, options, state, updateBound) {
function enableEventListeners (line 2563) | function enableEventListeners() {
function removeEventListeners (line 2575) | function removeEventListeners(reference, state) {
function disableEventListeners (line 2599) | function disableEventListeners() {
function isNumeric (line 2613) | function isNumeric(n) {
function setStyles (line 2625) | function setStyles(element, styles) {
function setAttributes (line 2644) | function setAttributes(element, attributes) {
function applyStyle (line 2664) | function applyStyle(data) {
function applyStyleOnLoad (line 2693) | function applyStyleOnLoad(reference, popper, options, modifierOptions, s...
function getRoundedOffsets (line 2730) | function getRoundedOffsets(data, shouldRound) {
function computeStyle (line 2769) | function computeStyle(data, options) {
function isModifierRequired (line 2870) | function isModifierRequired(modifiers, requestingName, requestedName) {
function arrow (line 2895) | function arrow(data, options) {
function getOppositeVariation (line 2977) | function getOppositeVariation(variation) {
function clockwise (line 3032) | function clockwise(placement) {
function flip (line 3053) | function flip(data, options) {
function keepTogether (line 3143) | function keepTogether(data) {
function toValue (line 3177) | function toValue(str, measurement, popperOffsets, referenceOffsets) {
function parseOffset (line 3229) | function parseOffset(offset, popperOffsets, referenceOffsets, basePlacem...
function offset (line 3305) | function offset(data, _ref) {
function preventOverflow (line 3346) | function preventOverflow(data, options) {
function shift (line 3417) | function shift(data) {
function hide (line 3450) | function hide(data) {
function inner (line 3488) | function inner(data) {
function Popper (line 3939) | function Popper(reference, popper) {
function Dropdown (line 4169) | function Dropdown(element, config) {
function Modal (line 4674) | function Modal(element, config) {
function allowedAttribute (line 5247) | function allowedAttribute(attr, allowedAttributeList) {
function sanitizeHtml (line 5271) | function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
function Tooltip (line 5408) | function Tooltip(element, config) {
function Popover (line 6086) | function Popover() {
function ScrollSpy (line 6273) | function ScrollSpy(element, config) {
function Tab (line 6568) | function Tab(element) {
function Toast (line 6805) | function Toast(element, config) {
FILE: src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.js
function _defineProperties (line 15) | function _defineProperties(target, props) {
function _createClass (line 25) | function _createClass(Constructor, protoProps, staticProps) {
function _defineProperty (line 31) | function _defineProperty(obj, key, value) {
function _objectSpread (line 46) | function _objectSpread(target) {
function _inheritsLoose (line 65) | function _inheritsLoose(subClass, superClass) {
function toType (line 87) | function toType(obj) {
function getSpecialTransitionEndEvent (line 91) | function getSpecialTransitionEndEvent() {
function transitionEndEmulator (line 105) | function transitionEndEmulator(duration) {
function setTransitionEndSupport (line 120) | function setTransitionEndSupport() {
function Alert (line 261) | function Alert(element) {
function Button (line 429) | function Button(element) {
function Carousel (line 636) | function Carousel(element, config) {
function Collapse (line 1196) | function Collapse(element, config) {
function Dropdown (line 1591) | function Dropdown(element, config) {
function Modal (line 2096) | function Modal(element, config) {
function allowedAttribute (line 2669) | function allowedAttribute(attr, allowedAttributeList) {
function sanitizeHtml (line 2693) | function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
function Tooltip (line 2830) | function Tooltip(element, config) {
function Popover (line 3508) | function Popover() {
function ScrollSpy (line 3695) | function ScrollSpy(element, config) {
function Tab (line 3990) | function Tab(element) {
function Toast (line 4227) | function Toast(element, config) {
FILE: src/Equinox.UI.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: src/Equinox.UI.Web/wwwroot/lib/jquery-validation/dist/additional-methods.js
function stripHtml (line 21) | function stripHtml( value ) {
function isOdd (line 212) | function isOdd( n ) {
FILE: src/Equinox.UI.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.js
function handle (line 70) | function handle() {
function delegate (line 411) | function delegate( event ) {
FILE: src/Equinox.UI.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: src/Equinox.UI.Web/wwwroot/lib/qrcode.js
function QR8bitByte (line 29) | function QR8bitByte(data) {
function QRCodeModel (line 78) | function QRCodeModel(typeNumber, errorCorrectLevel) {
function QRPolynomial (line 139) | function QRPolynomial(num,shift){if(num.length==undefined){throw new Err...
function QRRSBlock (line 146) | function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this...
function QRBitBuffer (line 149) | function QRBitBuffer(){this.buffer=[];this.length=0;}
function _isSupportCanvas (line 154) | function _isSupportCanvas() {
function _getAndroid (line 159) | function _getAndroid() {
function makeSVG (line 191) | function makeSVG(tag, attrs) {
function _onMakeImage (line 276) | function _onMakeImage() {
function _safeSetDataURI (line 310) | function _safeSetDataURI(fSuccess, fFail) {
function _getTypeNumber (line 469) | function _getTypeNumber(sText, nCorrectLevel) {
function _getUTF8Length (line 505) | function _getUTF8Length(sText) {
FILE: tests/Equinox.Tests.Architecture/DataBaseTests.cs
class DataBaseTests (line 7) | public class DataBaseTests
method DataBaseTests (line 11) | public DataBaseTests(ITestOutputHelper output)
method RepositoryClasses_MustHave_ConstructorWithParameters (line 18) | [Fact(DisplayName = "Repository Classes Must Have Constructor With Par...
FILE: tests/Equinox.Tests.Architecture/DomainTests.cs
class DomainTests (line 7) | public class DomainTests
method Domain_ShouldNotHave_ProjectDependencies (line 9) | [Fact(DisplayName = "Domain Should Not Have Any Dependencies")]
method DomainElements_MustReside_InSameNameSpace (line 34) | [Fact(DisplayName = "Domain Namespace Should Have A Pattern")]
method DomainCore_ShouldNotHave_ProjectDependencies (line 51) | [Fact(DisplayName = "Domain Core Should Not Have Any Dependencies")]
FILE: tests/Equinox.Tests.Architecture/GeneralPatternTests.cs
class GeneralPatternTests (line 6) | public class GeneralPatternTests
method BaseClasses_MustBe_Abstract (line 8) | [Fact(DisplayName = "Base Classes Must Be Abstract")]
method Interfaces_MustStarts_WithI (line 28) | [Fact(DisplayName = "Interfaces Must Starts With I")]
FILE: tests/Equinox.Tests.Architecture/Support/ShouldUseDependencyInjectionRule.cs
class ShouldUseDependencyInjectionRule (line 6) | public class ShouldUseDependencyInjectionRule : ICustomRule
method MeetsRule (line 8) | public bool MeetsRule(TypeDefinition type)
FILE: tests/Equinox.Tests.Architecture/Support/TestOutputHelperTextWriter.cs
class TestOutputHelperTextWriter (line 6) | public class TestOutputHelperTextWriter(ITestOutputHelper output) : Text...
method WriteLine (line 10) | public override void WriteLine(string? value)
FILE: tests/Equinox.Tests.Architecture/Support/TestsSupport.cs
class TestsSupport (line 14) | public class TestsSupport
method GetAllProjectAssemblies (line 16) | public static IEnumerable<Assembly> GetAllProjectAssemblies()
FILE: tests/Equinox.Tests.Architecture/WebApplicationTests.cs
class WebApplicationTests (line 6) | public class WebApplicationTests
method Application_ShouldNotHave_DataAccessDependencies (line 8) | [Fact(DisplayName = "Web Application Should Not Have Data Dependencies")]
Condensed preview — 179 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,480K chars).
[
{
"path": ".dockerignore",
"chars": 316,
"preview": "**/.classpath\n**/.dockerignore\n**/.env\n**/.git\n**/.gitignore\n**/.project\n**/.settings\n**/.toolstarget\n**/.vs\n**/.vscode\n"
},
{
"path": ".editorconfig",
"chars": 309,
"preview": "# Remove unused using directives\ndotnet_diagnostic.CS8019.severity = error\n\n# Unused variables\ndotnet_diagnostic.IDE0059"
},
{
"path": ".gitattributes",
"chars": 2518,
"preview": "###############################################################################\n# Set default behavior to automatically "
},
{
"path": ".github/FUNDING.yml",
"chars": 69,
"preview": "# These are supported funding model platforms\n\npatreon: eduardopires\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 834,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/custom.md",
"chars": 145,
"preview": "---\nname: Custom issue template\nabout: Describe this issue template's purpose here.\ntitle: ''\nlabels: ''\nassignees: ''\n\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 595,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".github/workflows/dotnet-core.yml",
"chars": 499,
"preview": "name: .NET Core\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n build:\n\n runs"
},
{
"path": ".gitignore",
"chars": 3755,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User"
},
{
"path": "AGENTS.md",
"chars": 2388,
"preview": "# AGENTS Setup Guide\n\nThis repository requires specific environment configuration to build and run .NET 9.0 projects. **"
},
{
"path": "Equinox.sln",
"chars": 7969,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.9.3462"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2016 Eduardo Pires\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 4956,
"preview": "<img src=\"https://github.com/user-attachments/assets/f078a9b9-bf99-48f6-a7a4-50403f33a4b0\" alt=\"Equinox Project\" width=\""
},
{
"path": "docs/Architecture.dgml",
"chars": 48732,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<DirectedGraph DataVirtualized=\"True\" Layout=\"Sugiyama\" ZoomLevel=\"-1\" xmlns=\"ht"
},
{
"path": "docs/_config.yml",
"chars": 202,
"preview": "title: The Equinox Project\ndescription: Full ASP.NET Core 3.1 application with DDD, CQRS and Event Sourcing\ngoogle_analy"
},
{
"path": "docs/index.md",
"chars": 4049,
"preview": "<img src=\"https://www.eduardopires.net.br/imagens/EquinoxLogoPequenoFundoBranco.png\" alt=\"Equinox Project\"> \r\n\r\n\r\nWhat i"
},
{
"path": "src/Equinox.Application/Equinox.Application.csproj",
"chars": 335,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Null"
},
{
"path": "src/Equinox.Application/EventSourcedNormalizers/CustomerHistory.cs",
"chars": 3116,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing Equinox.Domain.Core.Ev"
},
{
"path": "src/Equinox.Application/EventSourcedNormalizers/CustomerHistoryData.cs",
"chars": 404,
"preview": "namespace Equinox.Application.EventSourcedNormalizers\n{\n public class CustomerHistoryData\n {\n public strin"
},
{
"path": "src/Equinox.Application/Extensions/CustomerExtensions.cs",
"chars": 1592,
"preview": "using Equinox.Application.ViewModels;\nusing Equinox.Domain.Commands;\nusing Equinox.Domain.Models;\nusing System.Collecti"
},
{
"path": "src/Equinox.Application/Interfaces/ICustomerAppService.cs",
"chars": 695,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Application.EventSourcedNor"
},
{
"path": "src/Equinox.Application/Services/CustomerAppService.cs",
"chars": 2261,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Application.EventSourcedNor"
},
{
"path": "src/Equinox.Application/ViewModels/CustomerViewModel.cs",
"chars": 885,
"preview": "using System;\nusing System.ComponentModel;\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Equinox.Application."
},
{
"path": "src/Equinox.Domain/Commands/CustomerCommand.cs",
"chars": 356,
"preview": "using System;\nusing NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Commands\n{\n public abstract class CustomerComman"
},
{
"path": "src/Equinox.Domain/Commands/CustomerCommandHandler.cs",
"chars": 3289,
"preview": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Equinox.Domain.Events;\nusing Equinox.Domain.I"
},
{
"path": "src/Equinox.Domain/Commands/RegisterNewCustomerCommand.cs",
"chars": 561,
"preview": "using System;\nusing Equinox.Domain.Commands.Validations;\n\nnamespace Equinox.Domain.Commands\n{\n public class Register"
},
{
"path": "src/Equinox.Domain/Commands/RemoveCustomerCommand.cs",
"chars": 472,
"preview": "using System;\nusing Equinox.Domain.Commands.Validations;\n\nnamespace Equinox.Domain.Commands\n{\n public class RemoveCu"
},
{
"path": "src/Equinox.Domain/Commands/UpdateCustomerCommand.cs",
"chars": 576,
"preview": "using System;\nusing Equinox.Domain.Commands.Validations;\n\nnamespace Equinox.Domain.Commands\n{\n public class UpdateCu"
},
{
"path": "src/Equinox.Domain/Commands/Validations/CustomerValidation.cs",
"chars": 1137,
"preview": "using System;\nusing FluentValidation;\n\nnamespace Equinox.Domain.Commands.Validations\n{\n public abstract class Custom"
},
{
"path": "src/Equinox.Domain/Commands/Validations/RegisterNewCustomerCommandValidation.cs",
"chars": 329,
"preview": "namespace Equinox.Domain.Commands.Validations\n{\n public class RegisterNewCustomerCommandValidation : CustomerValidat"
},
{
"path": "src/Equinox.Domain/Commands/Validations/RemoveCustomerCommandValidation.cs",
"chars": 250,
"preview": "namespace Equinox.Domain.Commands.Validations\n{\n public class RemoveCustomerCommandValidation : CustomerValidation<R"
},
{
"path": "src/Equinox.Domain/Commands/Validations/UpdateCustomerCommandValidation.cs",
"chars": 340,
"preview": "namespace Equinox.Domain.Commands.Validations\n{\n public class UpdateCustomerCommandValidation : CustomerValidation<U"
},
{
"path": "src/Equinox.Domain/Equinox.Domain.csproj",
"chars": 690,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Null"
},
{
"path": "src/Equinox.Domain/Events/CustomerEventHandler.cs",
"chars": 949,
"preview": "using NetDevPack.SimpleMediator.Core.Interfaces;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Equin"
},
{
"path": "src/Equinox.Domain/Events/CustomerRegisteredEvent.cs",
"chars": 588,
"preview": "using System;\nusing NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Events\n{\n public class CustomerRegisteredEvent :"
},
{
"path": "src/Equinox.Domain/Events/CustomerRemovedEvent.cs",
"chars": 291,
"preview": "using System;\nusing NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Events\n{\n public class CustomerRemovedEvent : Ev"
},
{
"path": "src/Equinox.Domain/Events/CustomerUpdatedEvent.cs",
"chars": 582,
"preview": "using System;\nusing NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Events\n{\n public class CustomerUpdatedEvent : Ev"
},
{
"path": "src/Equinox.Domain/Interfaces/ICustomerRepository.cs",
"chars": 502,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Domain.Models;\nusing NetDev"
},
{
"path": "src/Equinox.Domain/Models/Customer.cs",
"chars": 575,
"preview": "using System;\nusing NetDevPack.Domain;\n\nnamespace Equinox.Domain.Models\n{\n public class Customer : Entity, IAggregat"
},
{
"path": "src/Equinox.Domain.Core/Equinox.Domain.Core.csproj",
"chars": 241,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Null"
},
{
"path": "src/Equinox.Domain.Core/Events/IEventStore.cs",
"chars": 165,
"preview": "using NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Core.Events\n{\n public interface IEventStore\n {\n void"
},
{
"path": "src/Equinox.Domain.Core/Events/StoredEvent.cs",
"chars": 610,
"preview": "using System;\nusing NetDevPack.Messaging;\n\nnamespace Equinox.Domain.Core.Events\n{\n public class StoredEvent : Event\n"
},
{
"path": "src/Equinox.Infra.CrossCutting.Bus/Equinox.Infra.CrossCutting.Bus.csproj",
"chars": 264,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Null"
},
{
"path": "src/Equinox.Infra.CrossCutting.Bus/InMemoryBus.cs",
"chars": 880,
"preview": "using System.Threading.Tasks;\nusing Equinox.Domain.Core.Events;\nusing FluentValidation.Results;\nusing NetDevPack.Mediat"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/API/AppJwtSettings.cs",
"chars": 307,
"preview": "namespace Equinox.Infra.CrossCutting.Identity.API\n{\n public class AppJwtSettings\n {\n public string SecretK"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/API/JwtBuilder.cs",
"chars": 4517,
"preview": "using Equinox.Infra.CrossCutting.Identity.Models;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.IdentityModel.To"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizationValidation.cs",
"chars": 548,
"preview": "using System.Linq;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Equinox.Infra.CrossCutting.Identity.Authorization\n{\n "
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Authorization/CustomAuthorizeAttribute.cs",
"chars": 414,
"preview": "using System.Security.Claims;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Equinox.Infra.CrossCutting.Identity.Authorizat"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Authorization/RequerimentClaimFilter.cs",
"chars": 859,
"preview": "using System.Security.Claims;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\n\nnamespace Equino"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Configuration/AspNetIdentityConfig.cs",
"chars": 5230,
"preview": "using Equinox.Infra.CrossCutting.Identity.API;\nusing Equinox.Infra.CrossCutting.Identity.Data;\nusing Equinox.Infra.Cros"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Data/EquinoxIdentityContext.cs",
"chars": 1536,
"preview": "using Microsoft.AspNetCore.Identity.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFra"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Equinox.Infra.CrossCutting.Identity.csproj",
"chars": 1292,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Nul"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Extensions/ClaimsPrincipalExtensions.cs",
"chars": 1913,
"preview": "using System.Security.Claims;\nusing System;\nusing System.IdentityModel.Tokens.Jwt;\n\nnamespace Equinox.Infra.CrossCuttin"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.Designer.cs",
"chars": 9607,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.CrossCutting.Identity.Data;\nusing Microsoft.EntityFrameworkCore"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Migrations/20250408033115_SQLite.cs",
"chars": 9824,
"preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Equinox.Infra.CrossCutting."
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Migrations/EquinoxIdentityContextModelSnapshot.cs",
"chars": 9530,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.CrossCutting.Identity.Data;\nusing Microsoft.EntityFrameworkCore"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Models/LoginUser.cs",
"chars": 339,
"preview": "using System.ComponentModel.DataAnnotations;\n\nnamespace Equinox.Infra.CrossCutting.Identity.Models\n{\n public class L"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Models/RegisterUser.cs",
"chars": 425,
"preview": "using System.ComponentModel.DataAnnotations;\n\nnamespace Equinox.Infra.CrossCutting.Identity.Models\n{\n public class R"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Models/UserClaim.cs",
"chars": 180,
"preview": "namespace Equinox.Infra.CrossCutting.Identity.Models\n{\n public class UserClaim\n {\n public string Value { g"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Models/UserResponse.cs",
"chars": 292,
"preview": "namespace Equinox.Infra.CrossCutting.Identity.Models\n{\n public class UserResponse\n {\n public string Access"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/Models/UserToken.cs",
"chars": 273,
"preview": "using System.Collections.Generic;\n\nnamespace Equinox.Infra.CrossCutting.Identity.Models\n{\n public class UserToken\n "
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/User/AspNetUser.cs",
"chars": 1307,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Security.Claims;\nusing Equinox.Infra.CrossCutting.Identity"
},
{
"path": "src/Equinox.Infra.CrossCutting.Identity/User/IAspNetUser.cs",
"chars": 448,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Security.Claims;\nusing Microsoft.AspNetCore.Http;\n\nnamespa"
},
{
"path": "src/Equinox.Infra.CrossCutting.IoC/Equinox.Infra.CrossCutting.IoC.csproj",
"chars": 422,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Nul"
},
{
"path": "src/Equinox.Infra.CrossCutting.IoC/NativeInjectorBootStrapper.cs",
"chars": 2341,
"preview": "using Equinox.Application.Interfaces;\nusing Equinox.Application.Services;\nusing Equinox.Domain.Commands;\nusing Equinox."
},
{
"path": "src/Equinox.Infra.Data/Context/EquinoxContext.cs",
"chars": 3209,
"preview": "using System.Linq;\nusing System.Threading.Tasks;\nusing Equinox.Domain.Models;\nusing Equinox.Infra.Data.Mappings;\nusing "
},
{
"path": "src/Equinox.Infra.Data/Context/EventStoreSQLContext.cs",
"chars": 588,
"preview": "using Equinox.Domain.Core.Events;\nusing Equinox.Infra.Data.Mappings;\nusing Microsoft.EntityFrameworkCore;\n\n\nnamespace E"
},
{
"path": "src/Equinox.Infra.Data/Equinox.Infra.Data.csproj",
"chars": 992,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</Null"
},
{
"path": "src/Equinox.Infra.Data/EventSourcing/SqlEventStore.cs",
"chars": 1294,
"preview": "using Equinox.Domain.Core.Events;\nusing Equinox.Infra.CrossCutting.Identity.User;\nusing Equinox.Infra.Data.Repository.E"
},
{
"path": "src/Equinox.Infra.Data/Mappings/CustomerMap.cs",
"chars": 727,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Equinox.Domain.Models;"
},
{
"path": "src/Equinox.Infra.Data/Mappings/StoredEventMap.cs",
"chars": 580,
"preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Equinox.Domain.Core.Ev"
},
{
"path": "src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.Designer.cs",
"chars": 1556,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\nusing Micros"
},
{
"path": "src/Equinox.Infra.Data/Migrations/20250408031104_SQLite.cs",
"chars": 1183,
"preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Equinox.Infra.Data.Migratio"
},
{
"path": "src/Equinox.Infra.Data/Migrations/EquinoxContextModelSnapshot.cs",
"chars": 1471,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\nusing Micros"
},
{
"path": "src/Equinox.Infra.Data/Migrations/EventStoreSQL/EventStoreSQLContextModelSnapshot.cs",
"chars": 1599,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\nusing Micros"
},
{
"path": "src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.Designer.cs",
"chars": 1678,
"preview": "// <auto-generated />\nusing System;\nusing Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\nusing Micros"
},
{
"path": "src/Equinox.Infra.Data/Migrations/EventStoreSql/20250408031128_SQLite.cs",
"chars": 1329,
"preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Equinox.Infra.Data.Migratio"
},
{
"path": "src/Equinox.Infra.Data/Repository/CustomerRepository.cs",
"chars": 1433,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Domain.Interfaces;\nusing Eq"
},
{
"path": "src/Equinox.Infra.Data/Repository/EventSourcing/EventStoreSQLRepository.cs",
"chars": 958,
"preview": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Domain.C"
},
{
"path": "src/Equinox.Infra.Data/Repository/EventSourcing/IEventStoreRepository.cs",
"chars": 338,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Equinox.Domain.Core.Events;\n\nnamesp"
},
{
"path": "src/Equinox.Infra.Data/appsettings.json",
"chars": 325,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection"
},
{
"path": "src/Equinox.Services.Api/Configurations/ApiConfig.cs",
"chars": 714,
"preview": "namespace Equinox.Services.Api.Configurations\n{\n public static class ApiConfig\n {\n public static WebApplic"
},
{
"path": "src/Equinox.Services.Api/Configurations/DatabaseConfig.cs",
"chars": 762,
"preview": "using Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Equinox.Services.Api.Configurations\n{"
},
{
"path": "src/Equinox.Services.Api/Configurations/DependencyInjectionConfig.cs",
"chars": 466,
"preview": "using Equinox.Infra.CrossCutting.IoC;\n\nnamespace Equinox.Services.Api.Configurations\n{\n public static class Dependen"
},
{
"path": "src/Equinox.Services.Api/Configurations/SwaggerConfig.cs",
"chars": 3476,
"preview": "using Microsoft.OpenApi.Models;\n\nnamespace Equinox.Services.Api.Configurations\n{\n public static class SwaggerConfig\n"
},
{
"path": "src/Equinox.Services.Api/Controllers/AccountController.cs",
"chars": 2800,
"preview": "using Equinox.Infra.CrossCutting.Identity.API;\nusing Equinox.Infra.CrossCutting.Identity.Models;\nusing Microsoft.AspNet"
},
{
"path": "src/Equinox.Services.Api/Controllers/ApiController.cs",
"chars": 1563,
"preview": "using FluentValidation.Results;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\n\nnamespace"
},
{
"path": "src/Equinox.Services.Api/Controllers/CustomerController.cs",
"chars": 2124,
"preview": "using Equinox.Application.EventSourcedNormalizers;\nusing Equinox.Application.Interfaces;\nusing Equinox.Application.ViewM"
},
{
"path": "src/Equinox.Services.Api/Dockerfile",
"chars": 782,
"preview": "#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for fast"
},
{
"path": "src/Equinox.Services.Api/Equinox.Services.Api.csproj",
"chars": 1586,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</"
},
{
"path": "src/Equinox.Services.Api/Program.cs",
"chars": 906,
"preview": "using Equinox.Infra.CrossCutting.Identity.Configuration;\nusing Equinox.Services.Api.Configurations;\nusing Microsoft.AspN"
},
{
"path": "src/Equinox.Services.Api/Properties/launchSettings.json",
"chars": 1258,
"preview": "{\n \"iisSettings\": {\n \"windowsAuthentication\": false,\n \"anonymousAuthentication\": true,\n \"iisExpress\": {\n "
},
{
"path": "src/Equinox.Services.Api/appsettings.Development.json",
"chars": 546,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection="
},
{
"path": "src/Equinox.Services.Api/appsettings.Staging.json",
"chars": 546,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection="
},
{
"path": "src/Equinox.Services.Api/appsettings.Testing.json",
"chars": 546,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection="
},
{
"path": "src/Equinox.Services.Api/appsettings.json",
"chars": 182,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft\": \"Warning\",\n \"Microsoft.Hostin"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/IdentityHostingStartup.cs",
"chars": 357,
"preview": "[assembly: HostingStartup(typeof(Equinox.UI.Web.Areas.Identity.IdentityHostingStartup))]\nnamespace Equinox.UI.Web.Areas"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Login.cshtml",
"chars": 3708,
"preview": "@page\n@model LoginModel\n\n@{\n ViewData[\"Title\"] = \"Log in\";\n}\n\n<h1>@ViewData[\"Title\"]</h1>\n<div class=\"row\">\n <div"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Login.cshtml.cs",
"chars": 3783,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.Linq;\nusing S"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Logout.cshtml",
"chars": 593,
"preview": "@page\n@model LogoutModel\n@{\n ViewData[\"Title\"] = \"Log out\";\n}\n\n<header>\n <h1>@ViewData[\"Title\"]</h1>\n @{\n "
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Logout.cshtml.cs",
"chars": 1185,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNet"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Register.cshtml",
"chars": 2761,
"preview": "@page\n@model RegisterModel\n@{\n ViewData[\"Title\"] = \"Register\";\n}\n\n<h1>@ViewData[\"Title\"]</h1>\n\n<div class=\"row\">\n "
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/Register.cshtml.cs",
"chars": 4073,
"preview": "using System.ComponentModel.DataAnnotations;\nusing System.Security.Claims;\nusing System.Text;\nusing Microsoft.AspNetCor"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/Account/_ViewImports.cshtml",
"chars": 51,
"preview": "@using Equinox.UI.Web.Areas.Identity.Pages.Account"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml",
"chars": 1191,
"preview": "<environment include=\"Development\">\n <script src=\"~/Identity/lib/jquery-validation/dist/jquery.validate.js\"></script"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/_ViewImports.cshtml",
"chars": 171,
"preview": "@using Microsoft.AspNetCore.Identity\n@using Equinox.UI.Web.Areas.Identity\n@using Equinox.UI.Web.Areas.Identity.Pages\n@a"
},
{
"path": "src/Equinox.UI.Web/Areas/Identity/Pages/_ViewStart.cshtml",
"chars": 51,
"preview": "@{\n Layout = \"/Views/Shared/_Layout.cshtml\";\n}\n"
},
{
"path": "src/Equinox.UI.Web/Configurations/DatabaseConfig.cs",
"chars": 1465,
"preview": "using Equinox.Infra.Data.Context;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Equinox.UI.Web.Configurations\n{\n p"
},
{
"path": "src/Equinox.UI.Web/Configurations/DbMigrationHelpers.cs",
"chars": 3921,
"preview": "using Equinox.Domain.Core.Events;\nusing Equinox.Domain.Events;\nusing Equinox.Domain.Models;\nusing Equinox.Infra.CrossCu"
},
{
"path": "src/Equinox.UI.Web/Configurations/DependencyInjectionConfig.cs",
"chars": 387,
"preview": "using Equinox.Infra.CrossCutting.IoC;\n\nnamespace Equinox.UI.Web.Configurations\n{\n public static class DependencyInje"
},
{
"path": "src/Equinox.UI.Web/Configurations/MvcConfig.cs",
"chars": 885,
"preview": "using Microsoft.AspNetCore.Mvc;\n\nnamespace Equinox.UI.Web.Configurations\n{\n public static class MvcConfig\n {\n "
},
{
"path": "src/Equinox.UI.Web/Controllers/BaseController.cs",
"chars": 778,
"preview": "using FluentValidation.Results;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Equinox.UI.Web.Controllers\n{\n public abst"
},
{
"path": "src/Equinox.UI.Web/Controllers/CustomerController.cs",
"chars": 4018,
"preview": "using Equinox.Application.Interfaces;\nusing Equinox.Application.ViewModels;\nusing Equinox.Infra.CrossCutting.Identity.Au"
},
{
"path": "src/Equinox.UI.Web/Controllers/HomeController.cs",
"chars": 1329,
"preview": "using Equinox.UI.Web.Models;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Equinox.UI.Web.Controllers\n{\n public class H"
},
{
"path": "src/Equinox.UI.Web/Data/ApplicationDbContext.cs",
"chars": 332,
"preview": "using Microsoft.AspNetCore.Identity.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Equinox.UI.Web"
},
{
"path": "src/Equinox.UI.Web/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs",
"chars": 10480,
"preview": "// <auto-generated />\nusing Equinox.UI.Web.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCor"
},
{
"path": "src/Equinox.UI.Web/Data/Migrations/00000000000000_CreateIdentitySchema.cs",
"chars": 9511,
"preview": "using Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\nnamespace Equinox.UI.Web"
},
{
"path": "src/Equinox.UI.Web/Data/Migrations/ApplicationDbContextModelSnapshot.cs",
"chars": 10400,
"preview": "// <auto-generated />\nusing Equinox.UI.Web.Data;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCor"
},
{
"path": "src/Equinox.UI.Web/Dockerfile",
"chars": 712,
"preview": "#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for fast"
},
{
"path": "src/Equinox.UI.Web/Equinox.UI.Web.csproj",
"chars": 1752,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\t<PropertyGroup>\n\t\t<TargetFramework>net9.0</TargetFramework>\n\t\t<Nullable>disable</"
},
{
"path": "src/Equinox.UI.Web/Models/ErrorViewModel.cs",
"chars": 209,
"preview": "namespace Equinox.UI.Web.Models\n{\n public class ErrorViewModel\n {\n public int ErrorCode { get; set; }\n "
},
{
"path": "src/Equinox.UI.Web/Program.cs",
"chars": 1053,
"preview": "using Equinox.UI.Web.Configurations;\nusing Equinox.Infra.CrossCutting.Identity.Configuration;\n\nvar builder = WebApplicat"
},
{
"path": "src/Equinox.UI.Web/Properties/launchSettings.json",
"chars": 1670,
"preview": "{\n \"iisSettings\": {\n \"windowsAuthentication\": false,\n \"anonymousAuthentication\": true,\n \"iisExpress\": {\n "
},
{
"path": "src/Equinox.UI.Web/Properties/serviceDependencies.json",
"chars": 114,
"preview": "{\n \"dependencies\": {\n \"mssql1\": {\n \"type\": \"mssql\",\n \"connectionId\": \"DefaultConnection\"\n }\n }\n}"
},
{
"path": "src/Equinox.UI.Web/Properties/serviceDependencies.local.json",
"chars": 120,
"preview": "{\n \"dependencies\": {\n \"mssql1\": {\n \"type\": \"mssql.local\",\n \"connectionId\": \"DefaultConnection\"\n }\n }\n}"
},
{
"path": "src/Equinox.UI.Web/ScaffoldingReadMe.txt",
"chars": 157,
"preview": "Support for ASP.NET Core Identity was added to your project.\n\nFor setup and configuration information, see https://go.m"
},
{
"path": "src/Equinox.UI.Web/ViewComponents/SummaryViewComponent.cs",
"chars": 244,
"preview": "using Microsoft.AspNetCore.Mvc;\n\nnamespace Equinox.UI.Web.ViewComponents\n{\n public class SummaryViewComponent : View"
},
{
"path": "src/Equinox.UI.Web/Views/Customer/Create.cshtml",
"chars": 1686,
"preview": "@model Equinox.Application.ViewModels.CustomerViewModel\n\n@{\n ViewData[\"Title\"] = \"Register new Customer\";\n}\n\n<h2>@Vie"
},
{
"path": "src/Equinox.UI.Web/Views/Customer/Delete.cshtml",
"chars": 1102,
"preview": "@model Equinox.Application.ViewModels.CustomerViewModel\n\n@{\n ViewData[\"Title\"] = \"Delete Customer\";\n}\n\n<h2>@ViewData["
},
{
"path": "src/Equinox.UI.Web/Views/Customer/Details.cshtml",
"chars": 848,
"preview": "@model Equinox.Application.ViewModels.CustomerViewModel\n\n@{\n ViewData[\"Title\"] = \"Customer Details\";\n}\n\n<h2>@ViewData"
},
{
"path": "src/Equinox.UI.Web/Views/Customer/Edit.cshtml",
"chars": 1712,
"preview": "@model Equinox.Application.ViewModels.CustomerViewModel\n\n@{\n ViewData[\"Title\"] = \"Edit Customer\";\n}\n\n<h2>@ViewData[\"T"
},
{
"path": "src/Equinox.UI.Web/Views/Customer/Index.cshtml",
"chars": 4730,
"preview": "@model IEnumerable<Equinox.Application.ViewModels.CustomerViewModel>\n\n@{\n ViewData[\"Title\"] = \"Customer Management\";\n"
},
{
"path": "src/Equinox.UI.Web/Views/Home/Index.cshtml",
"chars": 1206,
"preview": "@{\n ViewData[\"Title\"] = \"Welcome\";\n}\n\n<div>\n <img src=\"~/images/banner1.svg\" alt=\"ASP.NET\" class=\"img-responsive\""
},
{
"path": "src/Equinox.UI.Web/Views/Home/Privacy.cshtml",
"chars": 136,
"preview": "@{\n ViewData[\"Title\"] = \"Privacy Policy\";\n}\n<h1>@ViewData[\"Title\"]</h1>\n\n<p>Use this page to detail your site's priv"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/Components/Summary/Default.cshtml",
"chars": 535,
"preview": "\n@if (ViewData.ModelState.ErrorCount > 0)\n{\n <div class=\"alert alert-danger\">\n <button type=\"button\" class=\"c"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/Error.cshtml",
"chars": 400,
"preview": "@model Equinox.UI.Web.Models.ErrorViewModel\n@{\n ViewData[\"Title\"] = \"Oops! An error has occurred!\";\n}\n\n@{\n if (Mo"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/_CookieConsentPartial.cshtml",
"chars": 991,
"preview": "@using Microsoft.AspNetCore.Http.Features\n\n@{\n var consentFeature = Context.Features.Get<ITrackingConsentFeature>();"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/_Layout.cshtml",
"chars": 2318,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-wi"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/_LoginPartial.cshtml",
"chars": 1032,
"preview": "@using Microsoft.AspNetCore.Identity\n@inject SignInManager<IdentityUser> SignInManager\n@inject UserManager<IdentityUser"
},
{
"path": "src/Equinox.UI.Web/Views/Shared/_ValidationScriptsPartial.cshtml",
"chars": 894,
"preview": "<environment names=\"Development\">\n <script src=\"~/lib/jquery-validation/dist/jquery.validate.js\"></script>\n <scri"
},
{
"path": "src/Equinox.UI.Web/Views/_ViewImports.cshtml",
"chars": 110,
"preview": "@using Equinox.UI.Web\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n@addTagHelper \"*, Equinox.UI.Web\"\n"
},
{
"path": "src/Equinox.UI.Web/Views/_ViewStart.cshtml",
"chars": 30,
"preview": "@{\n Layout = \"_Layout\";\n}\n"
},
{
"path": "src/Equinox.UI.Web/appsettings.Development.json",
"chars": 445,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Data Source=EquinoxProject.db\"\n },\n \"Logging\": {\n \"LogLevel\": "
},
{
"path": "src/Equinox.UI.Web/appsettings.Staging.json",
"chars": 517,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection="
},
{
"path": "src/Equinox.UI.Web/appsettings.Testing.json",
"chars": 517,
"preview": "{\n \"ConnectionStrings\": {\n \"DefaultConnection\": \"Server=(localdb)\\\\mssqllocaldb;Database=Equinox;Trusted_Connection="
},
{
"path": "src/Equinox.UI.Web/appsettings.json",
"chars": 160,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft\": \"Warning\",\n \"Microsoft.Hosti"
},
{
"path": "src/Equinox.UI.Web/bundleconfig.json",
"chars": 601,
"preview": "// Configure bundling and minification for the project.\n// More info at https://go.microsoft.com/fwlink/?LinkId=808241\n"
},
{
"path": "src/Equinox.UI.Web/wwwroot/_references.js",
"chars": 341,
"preview": "/// <autosync enabled=\"true\" />\n/// <reference path=\"js/site.js\" />\n/// <reference path=\"lib/bootstrap/dist/js/bootstra"
},
{
"path": "src/Equinox.UI.Web/wwwroot/css/site.css",
"chars": 1344,
"preview": "/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\nfor details"
},
{
"path": "src/Equinox.UI.Web/wwwroot/js/site.js",
"chars": 224,
"preview": "// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\n// for deta"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/.bower.json",
"chars": 918,
"preview": "{\n \"name\": \"bootstrap\",\n \"description\": \"The most popular front-end framework for developing responsive, mobile first "
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/LICENSE",
"chars": 1131,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2011-2018 Twitter, Inc.\nCopyright (c) 2011-2018 The Bootstrap Authors\n\nPermission i"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css",
"chars": 64548,
"preview": "/*!\n * Bootstrap Grid v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css",
"chars": 4897,
"preview": "/*!\n * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 201"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css",
"chars": 26132,
"preview": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://gi"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/css/bootstrap.css",
"chars": 192348,
"preview": "/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 "
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js",
"chars": 222909,
"preview": "/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors (https://github.com/t"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.js",
"chars": 131637,
"preview": "/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors (https://github.com/t"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/bootstrap/dist/js/npm.js",
"chars": 484,
"preview": "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\nrequ"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery/.bower.json",
"chars": 523,
"preview": "{\n \"name\": \"jquery\",\n \"main\": \"dist/jquery.js\",\n \"license\": \"MIT\",\n \"ignore\": [\n \"package.json\"\n ],\n \"keywords\""
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery/LICENSE.txt",
"chars": 1605,
"preview": "Copyright JS Foundation and other contributors, https://js.foundation/\n\nThis software consists of voluntary contribution"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery/dist/jquery.js",
"chars": 287630,
"preview": "/*!\n * jQuery JavaScript Library v3.5.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * C"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation/.bower.json",
"chars": 885,
"preview": "{\n \"name\": \"jquery-validation\",\n \"homepage\": \"http://jqueryvalidation.org/\",\n \"repository\": {\n \"type\": \"git\",\n "
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation/LICENSE.md",
"chars": 1094,
"preview": "The MIT License (MIT)\n=====================\n\nCopyright Jörn Zaefferer\n\nPermission is hereby granted, free of charge, to "
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation/dist/additional-methods.js",
"chars": 42006,
"preview": "/*!\n * jQuery Validation Plugin v1.17.0\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2017 Jörn Zaefferer\n * R"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation/dist/jquery.validate.js",
"chars": 48675,
"preview": "/*!\n * jQuery Validation Plugin v1.17.0\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2017 Jörn Zaefferer\n * R"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation-unobtrusive/.bower.json",
"chars": 1100,
"preview": "{\n \"name\": \"jquery-validation-unobtrusive\",\n \"version\": \"3.2.6\",\n \"homepage\": \"https://github.com/aspnet/jquery-valid"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt",
"chars": 575,
"preview": "Copyright (c) .NET Foundation. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
"chars": 19366,
"preview": "// Unobtrusive validation support library for jQuery and jQuery Validate\n// Copyright (c) .NET Foundation. All rights re"
},
{
"path": "src/Equinox.UI.Web/wwwroot/lib/qrcode.js",
"chars": 33148,
"preview": "/**\n * @fileoverview\n * - Using the 'QRCode for Javascript library'\n * - Fixed dataset of 'QRCode for Javascript library"
},
{
"path": "tests/Equinox.Tests.Architecture/DataBaseTests.cs",
"chars": 1134,
"preview": "using Equinox.Tests.Architecture.Support;\nusing NetArchTest.Rules;\nusing Xunit.Abstractions;\n\nnamespace Equinox.Tests.A"
},
{
"path": "tests/Equinox.Tests.Architecture/DomainTests.cs",
"chars": 2690,
"preview": "using Equinox.Domain.Core.Events;\nusing Equinox.Domain.Models;\nusing NetArchTest.Rules;\n\nnamespace Equinox.Tests.Archit"
},
{
"path": "tests/Equinox.Tests.Architecture/Equinox.Tests.Architecture.csproj",
"chars": 1965,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>net9.0</TargetFramework>\n <ImplicitUsings>e"
},
{
"path": "tests/Equinox.Tests.Architecture/GeneralPatternTests.cs",
"chars": 1466,
"preview": "using Equinox.Tests.Architecture.Support;\nusing NetArchTest.Rules;\n\nnamespace Equinox.Tests.Architecture;\n\npublic class"
},
{
"path": "tests/Equinox.Tests.Architecture/Support/ShouldUseDependencyInjectionRule.cs",
"chars": 769,
"preview": "using Mono.Cecil;\nusing NetArchTest.Rules;\n\nnamespace Equinox.Tests.Architecture.Support;\n\npublic class ShouldUseDepend"
},
{
"path": "tests/Equinox.Tests.Architecture/Support/TestOutputHelperTextWriter.cs",
"chars": 404,
"preview": "using System.Text;\nusing Xunit.Abstractions;\n\nnamespace Equinox.Tests.Architecture.Support;\n\npublic class TestOutputHel"
},
{
"path": "tests/Equinox.Tests.Architecture/Support/TestsSupport.cs",
"chars": 1238,
"preview": "using Equinox.Application.Services;\nusing Equinox.Domain.Core.Events;\nusing Equinox.Domain.Models;\nusing Equinox.Infra."
},
{
"path": "tests/Equinox.Tests.Architecture/WebApplicationTests.cs",
"chars": 848,
"preview": "using Equinox.UI.Web.Controllers;\nusing NetArchTest.Rules;\n\nnamespace Equinox.Tests.Architecture;\n\npublic class WebAppl"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the EduardoPires/EquinoxProject GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 179 files (1.3 MB), approximately 378.9k tokens, and a symbol index with 515 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.