diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e17f4f2..9ab9dbc 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -250,11 +250,119 @@ return player; // Let caller handle null - Use route parameters for resource identification - Apply validation before processing requests +## 🛠️ Essential Commands & Workflows + +### Build & Run +```bash +# Build the solution +dotnet build + +# Run the API (hot reload enabled) +dotnet watch run --project src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj + +# Access Swagger UI (Development only) +# https://localhost:9000/swagger/index.html + +# Health check endpoint +# https://localhost:9000/health +``` + +### Testing +```bash +# Run all tests +dotnet test + +# Run tests with coverage +dotnet test --results-directory "coverage" --collect:"XPlat Code Coverage" --settings .runsettings + +# Run specific test category +dotnet test --filter "Category=Unit" +``` + +### Database Migrations +```bash +# Create a new migration +dotnet ef migrations add --project src/Dotnet.Samples.AspNetCore.WebApi + +# Apply migrations +dotnet ef database update --project src/Dotnet.Samples.AspNetCore.WebApi + +# Regenerate database with seed data +./scripts/run-migrations-and-copy-database.sh +``` + +**Important**: The `run-migrations-and-copy-database.sh` script: +- Resets the placeholder database file +- Runs all migrations +- Copies the generated database from `bin/Debug/net8.0/Data/` to `Data/` +- Requires `dotnet ef` CLI tool installed globally + +### Docker Operations +```bash +# Build the image +docker compose build + +# Start the app (with persistent volume) +docker compose up + +# Stop the app (preserve data) +docker compose down + +# Reset database (removes volume) +docker compose down -v +``` + +**Important**: The SQLite database is stored in a Docker volume for persistence. First run copies a pre-seeded database from the image to the volume. + +### Rate Limiting +- Configured via `RateLimiter` section in `appsettings.json` +- Default: 60 requests per 60 seconds (fixed window) +- Queue limit: 0 (immediate rejection when limit reached) + +## 🚨 Common Issues & Workarounds + +### Database Path Issues +- **SQLite database location**: `storage/players-sqlite3.db` relative to binary output +- **Container storage**: `/storage/players-sqlite3.db` (mounted volume) +- **Environment variable**: `STORAGE_PATH` can override the default path in containers + +### Validation Patterns +- **FluentValidation** runs in the validator class for input format/structure +- **Business rule validation** (e.g., unique squad number check) happens in the service layer +- This separation is intentional to keep validators focused on data structure, not business logic + +### Locking & Caching +- **DbContextPool** is used for performance - don't manually dispose DbContext +- **IMemoryCache** is cleared on data modifications using `Remove(CacheKey_RetrieveAsync)` +- Cache keys use `nameof()` for type safety + +### Test Configuration +- Test coverage excludes test projects via `.runsettings` configuration +- Coverage reports merge multiple Cobertura files into one +- `FluentAssertions` and `Moq` are standard testing libraries + +## 📝 Commit Message Conventions + +Follow **Conventional Commits** (): +- `feat:` - New features +- `fix:` - Bug fixes +- `chore:` - Maintenance tasks +- `docs:` - Documentation changes +- `test:` - Test additions or modifications +- `refactor:` - Code restructuring without behavior change + +**Constraints**: +- Header max length: 80 characters +- Body max line length: 80 characters +- Enforced via `commitlint.config.mjs` in CI/CD + ## 🚀 Future Evolution Considerations -- **Database Migration**: SQLite → PostgreSQL transition path -- **Authentication**: JWT Bearer token implementation ready -- **API Versioning**: URL-based versioning strategy -- **OpenAPI**: Comprehensive Swagger documentation -- **Monitoring**: Health checks and metrics endpoints -- **Containerization**: Docker multi-stage builds optimized +See open issues on GitHub for planned enhancements: +- **Clean Architecture Refactoring** ([#266](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/266)) - Migrate to Clean Architecture-inspired structure +- **PostgreSQL Support** ([#249](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/249)) - Add PostgreSQL to Docker Compose setup +- **.NET Aspire Integration** ([#256](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/256)) - Evaluate Aspire for dev-time orchestration and observability +- **JWT Authentication** ([#105](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/105)) - Implement Client Credentials Flow for protected routes +- **Global Exception Handling** ([#184](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/184)) - Add middleware with RFC 7807 Problem Details +- **Optimistic Concurrency** ([#65](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/65)) - Handle conflicts with application-managed tokens +- **Database Normalization** ([#125](https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/issues/125)) - Extract Position, Team, League into separate tables diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index bd62693..58d3ebc 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v6.0.0 - name: Set up .NET ${{ env.DOTNET_VERSION }} - uses: actions/setup-dotnet@v5.0.0 + uses: actions/setup-dotnet@v5.0.1 with: dotnet-version: ${{ env.DOTNET_VERSION }} # The action searches for packages.lock.json in the repository root, diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Configurations/AuthorizeCheckOperationFilter.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Configurations/AuthorizeCheckOperationFilter.cs index a78b116..31c710d 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Configurations/AuthorizeCheckOperationFilter.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Configurations/AuthorizeCheckOperationFilter.cs @@ -1,6 +1,6 @@ using System.Linq; using Microsoft.AspNetCore.Authorization; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Dotnet.Samples.AspNetCore.WebApi.Configurations @@ -25,23 +25,17 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) return; // Add security requirement (shows the lock icon) - operation.Security ??= new List(); - operation.Security.Add( - new OpenApiSecurityRequirement - { + // In Microsoft.OpenApi 2.x, use OpenApiSecuritySchemeReference instead of OpenApiSecurityScheme with nested Reference + if (operation is OpenApiOperation openApiOperation) + { + openApiOperation.Security ??= new List(); + openApiOperation.Security.Add( + new OpenApiSecurityRequirement { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = "Bearer", - Type = ReferenceType.SecurityScheme - } - }, - Array.Empty() + { new OpenApiSecuritySchemeReference("Bearer", null), new List() } } - } - ); + ); + } } } } diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj b/src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj index 3ac61c6..894bb1e 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj @@ -20,10 +20,10 @@ - + - + diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Extensions/ServiceCollectionExtensions.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Extensions/ServiceCollectionExtensions.cs index 59924c9..e5f8b34 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Extensions/ServiceCollectionExtensions.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Extensions/ServiceCollectionExtensions.cs @@ -8,7 +8,7 @@ using Dotnet.Samples.AspNetCore.WebApi.Validators; using FluentValidation; using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Serilog; namespace Dotnet.Samples.AspNetCore.WebApi.Extensions; diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/Utilities/SwaggerUtilities.cs b/src/Dotnet.Samples.AspNetCore.WebApi/Utilities/SwaggerUtilities.cs index d26c798..2cdba59 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/Utilities/SwaggerUtilities.cs +++ b/src/Dotnet.Samples.AspNetCore.WebApi/Utilities/SwaggerUtilities.cs @@ -1,5 +1,5 @@ using System.Reflection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Dotnet.Samples.AspNetCore.WebApi.Utilities; @@ -58,17 +58,7 @@ public static OpenApiSecurityRequirement ConfigureSecurityRequirement() { return new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Id = "Bearer", - Type = ReferenceType.SecurityScheme - } - }, - Array.Empty() - } + { new OpenApiSecuritySchemeReference("Bearer", null), new List() } }; } } diff --git a/src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json b/src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json index 89cf37b..0134a2d 100644 --- a/src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json +++ b/src/Dotnet.Samples.AspNetCore.WebApi/packages.lock.json @@ -131,13 +131,13 @@ }, "Serilog.Settings.Configuration": { "type": "Direct", - "requested": "[9.0.0, )", - "resolved": "9.0.0", - "contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==", + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "LNq+ibS1sbhTqPV1FIE69/9AJJbfaOhnaqkzcjFy95o+4U+STsta9mi97f1smgXsWYKICDeGUf8xUGzd/52/uA==", "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "9.0.0", - "Microsoft.Extensions.DependencyModel": "9.0.0", - "Serilog": "4.2.0" + "Microsoft.Extensions.Configuration.Binder": "10.0.0", + "Microsoft.Extensions.DependencyModel": "10.0.0", + "Serilog": "4.3.0" } }, "Serilog.Sinks.Console": { @@ -160,14 +160,14 @@ }, "Swashbuckle.AspNetCore": { "type": "Direct", - "requested": "[8.1.4, )", - "resolved": "8.1.4", - "contentHash": "qYk8VHyvs6wML+KXtjyCgS9Aj18mcm0ZtnJeNCTlj/DYQ7A3pfLIztQgLuZS/LEMYsrTo1lSKR3IIZ5/HzVCWA==", + "requested": "[10.0.1, )", + "resolved": "10.0.1", + "contentHash": "177+JNAV5TNvy8gLCdrcWBY9n2jdkxiHQDY4vhaExeqUpKrOqDatCcm/kW3kze60GqfnZ2NobD/IKiAPOL+CEw==", "dependencies": { - "Microsoft.Extensions.ApiDescription.Server": "6.0.5", - "Swashbuckle.AspNetCore.Swagger": "8.1.4", - "Swashbuckle.AspNetCore.SwaggerGen": "8.1.4", - "Swashbuckle.AspNetCore.SwaggerUI": "8.1.4" + "Microsoft.Extensions.ApiDescription.Server": "8.0.0", + "Swashbuckle.AspNetCore.Swagger": "10.0.1", + "Swashbuckle.AspNetCore.SwaggerGen": "10.0.1", + "Swashbuckle.AspNetCore.SwaggerUI": "10.0.1" } }, "Humanizer": { @@ -850,8 +850,8 @@ }, "Microsoft.Extensions.ApiDescription.Server": { "type": "Transitive", - "resolved": "6.0.5", - "contentHash": "Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==" + "resolved": "8.0.0", + "contentHash": "jDM3a95WerM8g6IcMiBXq1qRS9dqmEUpgnCk2DeMWpPkYtp1ia+CkXabOnK93JmhVlUmv8l9WMPsCSUm+WqkIA==" }, "Microsoft.Extensions.Caching.Abstractions": { "type": "Transitive", @@ -892,10 +892,11 @@ }, "Microsoft.Extensions.Configuration.Binder": { "type": "Transitive", - "resolved": "9.0.0", - "contentHash": "RiScL99DcyngY9zJA2ROrri7Br8tn5N4hP4YNvGdTN/bvg1A3dwvDOxHnNZ3Im7x2SJ5i4LkX1uPiR/MfSFBLQ==", + "resolved": "10.0.0", + "contentHash": "tMF9wNh+hlyYDWB8mrFCQHQmWHlRosol1b/N2Jrefy1bFLnuTlgSYmPyHNmz8xVQgs7DpXytBRWxGhG+mSTp0g==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.0" + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0" } }, "Microsoft.Extensions.Configuration.FileExtensions": { @@ -925,11 +926,11 @@ }, "Microsoft.Extensions.DependencyModel": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "DaBLlKcD5AYFLEeX7M07Q0vWOEBd86KYXOb+5ZRdQ1jYtN39cJd6fftxdNbRazEYQc9QqsAZiqKb9ub0gA+q+Q==", + "resolved": "10.0.0", + "contentHash": "RFYJR7APio/BiqdQunRq6DB+nDB6nc2qhHr77mlvZ0q0BT8PubMXN7XicmfzCbrDE/dzhBnUKBRXLTcqUiZDGg==", "dependencies": { - "System.Text.Encodings.Web": "9.0.11", - "System.Text.Json": "9.0.11" + "System.Text.Encodings.Web": "10.0.0", + "System.Text.Json": "10.0.0" } }, "Microsoft.Extensions.Diagnostics.Abstractions": { @@ -1017,8 +1018,11 @@ }, "Microsoft.OpenApi": { "type": "Transitive", - "resolved": "1.6.23", - "contentHash": "tZ1I0KXnn98CWuV8cpI247A17jaY+ILS9vvF7yhI0uPPEqF4P1d7BWL5Uwtel10w9NucllHB3nTkfYTAcHAh8g==" + "resolved": "2.3.0", + "contentHash": "5RZpjyt0JMmoc/aEgY9c1vE5pusdDGvkPl9qKIy9KFbRiIXD+w7gBJxX+unSjzzOcfgRoYxnO4okZyqDAL2WEw==", + "dependencies": { + "System.Text.Json": "8.0.5" + } }, "Microsoft.VisualStudio.Web.CodeGeneration": { "type": "Transitive", @@ -1262,8 +1266,8 @@ }, "Serilog": { "type": "Transitive", - "resolved": "4.2.0", - "contentHash": "gmoWVOvKgbME8TYR+gwMf7osROiWAURterc6Rt2dQyX7wtjZYpqFiA/pY6ztjGQKKV62GGCyOcmtP1UKMHgSmA==" + "resolved": "4.3.0", + "contentHash": "+cDryFR0GRhsGOnZSKwaDzRRl4MupvJ42FhCE4zhQRVanX0Jpg6WuCBk59OVhVDPmab1bB+nRykAnykYELA9qQ==" }, "Serilog.Extensions.Hosting": { "type": "Transitive", @@ -1334,24 +1338,24 @@ }, "Swashbuckle.AspNetCore.Swagger": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "w83aYEBJYNa6ZYomziwZWwXhqQPLKhZH0n8MzqqNhF1ElCGBKm71kd7W6pgIr/yu0i6ymQzrZUFSZLdvH1kY5w==", + "resolved": "10.0.1", + "contentHash": "HJYFSP18YF1Z6LCwunL+v8wuZUzzvcjarB8AJna/NVVIpq11FH9BW/D/6abwigu7SsKRbisStmk8xu2mTsxxHg==", "dependencies": { - "Microsoft.OpenApi": "1.6.23" + "Microsoft.OpenApi": "2.3.0" } }, "Swashbuckle.AspNetCore.SwaggerGen": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "aBwO2MF1HHAaWgdBwX8tlSqxycOKTKmCT6pEpb0oSY1pn7mUdmzJvHZA0HxWx9nfmKP0eOGQcLC9ZnN/MuehRQ==", + "resolved": "10.0.1", + "contentHash": "vMMBDiTC53KclPs1aiedRZnXkoI2ZgF5/JFr3Dqr8KT7wvIbA/MwD+ormQ4qf25gN5xCrJbmz/9/Z3RrpSofMA==", "dependencies": { - "Swashbuckle.AspNetCore.Swagger": "8.1.4" + "Swashbuckle.AspNetCore.Swagger": "10.0.1" } }, "Swashbuckle.AspNetCore.SwaggerUI": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "mTn6OwB43ETrN6IgAZd7ojWGhTwBZ98LT3QwbAn6Gg3wJStQV4znU0mWiHaKFlD/+Qhj1uhAUOa52rmd6xmbzg==" + "resolved": "10.0.1", + "contentHash": "a2eLI/fCxJ3WH+H1hr7Q2T82ZBk20FfqYBEZ9hOr3f+426ZUfGU2LxYWzOJrf5/4y6EKShmWpjJG01h3Rc+l6Q==" }, "System.CodeDom": { "type": "Transitive", diff --git a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Dotnet.Samples.AspNetCore.WebApi.Tests.csproj b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Dotnet.Samples.AspNetCore.WebApi.Tests.csproj index 0d9290f..5246b90 100644 --- a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Dotnet.Samples.AspNetCore.WebApi.Tests.csproj +++ b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/Dotnet.Samples.AspNetCore.WebApi.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json index 8b7a8d9..c3c09ef 100644 --- a/test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json +++ b/test/Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json @@ -16,12 +16,12 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.14.1, )", - "resolved": "17.14.1", - "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==", + "requested": "[18.0.1, )", + "resolved": "18.0.1", + "contentHash": "WNpu6vI2rA0pXY4r7NKxCN16XRWl5uHu6qjuyVLoDo6oYEggIQefrMjkRuibQHm/NslIUNCcKftvoWAN80MSAg==", "dependencies": { - "Microsoft.CodeCoverage": "17.14.1", - "Microsoft.TestPlatform.TestHost": "17.14.1" + "Microsoft.CodeCoverage": "18.0.1", + "Microsoft.TestPlatform.TestHost": "18.0.1" } }, "Moq": { @@ -90,8 +90,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.14.1", - "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg==" + "resolved": "18.0.1", + "contentHash": "O+utSr97NAJowIQT/OVp3Lh9QgW/wALVTP4RG1m2AfFP4IyJmJz0ZBmFJUsRQiAPgq6IRC0t8AAzsiPIsaUDEA==" }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", @@ -165,8 +165,8 @@ }, "Microsoft.Extensions.ApiDescription.Server": { "type": "Transitive", - "resolved": "6.0.5", - "contentHash": "Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==" + "resolved": "8.0.0", + "contentHash": "jDM3a95WerM8g6IcMiBXq1qRS9dqmEUpgnCk2DeMWpPkYtp1ia+CkXabOnK93JmhVlUmv8l9WMPsCSUm+WqkIA==" }, "Microsoft.Extensions.Caching.Abstractions": { "type": "Transitive", @@ -190,51 +190,52 @@ }, "Microsoft.Extensions.Configuration": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "UAm3SLGAMlJdowbN+/xnh2UGJkdJoXVm4MsdhZ60dAMS8jteoyCx5WfIab5DKv0TCYpdhVecLJVUjEO3abs9UQ==", + "resolved": "10.0.0", + "contentHash": "H4SWETCh/cC5L1WtWchHR6LntGk3rDTTznZMssr4cL8IbDmMWBxY+MOGDc/ASnqNolLKPIWHWeuC1ddiL/iNPw==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.10", - "Microsoft.Extensions.Primitives": "9.0.10" + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" } }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "g23//mPpMa33QdJkLujJICoCRbiLFpiQ4XbROG9JdeDI6/sM+qZPB2t5SmUWNM8GwY8dYW3NucxlZDFe8s3NAQ==", + "resolved": "10.0.0", + "contentHash": "d2kDKnCsJvY7mBVhcjPSp9BkJk48DsaHPg5u+Oy4f8XaOqnEedRy/USyvnpHL92wpJ6DrTPy7htppUUzskbCXQ==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.11" + "Microsoft.Extensions.Primitives": "10.0.0" } }, "Microsoft.Extensions.Configuration.Binder": { "type": "Transitive", - "resolved": "9.0.0", - "contentHash": "RiScL99DcyngY9zJA2ROrri7Br8tn5N4hP4YNvGdTN/bvg1A3dwvDOxHnNZ3Im7x2SJ5i4LkX1uPiR/MfSFBLQ==", + "resolved": "10.0.0", + "contentHash": "tMF9wNh+hlyYDWB8mrFCQHQmWHlRosol1b/N2Jrefy1bFLnuTlgSYmPyHNmz8xVQgs7DpXytBRWxGhG+mSTp0g==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.0" + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0" } }, "Microsoft.Extensions.Configuration.FileExtensions": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "kYWY9VRoCKQJCLKAA4Wqn74FVnytqosF7vFq1chJ8st9mGZS6SQrkoZg7GmcpqrRRUWmWDOZI4nFdoFnxsI/Ug==", + "resolved": "10.0.0", + "contentHash": "LqCTyF0twrG4tyEN6PpSC5ewRBDwCBazRUfCOdRddwaQ3n2S57GDDeYOlTLcbV/V2dxSSZWg5Ofr48h6BsBmxw==", "dependencies": { - "Microsoft.Extensions.Configuration": "9.0.10", - "Microsoft.Extensions.Configuration.Abstractions": "9.0.10", - "Microsoft.Extensions.FileProviders.Abstractions": "9.0.10", - "Microsoft.Extensions.FileProviders.Physical": "9.0.10", - "Microsoft.Extensions.Primitives": "9.0.10" + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileProviders.Physical": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" } }, "Microsoft.Extensions.Configuration.Json": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "bn+qnwuOaDelax8PUw30UTjLOuEd0lGWqUG4Z+oVr4D/gEWouCWOyvCVkyn+PWbftPlnmAmWxd4J+7ljwE8wVw==", + "resolved": "10.0.0", + "contentHash": "BIOPTEAZoeWbHlDT9Zudu+rpecZizFwhdIFRiyZKDml7JbayXmfTXKUt+ezifsSXfBkWDdJM10oDOxo8pufEng==", "dependencies": { - "Microsoft.Extensions.Configuration": "9.0.10", - "Microsoft.Extensions.Configuration.Abstractions": "9.0.10", - "Microsoft.Extensions.Configuration.FileExtensions": "9.0.10", - "Microsoft.Extensions.FileProviders.Abstractions": "9.0.10", - "System.Text.Json": "9.0.10" + "Microsoft.Extensions.Configuration": "10.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "System.Text.Json": "10.0.0" } }, "Microsoft.Extensions.DependencyInjection": { @@ -252,11 +253,11 @@ }, "Microsoft.Extensions.DependencyModel": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "DaBLlKcD5AYFLEeX7M07Q0vWOEBd86KYXOb+5ZRdQ1jYtN39cJd6fftxdNbRazEYQc9QqsAZiqKb9ub0gA+q+Q==", + "resolved": "10.0.0", + "contentHash": "RFYJR7APio/BiqdQunRq6DB+nDB6nc2qhHr77mlvZ0q0BT8PubMXN7XicmfzCbrDE/dzhBnUKBRXLTcqUiZDGg==", "dependencies": { - "System.Text.Encodings.Web": "9.0.11", - "System.Text.Json": "9.0.11" + "System.Text.Encodings.Web": "10.0.0", + "System.Text.Json": "10.0.0" } }, "Microsoft.Extensions.Diagnostics.Abstractions": { @@ -271,26 +272,26 @@ }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "3+cLxZKUWBbpfIXLLuKcEok9C91PsV1h5xxfUsEnLSXXLNMiPDfrhpb1xajNFcejFPs9Ck/Fi3z71hYDqFBwYg==", + "resolved": "10.0.0", + "contentHash": "/ppSdehKk3fuXjlqCDgSOtjRK/pSHU8eWgzSHfHdwVm5BP4Dgejehkw+PtxKG2j98qTDEHDst2Y99aNsmJldmw==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.10" + "Microsoft.Extensions.Primitives": "10.0.0" } }, "Microsoft.Extensions.FileProviders.Physical": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "Eg3YOEMpHWZzAgPD9YvGkQSv97AtG3II6maRQV/voDRORh4bRiyl0mVtT2PKnu1JoD9rJeYgjGCwRvVWMBaqgQ==", + "resolved": "10.0.0", + "contentHash": "UZUQ74lQMmvcprlG8w+XpxBbyRDQqfb7GAnccITw32hdkUBlmm9yNC4xl4aR9YjgV3ounZcub194sdmLSfBmPA==", "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "9.0.10", - "Microsoft.Extensions.FileSystemGlobbing": "9.0.10", - "Microsoft.Extensions.Primitives": "9.0.10" + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "10.0.0", + "Microsoft.Extensions.Primitives": "10.0.0" } }, "Microsoft.Extensions.FileSystemGlobbing": { "type": "Transitive", - "resolved": "9.0.10", - "contentHash": "KdZAM2YMYBipVp/4tSEWPLnrocd17SL4iaXdgXjR5/nheBXbfR5QfPWYoTyh6C6IW3uKR7TRMwQr2qCvtaCTiA==" + "resolved": "10.0.0", + "contentHash": "5hfVl/e+bx1px2UkN+1xXhd3hu7Ui6ENItBzckFaRDQXfr+SHT/7qrCDrlQekCF/PBtEu2vtk87U2+gDEF8EhQ==" }, "Microsoft.Extensions.Hosting.Abstractions": { "type": "Transitive", @@ -334,28 +335,31 @@ }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "rtUNSIhbQTv8iSBTFvtg2b/ZUkoqC9qAH9DdC2hr+xPpoZrxiCITci9UR/ELUGUGnGUrF8Xye+tGVRhCxE+4LA==" + "resolved": "10.0.0", + "contentHash": "inRnbpCS0nwO/RuoZIAqxQUuyjaknOOnCEZB55KSMMjRhl0RQDttSmLSGsUJN3RQ3ocf5NDLFd2mOQViHqMK5w==" }, "Microsoft.OpenApi": { "type": "Transitive", - "resolved": "1.6.23", - "contentHash": "tZ1I0KXnn98CWuV8cpI247A17jaY+ILS9vvF7yhI0uPPEqF4P1d7BWL5Uwtel10w9NucllHB3nTkfYTAcHAh8g==" + "resolved": "2.3.0", + "contentHash": "5RZpjyt0JMmoc/aEgY9c1vE5pusdDGvkPl9qKIy9KFbRiIXD+w7gBJxX+unSjzzOcfgRoYxnO4okZyqDAL2WEw==", + "dependencies": { + "System.Text.Json": "8.0.5" + } }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.14.1", - "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ==", + "resolved": "18.0.1", + "contentHash": "qT/mwMcLF9BieRkzOBPL2qCopl8hQu6A1P7JWAoj/FMu5i9vds/7cjbJ/LLtaiwWevWLAeD5v5wjQJ/l6jvhWQ==", "dependencies": { "System.Reflection.Metadata": "8.0.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.14.1", - "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==", + "resolved": "18.0.1", + "contentHash": "uDJKAEjFTaa2wHdWlfo6ektyoh+WD4/Eesrwb4FpBFKsLGehhACVnwwTI4qD3FrIlIEPlxdXg3SyrYRIcO+RRQ==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.14.1", + "Microsoft.TestPlatform.ObjectModel": "18.0.1", "Newtonsoft.Json": "13.0.3" } }, @@ -366,8 +370,8 @@ }, "Serilog": { "type": "Transitive", - "resolved": "4.2.0", - "contentHash": "gmoWVOvKgbME8TYR+gwMf7osROiWAURterc6Rt2dQyX7wtjZYpqFiA/pY6ztjGQKKV62GGCyOcmtP1UKMHgSmA==" + "resolved": "4.3.0", + "contentHash": "+cDryFR0GRhsGOnZSKwaDzRRl4MupvJ42FhCE4zhQRVanX0Jpg6WuCBk59OVhVDPmab1bB+nRykAnykYELA9qQ==" }, "Serilog.AspNetCore": { "type": "Transitive", @@ -414,12 +418,12 @@ }, "Serilog.Settings.Configuration": { "type": "Transitive", - "resolved": "9.0.0", - "contentHash": "4/Et4Cqwa+F88l5SeFeNZ4c4Z6dEAIKbu3MaQb2Zz9F/g27T5a3wvfMcmCOaAiACjfUb4A6wrlTVfyYUZk3RRQ==", + "resolved": "10.0.0", + "contentHash": "LNq+ibS1sbhTqPV1FIE69/9AJJbfaOhnaqkzcjFy95o+4U+STsta9mi97f1smgXsWYKICDeGUf8xUGzd/52/uA==", "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "9.0.0", - "Microsoft.Extensions.DependencyModel": "9.0.0", - "Serilog": "4.2.0" + "Microsoft.Extensions.Configuration.Binder": "10.0.0", + "Microsoft.Extensions.DependencyModel": "10.0.0", + "Serilog": "4.3.0" } }, "Serilog.Sinks.Console": { @@ -478,35 +482,35 @@ }, "Swashbuckle.AspNetCore": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "qYk8VHyvs6wML+KXtjyCgS9Aj18mcm0ZtnJeNCTlj/DYQ7A3pfLIztQgLuZS/LEMYsrTo1lSKR3IIZ5/HzVCWA==", + "resolved": "10.0.1", + "contentHash": "177+JNAV5TNvy8gLCdrcWBY9n2jdkxiHQDY4vhaExeqUpKrOqDatCcm/kW3kze60GqfnZ2NobD/IKiAPOL+CEw==", "dependencies": { - "Microsoft.Extensions.ApiDescription.Server": "6.0.5", - "Swashbuckle.AspNetCore.Swagger": "8.1.4", - "Swashbuckle.AspNetCore.SwaggerGen": "8.1.4", - "Swashbuckle.AspNetCore.SwaggerUI": "8.1.4" + "Microsoft.Extensions.ApiDescription.Server": "8.0.0", + "Swashbuckle.AspNetCore.Swagger": "10.0.1", + "Swashbuckle.AspNetCore.SwaggerGen": "10.0.1", + "Swashbuckle.AspNetCore.SwaggerUI": "10.0.1" } }, "Swashbuckle.AspNetCore.Swagger": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "w83aYEBJYNa6ZYomziwZWwXhqQPLKhZH0n8MzqqNhF1ElCGBKm71kd7W6pgIr/yu0i6ymQzrZUFSZLdvH1kY5w==", + "resolved": "10.0.1", + "contentHash": "HJYFSP18YF1Z6LCwunL+v8wuZUzzvcjarB8AJna/NVVIpq11FH9BW/D/6abwigu7SsKRbisStmk8xu2mTsxxHg==", "dependencies": { - "Microsoft.OpenApi": "1.6.23" + "Microsoft.OpenApi": "2.3.0" } }, "Swashbuckle.AspNetCore.SwaggerGen": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "aBwO2MF1HHAaWgdBwX8tlSqxycOKTKmCT6pEpb0oSY1pn7mUdmzJvHZA0HxWx9nfmKP0eOGQcLC9ZnN/MuehRQ==", + "resolved": "10.0.1", + "contentHash": "vMMBDiTC53KclPs1aiedRZnXkoI2ZgF5/JFr3Dqr8KT7wvIbA/MwD+ormQ4qf25gN5xCrJbmz/9/Z3RrpSofMA==", "dependencies": { - "Swashbuckle.AspNetCore.Swagger": "8.1.4" + "Swashbuckle.AspNetCore.Swagger": "10.0.1" } }, "Swashbuckle.AspNetCore.SwaggerUI": { "type": "Transitive", - "resolved": "8.1.4", - "contentHash": "mTn6OwB43ETrN6IgAZd7ojWGhTwBZ98LT3QwbAn6Gg3wJStQV4znU0mWiHaKFlD/+Qhj1uhAUOa52rmd6xmbzg==" + "resolved": "10.0.1", + "contentHash": "a2eLI/fCxJ3WH+H1hr7Q2T82ZBk20FfqYBEZ9hOr3f+426ZUfGU2LxYWzOJrf5/4y6EKShmWpjJG01h3Rc+l6Q==" }, "System.Collections.Immutable": { "type": "Transitive", @@ -525,8 +529,8 @@ }, "System.IO.Pipelines": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "NfGnevAV0r2gqtZWxa/7uCm3MNRYz1o4WRHhFahgBq46LuG2eaLwXIlPgtgaRUvf9CCrGFnuzN47MOzJUH1HKg==" + "resolved": "10.0.0", + "contentHash": "M1eb3nfXntaRJPrrMVM9EFS8I1bDTnt0uvUS6QP/SicZf/ZZjydMD5NiXxfmwW/uQwaMDP/yX2P+zQN1NBHChg==" }, "System.Memory": { "type": "Transitive", @@ -543,16 +547,16 @@ }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "l5L3Ov+pyD0dfK2bv6IMU2KPEyaaWnix6U0/YhgkNBGEOAgVTVlvh5ZyXWuuRlCtLnOziz+VtM5HFeqLlH2AbA==" + "resolved": "10.0.0", + "contentHash": "257hh1ep1Gqm1Lm0ulxf7vVBVMJuGN6EL4xSWjpi46DffXzm1058IiWsfSC06zSm7SniN+Tb5160UnXsSa8rRg==" }, "System.Text.Json": { "type": "Transitive", - "resolved": "9.0.11", - "contentHash": "DGToqSFbBSU6pMSbZuJ+7jDvLa73rvpcYdGFqZIB3FKdCVlEAbrBJrl9PuCT6E0QbdhXjPwqalYc5lxjUqMQzw==", + "resolved": "10.0.0", + "contentHash": "1Dpjwq9peG/Wt5BNbrzIhTpclfOSqBWZsUO28vVr59yQlkvL5jLBWfpfzRmJ1OY+6DciaY0DUcltyzs4fuZHjw==", "dependencies": { - "System.IO.Pipelines": "9.0.11", - "System.Text.Encodings.Web": "9.0.11" + "System.IO.Pipelines": "10.0.0", + "System.Text.Encodings.Web": "10.0.0" } }, "xunit.abstractions": { @@ -603,12 +607,12 @@ "FluentValidation.DependencyInjectionExtensions": "[12.1.0, )", "Microsoft.AspNetCore.OpenApi": "[8.0.22, )", "Microsoft.EntityFrameworkCore.Sqlite": "[9.0.11, )", - "Microsoft.Extensions.Configuration.Json": "[9.0.10, )", + "Microsoft.Extensions.Configuration.Json": "[10.0.0, )", "Serilog.AspNetCore": "[9.0.0, )", - "Serilog.Settings.Configuration": "[9.0.0, )", + "Serilog.Settings.Configuration": "[10.0.0, )", "Serilog.Sinks.Console": "[6.1.1, )", "Serilog.Sinks.File": "[7.0.0, )", - "Swashbuckle.AspNetCore": "[8.1.4, )" + "Swashbuckle.AspNetCore": "[10.0.1, )" } } }