Skip to content

Commit b7b9760

Browse files
committed
refactor: DRY persistence registration, server-side EF sorting, security hardening
- P0: Replace hardcoded connection string fallback with throw in Program.cs - P1.1: Extract AddPersistenceModule<TDbContext,TStore,TReader,TImpl>() generic method in ChengYuanEntityFrameworkCoreServiceCollectionExtensions, simplifying 5 persistence module registrations from 5 lines each to 1 line - P1.2: Move OrderBy/ThenBy before ToArrayAsync in EfPermissionGrantStore, EfFeatureValueStore, EfSettingValueStore so sorting runs at database level - P2: Add UnauthorizedAccessException->403 test for GlobalExceptionMiddleware and 7 Identity endpoint integration tests (GET/POST/PUT/DELETE users & roles) - P3.5: Extract JWT claim type magic strings to named constants in CurrentUserMiddleware Tests: 373 total (8 new), all passing
1 parent ecdd195 commit b7b9760

File tree

21 files changed

+452
-3639
lines changed

21 files changed

+452
-3639
lines changed

src/Applications/AuditLogging/ChengYuan.AuditLogging.Persistence/AuditLoggingPersistenceServiceCollectionExtensions.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using ChengYuan.EntityFrameworkCore;
22
using Microsoft.Extensions.DependencyInjection;
3-
using Microsoft.Extensions.DependencyInjection.Extensions;
43

54
namespace ChengYuan.AuditLogging;
65

@@ -10,11 +9,7 @@ public static IServiceCollection AddAuditLoggingPersistence(this IServiceCollect
109
{
1110
ArgumentNullException.ThrowIfNull(services);
1211

13-
services.AddConfiguredDbContext<AuditLoggingDbContext>();
14-
services.AddConfiguredDbContextFactory<AuditLoggingDbContext>();
15-
services.AddEntityFrameworkCoreDataAccess<AuditLoggingDbContext>();
16-
services.TryAddSingleton<IAuditLogStore, EfAuditLogStore>();
17-
services.TryAddSingleton<IAuditLogReader>(serviceProvider => serviceProvider.GetRequiredService<IAuditLogStore>());
12+
services.AddPersistenceModule<AuditLoggingDbContext, IAuditLogStore, IAuditLogReader, EfAuditLogStore>();
1813

1914
return services;
2015
}

src/Applications/AuditLogging/ChengYuan.AuditLogging.Persistence/packages.lock.json

Lines changed: 29 additions & 529 deletions
Large diffs are not rendered by default.

src/Applications/FeatureManagement/ChengYuan.FeatureManagement.Persistence/FeatureManagementPersistenceServiceCollectionExtensions.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using ChengYuan.EntityFrameworkCore;
22
using Microsoft.Extensions.DependencyInjection;
3-
using Microsoft.Extensions.DependencyInjection.Extensions;
43

54
namespace ChengYuan.FeatureManagement;
65

@@ -10,11 +9,7 @@ public static IServiceCollection AddFeatureManagementPersistence(this IServiceCo
109
{
1110
ArgumentNullException.ThrowIfNull(services);
1211

13-
services.AddConfiguredDbContext<FeatureManagementDbContext>();
14-
services.AddConfiguredDbContextFactory<FeatureManagementDbContext>();
15-
services.AddEntityFrameworkCoreDataAccess<FeatureManagementDbContext>();
16-
services.TryAddSingleton<IFeatureValueStore, EfFeatureValueStore>();
17-
services.TryAddSingleton<IFeatureValueReader>(serviceProvider => serviceProvider.GetRequiredService<IFeatureValueStore>());
12+
services.AddPersistenceModule<FeatureManagementDbContext, IFeatureValueStore, IFeatureValueReader, EfFeatureValueStore>();
1813

1914
return services;
2015
}

src/Applications/FeatureManagement/ChengYuan.FeatureManagement.Persistence/Stores/EfFeatureValueStore.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ public async ValueTask<IReadOnlyList<FeatureValueRecord>> GetListAsync(Cancellat
3030
{
3131
await using var dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
3232
var entities = await dbContext.FeatureValues
33+
.OrderBy(featureValue => featureValue.Scope)
34+
.ThenBy(featureValue => featureValue.Name)
35+
.ThenBy(featureValue => featureValue.TenantId)
36+
.ThenBy(featureValue => featureValue.UserId)
3337
.ToArrayAsync(cancellationToken);
3438

3539
return entities
36-
.OrderBy(featureValue => featureValue.Scope)
37-
.ThenBy(featureValue => featureValue.Name, StringComparer.Ordinal)
38-
.ThenBy(featureValue => featureValue.TenantId)
39-
.ThenBy(featureValue => featureValue.UserId, StringComparer.Ordinal)
4040
.Select(MapToRecord)
4141
.ToArray();
4242
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"version": 2,
3+
"dependencies": {
4+
"net10.0": {
5+
"Microsoft.CodeAnalysis.PublicApiAnalyzers": {
6+
"type": "Direct",
7+
"requested": "[5.0.0-1.25277.114, )",
8+
"resolved": "5.0.0-1.25277.114",
9+
"contentHash": "jhR84dGvszupV7ccc8BE1HJdBt49jHaZcBgwLBmwsJ4Ci5bRBrX1Te7TgrRUsWaAICDNZzWT5sEiqXHdA4pfjg=="
10+
},
11+
"Microsoft.DotNet.ILCompiler": {
12+
"type": "Direct",
13+
"requested": "[10.0.5, )",
14+
"resolved": "10.0.5",
15+
"contentHash": "yadTZIkStCVsG8nGwvfroSfBApPsgjQbodQyaIfp53dgayE0qhZpywixiCB6lx57JYQ+KVg1m1AFLrj54pxpZg=="
16+
},
17+
"Microsoft.NET.ILLink.Tasks": {
18+
"type": "Direct",
19+
"requested": "[10.0.5, )",
20+
"resolved": "10.0.5",
21+
"contentHash": "A+5ZuQ0f449tM+MQrhf6R9ZX7lYpjk/ODEwLYKrnF6111rtARx8fVsm4YznUnQiKnnXfaXNBqgxmil6RW3L3SA=="
22+
}
23+
},
24+
"net10.0/osx-arm64": {
25+
"Microsoft.DotNet.ILCompiler": {
26+
"type": "Direct",
27+
"requested": "[10.0.5, )",
28+
"resolved": "10.0.5",
29+
"contentHash": "yadTZIkStCVsG8nGwvfroSfBApPsgjQbodQyaIfp53dgayE0qhZpywixiCB6lx57JYQ+KVg1m1AFLrj54pxpZg==",
30+
"dependencies": {
31+
"runtime.osx-arm64.Microsoft.DotNet.ILCompiler": "10.0.5"
32+
}
33+
},
34+
"runtime.osx-arm64.Microsoft.DotNet.ILCompiler": {
35+
"type": "Transitive",
36+
"resolved": "10.0.5",
37+
"contentHash": "Kyh5mVD60xdgfUKn6hE989GZBv1Pw1IaWP6Eikf3A9RuSiMyq6XhD5JJsCFiKJ8iDuM782yx5pIus60Dzjk7gQ=="
38+
}
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)