From 97736f7239e55af48e2259fb498e0170ccf45b2f Mon Sep 17 00:00:00 2001 From: iammukeshm Date: Fri, 25 Sep 2026 19:32:51 +0530 Subject: [PATCH] chore(deps): upgrade Aspire to 13.5.4 and all NuGet packages to latest - Aspire.AppHost.Sdk + Aspire.Hosting.* 13.4.0 -> 13.5.4 (upgraded together; mixed 13.4/13.5 packages fail at runtime). Suppress ASPIRE010 - we run via `dotnet run` with NuGet-restored DCP/dashboard, not the Aspire CLI bundle. - .NET 10 platform packages 10.0.8 -> 10.0.12, EF Core 10.0.12, Npgsql EF 10.0.3, OpenTelemetry 1.19, Asp.Versioning 10.2, Scalar 2.17, QuestPDF 2026.9, Hangfire 1.8.25, MailKit/MimeKit 4.18, AWSSDK.S3 4.0.103, Testcontainers 4.15, SonarAnalyzer 10.34, and the rest to latest stable. - Majors: StackExchange.Redis 3.3.1 (same API as 2.13.17, new IO core, RESP3 by default), NSubstitute 6.2.0, xunit.runner.visualstudio 4.0.0 (still runs v2). - Security pins bumped within their lines: Microsoft.OpenApi 2.12.2 (stays 2.x), System.Security.Cryptography.Xml 10.0.12, SQLitePCLRaw.lib.e_sqlite3 3.53.3, MessagePack 2.5.305. - SonarAnalyzer S8969 (new): removed 157 redundant null-forgiving operators; compile-time only. Hangfire basic-auth filter uses header.ToString() where Sonar and the compiler disagreed. - S8949 (new): TenantProvisioningService passes CancellationToken.None explicitly into the Hangfire job expression. - AV0029/AV0030 (Asp.Versioning 10.2 advisories toward AddApiVersioning().AddOpenApi()) suppressed - FSH registers one OpenAPI document per version by design. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/BuildingBlocks/Jobs/Extensions.cs | 4 +- ...HangfireCustomBasicAuthenticationFilter.cs | 4 +- src/BuildingBlocks/Quota/Extensions.cs | 2 +- src/BuildingBlocks/Quota/QuotaPlanResolver.cs | 2 +- .../Storage/Local/LocalStorageService.cs | 2 +- src/Directory.Build.props | 3 + src/Directory.Packages.props | 154 +++++++++--------- .../FSH.Starter.AppHost.csproj | 4 +- .../Persistence/EntityDiffBuilder.cs | 2 +- .../Data/IdentityDbInitializer.cs | 8 +- .../RefreshTokenCommandHandler.cs | 10 +- .../GenerateTokenCommandHandler.cs | 8 +- .../CreateTenantCommandHandler.cs | 2 +- .../CreateTenantCommandValidator.cs | 2 +- .../v1/GetTenants/GetTenantsSpecification.cs | 12 +- .../RenewTenant/RenewTenantCommandHandler.cs | 4 +- .../MultitenancyModule.cs | 2 +- .../Provisioning/TenantProvisioningService.cs | 3 +- .../Services/TenantService.cs | 4 +- .../TenantMigrationsHealthCheck.cs | 8 +- .../NamespaceConventionsTests.cs | 2 +- .../Billing.Tests/Domain/InvoiceTests.cs | 2 +- .../Billing.Tests/Domain/SubscriptionTests.cs | 2 +- .../Caching.Tests/CachedTypeContractTests.cs | 2 +- .../Eventing/EventingDbContextModelTests.cs | 6 +- .../Storage/LocalPresignTokenStoreTests.cs | 2 +- .../Storage/LocalStorageServiceTests.cs | 4 +- .../Framework.Tests/Web/CorsPolicyTests.cs | 2 +- .../IdempotencyEndpointFilterReplayTests.cs | 6 +- .../RegisterUserCommandHandlerTests.cs | 4 +- .../Services/UserPasswordServiceTests.cs | 2 +- .../Tests/RateLimitingTests.cs | 2 +- .../Tests/SecurityHeadersTests.cs | 8 +- .../Auditing/AuditExceptionAndFilterTests.cs | 2 +- .../Tests/Auditing/AuditPayloadFilterTests.cs | 2 +- .../Authentication/AccountLockoutTests.cs | 4 +- .../Authentication/TwoFactorAuthTests.cs | 16 +- .../Tests/Billing/BillingDomainEdgeTests.cs | 4 +- .../Tests/Billing/BillingEndpointTests.cs | 20 +-- .../Billing/BillingTenantIsolationTests.cs | 6 +- .../Tests/Billing/MonthlyInvoiceJobTests.cs | 2 +- .../Billing/TenantBillingLifecycleTests.cs | 8 +- .../Tests/Billing/TopupApprovalTests.cs | 6 +- .../Tests/Billing/UsageSnapshotQueryTests.cs | 2 +- .../Tests/Caching/HybridCacheRedisTests.cs | 2 +- .../Tests/Catalog/BrandsEndpointTests.cs | 2 +- .../Tests/Catalog/CategoriesEndpointTests.cs | 4 +- .../Catalog/ProductFileAccessPolicyTests.cs | 2 +- .../Catalog/ProductImageRemoveReorderTests.cs | 2 +- .../Tests/Catalog/ProductImagesTests.cs | 2 +- .../Tests/Catalog/ProductsEndpointTests.cs | 2 +- .../Tests/Chat/ChatChannelFileAccessTests.cs | 2 +- .../Tests/Chat/ChatSendMessageTests.cs | 2 +- .../Tests/Chat/JoinChannelTests.cs | 2 +- .../Tests/Chat/MentionAndNotificationTests.cs | 10 +- .../Tests/Chat/PinMessageTests.cs | 6 +- .../Tests/Chat/PresenceTests.cs | 2 +- .../Tests/Chat/SearchMessagesTests.cs | 2 +- .../Tests/Chat/TypingIndicatorTests.cs | 2 +- .../Tests/Eventing/OutboxRetryTests.cs | 2 +- .../Files/FileVisibilityAndSharingTests.cs | 2 +- .../Tests/Files/PurgeJobsTests.cs | 6 +- .../Tests/Files/StorageFlowTests.cs | 4 +- .../TenantMigrationsHealthCheckTests.cs | 4 +- .../Tests/Impersonation/ImpersonationTests.cs | 2 +- .../Multitenancy/AdjustTenantValidityTests.cs | 2 +- .../Tests/Multitenancy/MyTenantStatusTests.cs | 2 +- .../Tests/Multitenancy/RenewTenantTests.cs | 8 +- .../TenantExpiryEnforcementTests.cs | 4 +- .../NotificationsEndpointTests.cs | 2 +- .../Tests/Sessions/IdentityUserSeeder.cs | 6 +- .../Tests/Tickets/TicketsEndpointTests.cs | 2 +- .../Tests/Users/UserProfileTests.cs | 6 +- .../Tests/Webhooks/WebhookDeliveryTests.cs | 2 +- .../Tests/Webhooks/WebhookDispatchJobTests.cs | 8 +- .../Webhooks/WebhookDispatchOutcomeTests.cs | 6 +- .../FinbuckleEventTenantScopeTests.cs | 6 +- 77 files changed, 240 insertions(+), 234 deletions(-) diff --git a/src/BuildingBlocks/Jobs/Extensions.cs b/src/BuildingBlocks/Jobs/Extensions.cs index 9ab773b0fc..a56a6cada0 100644 --- a/src/BuildingBlocks/Jobs/Extensions.cs +++ b/src/BuildingBlocks/Jobs/Extensions.cs @@ -78,8 +78,8 @@ public static IApplicationBuilder UseHeroJobDashboard(this IApplicationBuilder a { new HangfireCustomBasicAuthenticationFilter { - User = hangfireOptions.UserName!, - Pass = hangfireOptions.Password! + User = hangfireOptions.UserName, + Pass = hangfireOptions.Password } }; diff --git a/src/BuildingBlocks/Jobs/HangfireCustomBasicAuthenticationFilter.cs b/src/BuildingBlocks/Jobs/HangfireCustomBasicAuthenticationFilter.cs index d03357c23d..935334998a 100644 --- a/src/BuildingBlocks/Jobs/HangfireCustomBasicAuthenticationFilter.cs +++ b/src/BuildingBlocks/Jobs/HangfireCustomBasicAuthenticationFilter.cs @@ -24,7 +24,7 @@ public HangfireCustomBasicAuthenticationFilter() public bool Authorize(DashboardContext context) { var httpContext = context.GetHttpContext(); - var header = httpContext.Request.Headers.Authorization!; + var header = httpContext.Request.Headers.Authorization; if (MissingAuthorizationHeader(header)) { @@ -33,7 +33,7 @@ public bool Authorize(DashboardContext context) return false; } - var authValues = AuthenticationHeaderValue.Parse(header!); + var authValues = AuthenticationHeaderValue.Parse(header.ToString()); if (NotBasicAuthentication(authValues)) { diff --git a/src/BuildingBlocks/Quota/Extensions.cs b/src/BuildingBlocks/Quota/Extensions.cs index 508899ca1d..2e860640d2 100644 --- a/src/BuildingBlocks/Quota/Extensions.cs +++ b/src/BuildingBlocks/Quota/Extensions.cs @@ -39,7 +39,7 @@ public static IServiceCollection AddHeroQuotas(this IServiceCollection services, { services.AddSingleton(_ => { - var config = ConfigurationOptions.Parse(quotaOptions.Redis!); + var config = ConfigurationOptions.Parse(quotaOptions.Redis); config.AbortOnConnectFail = false; return ConnectionMultiplexer.Connect(config); }); diff --git a/src/BuildingBlocks/Quota/QuotaPlanResolver.cs b/src/BuildingBlocks/Quota/QuotaPlanResolver.cs index 588c63a4be..8c6decbba5 100644 --- a/src/BuildingBlocks/Quota/QuotaPlanResolver.cs +++ b/src/BuildingBlocks/Quota/QuotaPlanResolver.cs @@ -26,7 +26,7 @@ public long ResolveLimit(AppTenantInfo? tenant, QuotaResource resource) return NormalizeLimit(tenantLimit); } - var planName = !string.IsNullOrWhiteSpace(tenant?.Plan) ? tenant!.Plan! : _options.DefaultPlan; + var planName = !string.IsNullOrWhiteSpace(tenant?.Plan) ? tenant.Plan : _options.DefaultPlan; if (_options.Plans.TryGetValue(planName, out var plan) && plan.TryGetValue(resource, out var planLimit)) diff --git a/src/BuildingBlocks/Storage/Local/LocalStorageService.cs b/src/BuildingBlocks/Storage/Local/LocalStorageService.cs index 23b60d6f1a..48ebcffc3e 100644 --- a/src/BuildingBlocks/Storage/Local/LocalStorageService.cs +++ b/src/BuildingBlocks/Storage/Local/LocalStorageService.cs @@ -209,7 +209,7 @@ public string BuildPublicUrl(string storageKey) return Task.FromResult(new StoredObjectMetadata( info.Length, - contentType!, + contentType, new DateTimeOffset(info.LastWriteTimeUtc, TimeSpan.Zero), ETag: null)); } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index be9ac87f2f..1ea568090e 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -21,6 +21,9 @@ true $(NoWarn);CS1591;MSG0005;CA1054;CA1056 + + $(NoWarn);AV0029;AV0030 diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 5cc70bbb6f..39ac673040 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -12,26 +12,26 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - - - - - - - - + + + + + + + + + + + + @@ -40,108 +40,108 @@ - - - + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - + + - - - - - - - + + + - - - - - + + + + + - + - + - + - + - + \ No newline at end of file diff --git a/src/Host/FSH.Starter.AppHost/FSH.Starter.AppHost.csproj b/src/Host/FSH.Starter.AppHost/FSH.Starter.AppHost.csproj index 1e4c5483d6..526a662916 100644 --- a/src/Host/FSH.Starter.AppHost/FSH.Starter.AppHost.csproj +++ b/src/Host/FSH.Starter.AppHost/FSH.Starter.AppHost.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,8 @@ enable 9fe5df9a-b9b2-4202-bdb4-d30b01b71d1a false + + $(NoWarn);ASPIRE010 diff --git a/src/Modules/Auditing/Modules.Auditing/Persistence/EntityDiffBuilder.cs b/src/Modules/Auditing/Modules.Auditing/Persistence/EntityDiffBuilder.cs index 2635b3e903..986a5dda5a 100644 --- a/src/Modules/Auditing/Modules.Auditing/Persistence/EntityDiffBuilder.cs +++ b/src/Modules/Auditing/Modules.Auditing/Persistence/EntityDiffBuilder.cs @@ -57,7 +57,7 @@ public static List Build(IEnumerable entries) return new Diff( DbContext: entry.Context.GetType().Name, Schema: schema, - Table: table!, + Table: table, EntityName: entityType.ClrType.Name, Key: key, Operation: operation, diff --git a/src/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs b/src/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs index ed2b58276b..5c8623612c 100644 --- a/src/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs +++ b/src/Modules/Identity/Modules.Identity/Data/IdentityDbInitializer.cs @@ -182,7 +182,7 @@ private async Task SeedAdminUserAsync(CancellationToken cancellationToken = defa return; } - if (await userManager.Users.FirstOrDefaultAsync(u => u.Email == multiTenantContextAccessor.MultiTenantContext.TenantInfo!.AdminEmail, cancellationToken) + if (await userManager.Users.FirstOrDefaultAsync(u => u.Email == multiTenantContextAccessor.MultiTenantContext.TenantInfo.AdminEmail, cancellationToken) is not FshUser adminUser) { string adminUserName = $"{multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id.Trim()}.{RoleConstants.Admin}".ToUpperInvariant(); @@ -194,7 +194,7 @@ private async Task SeedAdminUserAsync(CancellationToken cancellationToken = defa UserName = adminUserName, EmailConfirmed = true, PhoneNumberConfirmed = true, - NormalizedEmail = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.AdminEmail!.ToUpperInvariant(), + NormalizedEmail = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.AdminEmail.ToUpperInvariant(), NormalizedUserName = adminUserName.ToUpperInvariant(), // No default avatar: the asset was never shipped, and baking an absolute // {OriginUrl}/… URL at seed time pinned it to the seeder's localhost origin @@ -207,7 +207,7 @@ private async Task SeedAdminUserAsync(CancellationToken cancellationToken = defa { logger.LogInformation("Seeding Default Admin User for '{TenantId}' Tenant.", multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id); } - var initialPassword = ResolveInitialAdminPassword(multiTenantContextAccessor.MultiTenantContext.TenantInfo!.Id!); + var initialPassword = ResolveInitialAdminPassword(multiTenantContextAccessor.MultiTenantContext.TenantInfo!.Id); var password = new PasswordHasher(); adminUser.PasswordHash = password.HashPassword(adminUser, initialPassword); // MUST check IdentityResult: a silent failure (password-policy reject, transient DB error) @@ -216,7 +216,7 @@ private async Task SeedAdminUserAsync(CancellationToken cancellationToken = defa if (!createResult.Succeeded) { throw new InvalidOperationException( - $"Failed to seed admin user for tenant '{multiTenantContextAccessor.MultiTenantContext.TenantInfo!.Id}': " + $"Failed to seed admin user for tenant '{multiTenantContextAccessor.MultiTenantContext.TenantInfo.Id}': " + string.Join("; ", createResult.Errors.Select(e => e.Description))); } } diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs index dd66630e31..41c5878ade 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/RefreshToken/RefreshTokenCommandHandler.cs @@ -50,7 +50,7 @@ public async ValueTask Handle( if (validated is null) { - await _securityAudit.TokenRevokedAsync("unknown", clientId!, "InvalidRefreshToken", cancellationToken); + await _securityAudit.TokenRevokedAsync("unknown", clientId, "InvalidRefreshToken", cancellationToken); throw new UnauthorizedException("Invalid refresh token."); } @@ -61,7 +61,7 @@ public async ValueTask Handle( var isSessionValid = await _sessionService.ValidateSessionAsync(refreshTokenHash, cancellationToken); if (!isSessionValid) { - await _securityAudit.TokenRevokedAsync(subject, clientId!, "SessionRevoked", cancellationToken); + await _securityAudit.TokenRevokedAsync(subject, clientId, "SessionRevoked", cancellationToken); throw new UnauthorizedException("Session has been revoked."); } @@ -86,13 +86,13 @@ public async ValueTask Handle( if (!string.IsNullOrEmpty(accessTokenSubject) && !string.Equals(accessTokenSubject, subject, StringComparison.Ordinal)) { - await _securityAudit.TokenRevokedAsync(subject, clientId!, "RefreshTokenSubjectMismatch", cancellationToken); + await _securityAudit.TokenRevokedAsync(subject, clientId, "RefreshTokenSubjectMismatch", cancellationToken); throw new UnauthorizedException("Access token subject mismatch."); } } // Audit previous token revocation by rotation (no raw tokens) - await _securityAudit.TokenRevokedAsync(subject, clientId!, "RefreshTokenRotated", cancellationToken); + await _securityAudit.TokenRevokedAsync(subject, clientId, "RefreshTokenRotated", cancellationToken); // Issue new tokens var newToken = await _tokenService.IssueAsync(subject, claims, null, cancellationToken); @@ -113,7 +113,7 @@ await _sessionService.UpdateSessionRefreshTokenAsync( await _securityAudit.TokenIssuedAsync( userId: subject, userName: claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? string.Empty, - clientId: clientId!, + clientId: clientId, tokenFingerprint: fingerprint, expiresUtc: newToken.AccessTokenExpiresAt, ct: cancellationToken); diff --git a/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/GenerateTokenCommandHandler.cs b/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/GenerateTokenCommandHandler.cs index 24bffb7030..a5a44a43ab 100644 --- a/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/GenerateTokenCommandHandler.cs +++ b/src/Modules/Identity/Modules.Identity/Features/v1/Tokens/TokenGeneration/GenerateTokenCommandHandler.cs @@ -65,7 +65,7 @@ public async ValueTask Handle( // 1) Audit failed login BEFORE throwing await _securityAudit.LoginFailedAsync( subjectIdOrName: request.Email, - clientId: clientId!, + clientId: clientId, reason: "InvalidCredentials", ip: ip, ct: cancellationToken); @@ -80,7 +80,7 @@ await _securityAudit.LoginFailedAsync( await _securityAudit.LoginSucceededAsync( userId: subject, userName: claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? request.Email, - clientId: clientId!, + clientId: clientId, ip: ip, userAgent: ua, ct: cancellationToken); @@ -115,7 +115,7 @@ await _sessionService.CreateSessionAsync( await _securityAudit.TokenIssuedAsync( userId: subject, userName: claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? request.Email, - clientId: clientId!, + clientId: clientId, tokenFingerprint: fingerprint, expiresUtc: token.AccessTokenExpiresAt, ct: cancellationToken); @@ -132,7 +132,7 @@ await _securityAudit.TokenIssuedAsync( Source: "Identity", UserId: subject, Email: request.Email, - ClientId: clientId!, + ClientId: clientId, IpAddress: ip, UserAgent: ua, TokenFingerprint: fingerprint, diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandHandler.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandHandler.cs index 0a30637422..9490977f30 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandHandler.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandHandler.cs @@ -28,7 +28,7 @@ public async ValueTask Handle(CreateTenantCommand c // window. A bad plan key throws NotFound (400) before any tenant is created. var planKey = string.IsNullOrWhiteSpace(command.PlanKey) ? billingOptions.Value.DefaultPlanKey - : command.PlanKey!; + : command.PlanKey; var term = await mediator.Send(new GetPlanTermQuery(planKey), cancellationToken).ConfigureAwait(false); var periodStart = timeProvider.GetUtcNow().UtcDateTime; diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandValidator.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandValidator.cs index 2e199a329d..d7dad9e8db 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandValidator.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/CreateTenant/CreateTenantCommandValidator.cs @@ -16,7 +16,7 @@ public CreateTenantCommandValidator(ITenantService tenantService, IConnectionStr RuleFor(t => t.Name).Cascade(CascadeMode.Stop) .NotEmpty() - .MustAsync(async (name, ct) => !await tenantService.ExistsWithNameAsync(name!, ct).ConfigureAwait(false)) + .MustAsync(async (name, ct) => !await tenantService.ExistsWithNameAsync(name, ct).ConfigureAwait(false)) .WithMessage((_, name) => $"Tenant {name} already exists."); RuleFor(t => t.ConnectionString).Cascade(CascadeMode.Stop) diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/GetTenants/GetTenantsSpecification.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/GetTenants/GetTenantsSpecification.cs index 4b4a874994..dae359dd08 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/GetTenants/GetTenantsSpecification.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/GetTenants/GetTenantsSpecification.cs @@ -13,10 +13,10 @@ internal sealed class GetTenantsSpecification : Specification>>( StringComparer.OrdinalIgnoreCase) { - ["id"] = t => t.Id!, + ["id"] = t => t.Id, ["name"] = t => t.Name!, - ["connectionstring"] = t => t.ConnectionString!, - ["adminemail"] = t => t.AdminEmail!, + ["connectionstring"] = t => t.ConnectionString, + ["adminemail"] = t => t.AdminEmail, ["isactive"] = t => t.IsActive, ["validupto"] = t => t.ValidUpto, ["issuer"] = t => t.Issuer! @@ -29,10 +29,10 @@ public GetTenantsSpecification(GetTenantsQuery query) // Default projection to TenantDto. Select(t => new TenantDto { - Id = t.Id!, + Id = t.Id, Name = t.Name!, ConnectionString = t.ConnectionString, - AdminEmail = t.AdminEmail!, + AdminEmail = t.AdminEmail, IsActive = t.IsActive, ValidUpto = t.ValidUpto, Issuer = t.Issuer @@ -46,7 +46,7 @@ public GetTenantsSpecification(GetTenantsQuery query) () => { OrderBy(t => t.Name!); - ThenBy(t => t.Id!); + ThenBy(t => t.Id); }, SortMappings); } diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/RenewTenant/RenewTenantCommandHandler.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/RenewTenant/RenewTenantCommandHandler.cs index 7a509d809c..9f99c7d9d7 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/RenewTenant/RenewTenantCommandHandler.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Features/v1/RenewTenant/RenewTenantCommandHandler.cs @@ -25,10 +25,10 @@ public async ValueTask Handle(RenewTenantCommand com var targetKey = command.PlanKey; if (string.IsNullOrWhiteSpace(targetKey)) { - targetKey = string.IsNullOrWhiteSpace(status.Plan) ? billingOptions.Value.DefaultPlanKey : status.Plan!; + targetKey = string.IsNullOrWhiteSpace(status.Plan) ? billingOptions.Value.DefaultPlanKey : status.Plan; } - var term = await mediator.Send(new GetPlanTermQuery(targetKey!), cancellationToken).ConfigureAwait(false); + var term = await mediator.Send(new GetPlanTermQuery(targetKey), cancellationToken).ConfigureAwait(false); var (periodStart, validUpto, planChanged) = await tenantService .RenewAsync(command.TenantId, term.Key, term.TermMonths, cancellationToken).ConfigureAwait(false); diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/MultitenancyModule.cs b/src/Modules/Multitenancy/Modules.Multitenancy/MultitenancyModule.cs index 698a90277c..096b032136 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/MultitenancyModule.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/MultitenancyModule.cs @@ -90,7 +90,7 @@ public void ConfigureServices(IHostApplicationBuilder builder) if (context.MultiTenantContext.StoreInfo is null) return; if (context.MultiTenantContext.StoreInfo.StoreType != typeof(DistributedCacheStore)) { - var sp = ((HttpContext)context.Context!).RequestServices; + var sp = ((HttpContext)context.Context).RequestServices; var distributedStore = sp .GetRequiredService>>() .FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningService.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningService.cs index c7a9ec719a..0d99b4d3c9 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningService.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Provisioning/TenantProvisioningService.cs @@ -65,7 +65,8 @@ public async Task StartAsync(string tenantId, CancellationTo return provisioning; } - var jobId = _jobService.Enqueue(job => job.RunAsync(tenant.Id, correlationId)); + // CancellationToken.None: Hangfire substitutes its own job-cancellation token at execution time; the request token must not flow into the job. + var jobId = _jobService.Enqueue(job => job.RunAsync(tenant.Id, correlationId, CancellationToken.None)); provisioning.SetJobId(jobId); await _dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantService.cs b/src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantService.cs index 15d8fdbe01..3b504f5c37 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantService.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/Services/TenantService.cs @@ -184,12 +184,12 @@ public async Task GetStatusAsync(string id, CancellationToken c return new TenantStatusDto { - Id = tenant.Id!, + Id = tenant.Id, Name = tenant.Name!, IsActive = tenant.IsActive, ValidUpto = tenant.ValidUpto, HasConnectionString = !string.IsNullOrWhiteSpace(tenant.ConnectionString), - AdminEmail = tenant.AdminEmail!, + AdminEmail = tenant.AdminEmail, Issuer = tenant.Issuer, Plan = tenant.Plan, ExpiryState = expiryState, diff --git a/src/Modules/Multitenancy/Modules.Multitenancy/TenantMigrationsHealthCheck.cs b/src/Modules/Multitenancy/Modules.Multitenancy/TenantMigrationsHealthCheck.cs index 2ac150aa52..68e69b477a 100644 --- a/src/Modules/Multitenancy/Modules.Multitenancy/TenantMigrationsHealthCheck.cs +++ b/src/Modules/Multitenancy/Modules.Multitenancy/TenantMigrationsHealthCheck.cs @@ -54,10 +54,10 @@ public async Task CheckHealthAsync(HealthCheckContext context bool hasPending = pendingMigrations.Length > 0; if (hasPending) { - tenantsWithPending.Add(tenant.Id!); + tenantsWithPending.Add(tenant.Id); } - details[tenant.Id!] = new + details[tenant.Id] = new { tenant.Name, tenant.IsActive, @@ -70,8 +70,8 @@ public async Task CheckHealthAsync(HealthCheckContext context // detail entries so the readiness payload tells the operator which tenant is broken. catch (Exception ex) { - tenantsWithError.Add(tenant.Id!); - details[tenant.Id!] = new + tenantsWithError.Add(tenant.Id); + details[tenant.Id] = new { tenant.Name, tenant.IsActive, diff --git a/src/Tests/Architecture.Tests/NamespaceConventionsTests.cs b/src/Tests/Architecture.Tests/NamespaceConventionsTests.cs index dedc87a07b..840ceb087b 100644 --- a/src/Tests/Architecture.Tests/NamespaceConventionsTests.cs +++ b/src/Tests/Architecture.Tests/NamespaceConventionsTests.cs @@ -34,7 +34,7 @@ public void BuildingBlocks_Core_Domain_Namespaces_Should_Match_Folder() namespaceLine.ShouldNotBeNull($"File '{file}' must declare a namespace matching the folder structure."); - string declaredNamespace = namespaceLine!["namespace ".Length..].Trim().TrimEnd(';'); + string declaredNamespace = namespaceLine["namespace ".Length..].Trim().TrimEnd(';'); declaredNamespace .Contains(".Core.", StringComparison.Ordinal) diff --git a/src/Tests/Billing.Tests/Domain/InvoiceTests.cs b/src/Tests/Billing.Tests/Domain/InvoiceTests.cs index 3c6dfeae66..7f1e18a460 100644 --- a/src/Tests/Billing.Tests/Domain/InvoiceTests.cs +++ b/src/Tests/Billing.Tests/Domain/InvoiceTests.cs @@ -84,7 +84,7 @@ public void Issue_Should_Default_Due_Date_To_14_Days_After_Issue() inv.Status.ShouldBe(InvoiceStatus.Issued); inv.IssuedAtUtc.ShouldNotBeNull(); inv.DueAtUtc.ShouldNotBeNull(); - (inv.DueAtUtc!.Value - inv.IssuedAtUtc!.Value).Days.ShouldBe(14); + (inv.DueAtUtc.Value - inv.IssuedAtUtc.Value).Days.ShouldBe(14); } [Fact] diff --git a/src/Tests/Billing.Tests/Domain/SubscriptionTests.cs b/src/Tests/Billing.Tests/Domain/SubscriptionTests.cs index aad30c5084..0f5e188573 100644 --- a/src/Tests/Billing.Tests/Domain/SubscriptionTests.cs +++ b/src/Tests/Billing.Tests/Domain/SubscriptionTests.cs @@ -54,7 +54,7 @@ public void Cancel_Should_Set_Status_Cancelled_And_Normalize_EndUtc_To_Utc() sub.Status.ShouldBe(SubscriptionStatus.Cancelled); sub.EndUtc.ShouldNotBeNull(); - sub.EndUtc!.Value.Kind.ShouldBe(DateTimeKind.Utc); + sub.EndUtc.Value.Kind.ShouldBe(DateTimeKind.Utc); sub.UpdatedAtUtc.ShouldNotBeNull(); } diff --git a/src/Tests/Caching.Tests/CachedTypeContractTests.cs b/src/Tests/Caching.Tests/CachedTypeContractTests.cs index 29b766c809..c14799c243 100644 --- a/src/Tests/Caching.Tests/CachedTypeContractTests.cs +++ b/src/Tests/Caching.Tests/CachedTypeContractTests.cs @@ -63,7 +63,7 @@ public void CachedType_Should_HaveImmutableObjectAttribute(Type type) attr.ShouldNotBeNull( $"{type.FullName} is stored in HybridCache and must have [ImmutableObject(true)] so the runtime can return the same reference across L1 hits instead of re-deserializing."); - attr!.Immutable.ShouldBeTrue( + attr.Immutable.ShouldBeTrue( $"{type.FullName} has [ImmutableObject(false)] — change to [ImmutableObject(true)] or stop caching it."); } } diff --git a/src/Tests/Framework.Tests/Eventing/EventingDbContextModelTests.cs b/src/Tests/Framework.Tests/Eventing/EventingDbContextModelTests.cs index b257ab5962..f328c31551 100644 --- a/src/Tests/Framework.Tests/Eventing/EventingDbContextModelTests.cs +++ b/src/Tests/Framework.Tests/Eventing/EventingDbContextModelTests.cs @@ -46,7 +46,7 @@ public void Maps_OutboxMessages_To_Framework_Schema() var entity = context.Model.FindEntityType(typeof(OutboxMessage)); entity.ShouldNotBeNull(); - entity!.GetSchema().ShouldBe(EventingConstants.SchemaName); + entity.GetSchema().ShouldBe(EventingConstants.SchemaName); entity.GetTableName().ShouldBe("OutboxMessages"); } @@ -57,7 +57,7 @@ public void Outbox_Has_Claim_Index_For_Pending_Scan() var entity = context.Model.FindEntityType(typeof(OutboxMessage)); entity.ShouldNotBeNull(); - entity!.GetIndexes() + entity.GetIndexes() .Any(i => i.GetDatabaseName() == "IX_OutboxMessages_Pending") .ShouldBeTrue("the claim scan filters and orders on these columns under a row lock"); } @@ -69,7 +69,7 @@ public void Maps_InboxMessages_To_Framework_Schema() var entity = context.Model.FindEntityType(typeof(InboxMessage)); entity.ShouldNotBeNull(); - entity!.GetSchema().ShouldBe(EventingConstants.SchemaName); + entity.GetSchema().ShouldBe(EventingConstants.SchemaName); entity.GetTableName().ShouldBe("InboxMessages"); } diff --git a/src/Tests/Framework.Tests/Storage/LocalPresignTokenStoreTests.cs b/src/Tests/Framework.Tests/Storage/LocalPresignTokenStoreTests.cs index 2ef9b825e2..e5d1e6371a 100644 --- a/src/Tests/Framework.Tests/Storage/LocalPresignTokenStoreTests.cs +++ b/src/Tests/Framework.Tests/Storage/LocalPresignTokenStoreTests.cs @@ -19,7 +19,7 @@ public void IssueThenConsume_Should_ReturnToken_When_NotExpired() // Assert token.ShouldNotBeNullOrWhiteSpace(); consumed.ShouldNotBeNull(); - consumed!.StorageKey.ShouldBe("uploads/probe/file.png"); + consumed.StorageKey.ShouldBe("uploads/probe/file.png"); consumed.ContentType.ShouldBe("image/png"); consumed.MaxBytes.ShouldBe(2048); } diff --git a/src/Tests/Framework.Tests/Storage/LocalStorageServiceTests.cs b/src/Tests/Framework.Tests/Storage/LocalStorageServiceTests.cs index 1e81aa821a..780ea38423 100644 --- a/src/Tests/Framework.Tests/Storage/LocalStorageServiceTests.cs +++ b/src/Tests/Framework.Tests/Storage/LocalStorageServiceTests.cs @@ -66,7 +66,7 @@ public async Task UploadDownloadExists_Should_RoundTrip_When_FileUploaded() exists.ShouldBeTrue(); size.ShouldBe(4); download.ShouldNotBeNull(); - download!.ContentType.ShouldBe("image/png"); + download.ContentType.ShouldBe("image/png"); download.ContentLength.ShouldBe(4); await download.Stream.DisposeAsync(); } @@ -96,7 +96,7 @@ public async Task HeadObjectAsync_Should_ReturnMetadata_When_FileExists() // Assert metadata.ShouldNotBeNull(); - metadata!.SizeBytes.ShouldBe(4); + metadata.SizeBytes.ShouldBe(4); metadata.ContentType.ShouldBe("image/png"); } diff --git a/src/Tests/Framework.Tests/Web/CorsPolicyTests.cs b/src/Tests/Framework.Tests/Web/CorsPolicyTests.cs index f17ece3e0f..d172fc36a7 100644 --- a/src/Tests/Framework.Tests/Web/CorsPolicyTests.cs +++ b/src/Tests/Framework.Tests/Web/CorsPolicyTests.cs @@ -41,6 +41,6 @@ public void Policy_Should_ExposeETag_When_Built(bool allowAll) // Assert policy.ShouldNotBeNull(); - policy!.ExposedHeaders.ShouldContain("ETag"); + policy.ExposedHeaders.ShouldContain("ETag"); } } diff --git a/src/Tests/Framework.Tests/Web/IdempotencyEndpointFilterReplayTests.cs b/src/Tests/Framework.Tests/Web/IdempotencyEndpointFilterReplayTests.cs index 2802d61b02..97f87f12be 100644 --- a/src/Tests/Framework.Tests/Web/IdempotencyEndpointFilterReplayTests.cs +++ b/src/Tests/Framework.Tests/Web/IdempotencyEndpointFilterReplayTests.cs @@ -1308,14 +1308,14 @@ private static IConnectionMultiplexer KeyspaceMultiplexer(SharedKeyspace keyspac db.StringSetAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => Task.FromResult( ci.ArgAt(3) == When.NotExists - ? keyspace.TryAdd(ci.ArgAt(0).ToString(), (byte[])ci.ArgAt(1)!) - : keyspace.Set(ci.ArgAt(0).ToString(), (byte[])ci.ArgAt(1)!))); + ? keyspace.TryAdd(ci.ArgAt(0).ToString(), ((byte[])ci.ArgAt(1))!) + : keyspace.Set(ci.ArgAt(0).ToString(), ((byte[])ci.ArgAt(1))!))); db.ScriptEvaluateAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => { keyspace.RemoveIfValueMatches( ci.ArgAt(1)[0].ToString(), - (byte[])ci.ArgAt(2)[0]!); + ((byte[])ci.ArgAt(2)[0])!); return Task.FromResult(RedisResult.Create(1)); }); return RedisMultiplexer(db); diff --git a/src/Tests/Identity.Tests/Handlers/RegisterUserCommandHandlerTests.cs b/src/Tests/Identity.Tests/Handlers/RegisterUserCommandHandlerTests.cs index 8d4168b74d..fc4bc78bed 100644 --- a/src/Tests/Identity.Tests/Handlers/RegisterUserCommandHandlerTests.cs +++ b/src/Tests/Identity.Tests/Handlers/RegisterUserCommandHandlerTests.cs @@ -252,8 +252,8 @@ await _userService.Received(1).RegisterAsync( command.UserName, command.Password, command.ConfirmPassword, - command.PhoneNumber!, - command.Origin!, + command.PhoneNumber, + command.Origin, cancellationToken); } diff --git a/src/Tests/Identity.Tests/Services/UserPasswordServiceTests.cs b/src/Tests/Identity.Tests/Services/UserPasswordServiceTests.cs index f772ce9383..efcd9e8bc9 100644 --- a/src/Tests/Identity.Tests/Services/UserPasswordServiceTests.cs +++ b/src/Tests/Identity.Tests/Services/UserPasswordServiceTests.cs @@ -124,7 +124,7 @@ public async Task ForgotPasswordAsync_Should_SendATextAlternative_AlongsideTheHt // Assert var mail = CaptureSentMail(); mail.TextBody.ShouldNotBeNullOrWhiteSpace(); - mail.TextBody!.ShouldContain("https://adminbase.codefi.com.br/reset-password?"); + mail.TextBody.ShouldContain("https://adminbase.codefi.com.br/reset-password?"); mail.TextBody.ShouldNotContain(" r.EventType == AuditEventType.Security); + paged.Items.ShouldContain(r => r.EventType == AuditEventType.Security); } #endregion diff --git a/src/Tests/Integration.Tests/Tests/Authentication/AccountLockoutTests.cs b/src/Tests/Integration.Tests/Tests/Authentication/AccountLockoutTests.cs index e613d5129c..04ef82973b 100644 --- a/src/Tests/Integration.Tests/Tests/Authentication/AccountLockoutTests.cs +++ b/src/Tests/Integration.Tests/Tests/Authentication/AccountLockoutTests.cs @@ -96,8 +96,8 @@ public async Task Login_Should_ResetFailedCount_After_SuccessfulAuthentication() .GetRequiredService>(); var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - var token = await userManager.GenerateEmailConfirmationTokenAsync(user!); - var confirm = await userManager.ConfirmEmailAsync(user!, token); + var token = await userManager.GenerateEmailConfirmationTokenAsync(user); + var confirm = await userManager.ConfirmEmailAsync(user, token); confirm.Succeeded.ShouldBeTrue(); return (email, password); diff --git a/src/Tests/Integration.Tests/Tests/Authentication/TwoFactorAuthTests.cs b/src/Tests/Integration.Tests/Tests/Authentication/TwoFactorAuthTests.cs index 9cbe147ebe..5ece6d65ba 100644 --- a/src/Tests/Integration.Tests/Tests/Authentication/TwoFactorAuthTests.cs +++ b/src/Tests/Integration.Tests/Tests/Authentication/TwoFactorAuthTests.cs @@ -58,7 +58,7 @@ public async Task Enroll_Should_ReturnSharedKey_AndAuthenticatorUri() var enrollment = await DeserializeAsync(response); enrollment.ShouldNotBeNull(); - enrollment!.SharedKey.ShouldNotBeNullOrWhiteSpace(); + enrollment.SharedKey.ShouldNotBeNullOrWhiteSpace(); enrollment.AuthenticatorUri.ShouldStartWith("otpauth://totp/"); enrollment.AuthenticatorUri.ShouldContain("secret="); } @@ -141,8 +141,8 @@ await WithRootTenantScopeAsync(async userManager => { var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - var token = await userManager.GenerateEmailConfirmationTokenAsync(user!); - (await userManager.ConfirmEmailAsync(user!, token)).Succeeded.ShouldBeTrue(); + var token = await userManager.GenerateEmailConfirmationTokenAsync(user); + (await userManager.ConfirmEmailAsync(user, token)).Succeeded.ShouldBeTrue(); }); return (email, password); @@ -162,7 +162,7 @@ private async Task SignInAsync(string email, string password, string var client = _factory.CreateClient(); client.DefaultRequestHeaders.Authorization = - new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token!.AccessToken); + new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.AccessToken); client.DefaultRequestHeaders.Add("tenant", TestConstants.RootTenantId); return client; } @@ -182,8 +182,8 @@ await WithRootTenantScopeAsync(async userManager => { var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - await userManager.ResetAuthenticatorKeyAsync(user!); - await userManager.SetTwoFactorEnabledAsync(user!, true); + await userManager.ResetAuthenticatorKeyAsync(user); + await userManager.SetTwoFactorEnabledAsync(user, true); }); } @@ -193,7 +193,7 @@ await WithRootTenantScopeAsync(async userManager => { var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - await userManager.SetTwoFactorEnabledAsync(user!, enabled); + await userManager.SetTwoFactorEnabledAsync(user, enabled); }); } @@ -204,7 +204,7 @@ await WithRootTenantScopeAsync(async userManager => { var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - enabled = await userManager.GetTwoFactorEnabledAsync(user!); + enabled = await userManager.GetTwoFactorEnabledAsync(user); }); return enabled; } diff --git a/src/Tests/Integration.Tests/Tests/Billing/BillingDomainEdgeTests.cs b/src/Tests/Integration.Tests/Tests/Billing/BillingDomainEdgeTests.cs index c729d7cd97..f8deaa3398 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/BillingDomainEdgeTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/BillingDomainEdgeTests.cs @@ -71,7 +71,7 @@ await SeedDirectAsync(async db => { var domain = await db.Plans.FindAsync(planId); domain.ShouldNotBeNull(); - domain!.GetOverageRate(QuotaResource.ApiCalls).ShouldBe(0.01m); + domain.GetOverageRate(QuotaResource.ApiCalls).ShouldBe(0.01m); domain.GetOverageRate(QuotaResource.Users).ShouldBe(0m, "GetOverageRate returns 0 for a resource with no configured rate"); }); @@ -169,7 +169,7 @@ await SeedDirectAsync(async db => var sub = await db.Subscriptions.AsNoTracking().FirstAsync(s => s.Id == subId); sub.Status.ShouldBe(SubscriptionStatus.Cancelled); sub.EndUtc.ShouldNotBeNull(); - sub.EndUtc!.Value.Date.ShouldBe(endUtc.Date); + sub.EndUtc.Value.Date.ShouldBe(endUtc.Date); sub.EndUtc.Value.Kind.ShouldBe(DateTimeKind.Utc, "Cancel must normalize EndUtc to UTC kind"); }); } diff --git a/src/Tests/Integration.Tests/Tests/Billing/BillingEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Billing/BillingEndpointTests.cs index 590093bb2d..836f51cabd 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/BillingEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/BillingEndpointTests.cs @@ -89,7 +89,7 @@ await SeedDirectAsync(async db => { var plan = await db.Plans.FindAsync(planId); plan.ShouldNotBeNull(); - plan!.Deactivate(); + plan.Deactivate(); await db.SaveChangesAsync(); }); @@ -170,7 +170,7 @@ public async Task AssignSubscription_Should_Return200_And_Persist() var current = await GetSubscriptionAsync(client, TestConstants.RootTenantId); current.ShouldNotBeNull(); - current!.Id.ShouldBe(subscriptionId); + current.Id.ShouldBe(subscriptionId); current.PlanKey.ShouldBe(key, StringCompareShould.IgnoreCase); current.Status.ShouldBe(SubscriptionStatus.Active); } @@ -190,7 +190,7 @@ public async Task AssignSubscription_Should_Replace_Existing_Active_Subscription var current = await GetSubscriptionAsync(client, TestConstants.RootTenantId); current.ShouldNotBeNull(); - current!.Id.ShouldBe(secondSubId, "the second assign must become the active subscription"); + current.Id.ShouldBe(secondSubId, "the second assign must become the active subscription"); current.PlanKey.ShouldBe(secondKey, StringCompareShould.IgnoreCase); // First should be cancelled, not active — visible only through direct DB inspection. @@ -198,7 +198,7 @@ await SeedDirectAsync(async db => { var oldSub = await db.Subscriptions.FindAsync(firstSubId); oldSub.ShouldNotBeNull(); - oldSub!.Status.ShouldBe(SubscriptionStatus.Cancelled, + oldSub.Status.ShouldBe(SubscriptionStatus.Cancelled, "first subscription must be cancelled after the second one is assigned"); }); } @@ -226,7 +226,7 @@ public async Task GetMySubscription_Should_Return_Current_Tenant_Subscription() response.StatusCode.ShouldBe(HttpStatusCode.OK); var dto = await ParseAsync(response); dto.ShouldNotBeNull(); - dto!.Id.ShouldBe(subId); + dto.Id.ShouldBe(subId); dto.TenantId.ShouldBe(TestConstants.RootTenantId); } @@ -305,7 +305,7 @@ await SeedDirectAsync(async db => { var inv = await db.Invoices.FindAsync(paidSourceId); inv.ShouldNotBeNull(); - inv!.Issue(dueAtUtc: null); + inv.Issue(dueAtUtc: null); inv.MarkPaid(); await db.SaveChangesAsync(); }); @@ -354,7 +354,7 @@ public async Task IssueInvoice_Should_Transition_Draft_To_Issued_With_Default_Du dto.Status.ShouldBe(InvoiceStatus.Issued); dto.IssuedAtUtc.ShouldNotBeNull(); dto.DueAtUtc.ShouldNotBeNull(); - var defaultDueDelta = (dto.DueAtUtc!.Value - dto.IssuedAtUtc!.Value).TotalDays; + var defaultDueDelta = (dto.DueAtUtc.Value - dto.IssuedAtUtc.Value).TotalDays; defaultDueDelta.ShouldBe(14.0, tolerance: 0.01, "Default due-date is +14 days from issued time"); } @@ -374,7 +374,7 @@ public async Task IssueInvoice_Should_Use_Custom_DueDate_When_Provided() var dto = await GetInvoiceAsync(client, invoiceId); dto.Status.ShouldBe(InvoiceStatus.Issued); dto.DueAtUtc.ShouldNotBeNull(); - dto.DueAtUtc!.Value.Date.ShouldBe(customDue.Date); + dto.DueAtUtc.Value.Date.ShouldBe(customDue.Date); } [Fact] @@ -470,7 +470,7 @@ public async Task VoidInvoice_Should_Transition_Draft_To_Void() dto.Status.ShouldBe(InvoiceStatus.Void); dto.VoidedAtUtc.ShouldNotBeNull(); dto.Notes.ShouldNotBeNullOrWhiteSpace(); - dto.Notes!.ShouldContain("duplicate"); + dto.Notes.ShouldContain("duplicate"); } [Fact] @@ -666,7 +666,7 @@ await SeedDirectAsync(async db => { var inv = await db.Invoices.FindAsync(id); inv.ShouldNotBeNull(); - inv!.Issue(dueAtUtc: null); + inv.Issue(dueAtUtc: null); await db.SaveChangesAsync(); }); return id; diff --git a/src/Tests/Integration.Tests/Tests/Billing/BillingTenantIsolationTests.cs b/src/Tests/Integration.Tests/Tests/Billing/BillingTenantIsolationTests.cs index ec1630aeef..614e852eb3 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/BillingTenantIsolationTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/BillingTenantIsolationTests.cs @@ -115,7 +115,7 @@ public async Task GetSubscription_Should_NotLeak_When_OtherTenantPassesOwnersTen // Act + Assert — owner reads its own subscription back. var ownerSub = await GetSubscriptionAsync(rootClient, TestConstants.RootTenantId); ownerSub.ShouldNotBeNull("the owning tenant must be able to read its own subscription"); - ownerSub!.Id.ShouldBe(rootSubId); + ownerSub.Id.ShouldBe(rootSubId); ownerSub.TenantId.ShouldBe(TestConstants.RootTenantId); // Act + Assert — tenant B passing root's tenant id must NOT receive root's subscription. @@ -189,7 +189,7 @@ public async Task AssignSubscription_Should_NotAffect_OtherTenant_When_NonRootPa var rootSubAfter = await GetSubscriptionAsync(rootClient, TestConstants.RootTenantId); rootSubAfter.ShouldNotBeNull(); - rootSubAfter!.Id.ShouldBe(rootSubId, + rootSubAfter.Id.ShouldBe(rootSubId, "a tenant must not be able to cancel/replace root's subscription via a foreign tenant id"); } @@ -297,7 +297,7 @@ await SeedDirectAsync(TestConstants.RootTenantId, async db => var generated = await InvokeGenerateInvoiceForPeriodAsync(TestConstants.RootTenantId, year, month); generated.ShouldNotBeNull("the generator must produce an invoice when an active subscription exists"); - generated!.Purpose.ShouldBe(InvoicePurpose.Usage, + generated.Purpose.ShouldBe(InvoicePurpose.Usage, "the usage invoice must be generated even when a subscription invoice already shares the month"); } diff --git a/src/Tests/Integration.Tests/Tests/Billing/MonthlyInvoiceJobTests.cs b/src/Tests/Integration.Tests/Tests/Billing/MonthlyInvoiceJobTests.cs index 24c528f1c0..315162ca9c 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/MonthlyInvoiceJobTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/MonthlyInvoiceJobTests.cs @@ -53,7 +53,7 @@ public async Task RunAsync_Should_Generate_Draft_Invoice_For_Subscribed_Tenant_F var invoice = await GetRootInvoiceForPeriodAsync(previous.Year, previous.Month); invoice.ShouldNotBeNull("MonthlyInvoiceJob must produce a draft invoice for the subscribed root tenant"); - invoice!.Status.ShouldBe(InvoiceStatus.Draft); + invoice.Status.ShouldBe(InvoiceStatus.Draft); invoice.PeriodYear.ShouldBe(previous.Year); invoice.PeriodMonth.ShouldBe(previous.Month); invoice.Purpose.ShouldBe(InvoicePurpose.Usage, "the monthly job produces usage invoices"); diff --git a/src/Tests/Integration.Tests/Tests/Billing/TenantBillingLifecycleTests.cs b/src/Tests/Integration.Tests/Tests/Billing/TenantBillingLifecycleTests.cs index 234d6a1e1d..1535ee2121 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/TenantBillingLifecycleTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/TenantBillingLifecycleTests.cs @@ -52,7 +52,7 @@ public async Task CreateTenant_With_Paid_Plan_Should_Start_Subscription_And_Issu var subscription = await rootClient.GetFromJsonAsync( $"{BillingBasePath}/subscriptions?tenantId={tenantId}", Json); subscription.ShouldNotBeNull("creating a tenant must start a subscription"); - subscription!.PlanKey.ShouldBe(planKey); + subscription.PlanKey.ShouldBe(planKey); subscription.Status.ShouldBe(SubscriptionStatus.Active); // Exactly one issued subscription invoice for the plan term price. @@ -66,7 +66,7 @@ public async Task CreateTenant_With_Paid_Plan_Should_Start_Subscription_And_Issu var status = await rootClient.GetFromJsonAsync( $"{TestConstants.TenantsBasePath}/{tenantId}/status", Json); status.ShouldNotBeNull(); - status!.Plan.ShouldBe(planKey); + status.Plan.ShouldBe(planKey); status.ValidUpto!.Value.ShouldBeGreaterThan(DateTime.UtcNow.AddDays(27)); status.ValidUpto.Value.ShouldBeLessThan(DateTime.UtcNow.AddDays(32)); } @@ -84,7 +84,7 @@ public async Task CreateTenant_With_Free_Plan_Should_Start_Subscription_Without_ var subscription = await rootClient.GetFromJsonAsync( $"{BillingBasePath}/subscriptions?tenantId={tenantId}", Json); subscription.ShouldNotBeNull("a free plan still gets a subscription"); - subscription!.Status.ShouldBe(SubscriptionStatus.Active); + subscription.Status.ShouldBe(SubscriptionStatus.Active); var invoices = await GetInvoicesAsync(rootClient, tenantId); invoices.Any(i => i.Purpose == InvoicePurpose.Subscription) @@ -96,7 +96,7 @@ private static async Task> GetInvoicesAsync(Http var page = await client.GetFromJsonAsync>( $"{BillingBasePath}/invoices?tenantId={tenantId}&pageNumber=1&pageSize=50", Json); page.ShouldNotBeNull(); - return page!.Items; + return page.Items; } private static async Task CreatePlanAsync(HttpClient client, string key, decimal monthlyBasePrice) diff --git a/src/Tests/Integration.Tests/Tests/Billing/TopupApprovalTests.cs b/src/Tests/Integration.Tests/Tests/Billing/TopupApprovalTests.cs index 32cf80a608..9f72fccc3c 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/TopupApprovalTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/TopupApprovalTests.cs @@ -64,7 +64,7 @@ await InspectDirectAsync(TestConstants.RootTenantId, async db => { var request = await db.TopupRequests.FindAsync(requestId); request.ShouldNotBeNull(); - request!.Status.ShouldBe(TopupRequestStatus.Invoiced, "request must be Invoiced after approval"); + request.Status.ShouldBe(TopupRequestStatus.Invoiced, "request must be Invoiced after approval"); request.InvoiceId.ShouldBe(invoiceId, "request.InvoiceId must match the returned invoice id"); }); @@ -73,7 +73,7 @@ await InspectDirectAsync(TestConstants.RootTenantId, async db => { var invoice = await db.Invoices.FindAsync(invoiceId); invoice.ShouldNotBeNull(); - invoice!.TenantId.ShouldBe(TestConstants.RootTenantId); + invoice.TenantId.ShouldBe(TestConstants.RootTenantId); invoice.Purpose.ShouldBe(InvoicePurpose.Topup); invoice.Status.ShouldBe(InvoiceStatus.Issued); }); @@ -102,7 +102,7 @@ await InspectDirectAsync(TestConstants.RootTenantId, async db => { var request = await db.TopupRequests.FindAsync(requestId); request.ShouldNotBeNull(); - request!.Status.ShouldBe(TopupRequestStatus.Rejected); + request.Status.ShouldBe(TopupRequestStatus.Rejected); request.DecisionNote.ShouldBe("rejected in integration test"); }); } diff --git a/src/Tests/Integration.Tests/Tests/Billing/UsageSnapshotQueryTests.cs b/src/Tests/Integration.Tests/Tests/Billing/UsageSnapshotQueryTests.cs index c85fc017eb..81fb95e3ae 100644 --- a/src/Tests/Integration.Tests/Tests/Billing/UsageSnapshotQueryTests.cs +++ b/src/Tests/Integration.Tests/Tests/Billing/UsageSnapshotQueryTests.cs @@ -322,7 +322,7 @@ private async Task ConfirmEmailAsync(string userId) .GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Caching/HybridCacheRedisTests.cs b/src/Tests/Integration.Tests/Tests/Caching/HybridCacheRedisTests.cs index 95776b9108..26f9fe87c8 100644 --- a/src/Tests/Integration.Tests/Tests/Caching/HybridCacheRedisTests.cs +++ b/src/Tests/Integration.Tests/Tests/Caching/HybridCacheRedisTests.cs @@ -81,7 +81,7 @@ public async Task SetAsync_Should_Persist_Bytes_To_Redis() // Read the underlying L2 directly to confirm bytes are present. var raw = await distributedCache.GetAsync("rt:set"); raw.ShouldNotBeNull(); - raw!.Length.ShouldBeGreaterThan(0); + raw.Length.ShouldBeGreaterThan(0); } } diff --git a/src/Tests/Integration.Tests/Tests/Catalog/BrandsEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/BrandsEndpointTests.cs index e3c1556846..696a944460 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/BrandsEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/BrandsEndpointTests.cs @@ -119,7 +119,7 @@ public async Task DeleteBrand_Should_HideFromSearch_But_Keep_Row_For_Restore() var trash = await trashResponse.DeserializeAsync>(); var trashed = trash.Items.FirstOrDefault(b => b.Id == brandId); trashed.ShouldNotBeNull("Soft-deleted brand should appear in /brands/trash."); - trashed!.DeletedOnUtc.ShouldNotBeNull(); + trashed.DeletedOnUtc.ShouldNotBeNull(); trashed.DeletedBy.ShouldNotBeNullOrWhiteSpace(); } diff --git a/src/Tests/Integration.Tests/Tests/Catalog/CategoriesEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/CategoriesEndpointTests.cs index e3adac5de3..62babc9aaa 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/CategoriesEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/CategoriesEndpointTests.cs @@ -157,7 +157,7 @@ public async Task GetCategoryTree_Should_Expose_Child_Under_Parent() var parentNode = tree.FirstOrDefault(n => n.Id == parentId); parentNode.ShouldNotBeNull("the freshly created parent must appear at the root level of the tree"); - parentNode!.Children.ShouldContain(n => n.Id == childId, + parentNode.Children.ShouldContain(n => n.Id == childId, "the child must be nested under its parent in the tree response"); } @@ -228,7 +228,7 @@ public async Task DeleteCategory_Should_HideFromSearch_But_Keep_Row_For_Restore( var trash = await trashResponse.DeserializeAsync>(); var trashed = trash.Items.FirstOrDefault(c => c.Id == categoryId); trashed.ShouldNotBeNull("Soft-deleted category should appear in /categories/trash."); - trashed!.DeletedOnUtc.ShouldNotBeNull(); + trashed.DeletedOnUtc.ShouldNotBeNull(); trashed.DeletedBy.ShouldNotBeNullOrWhiteSpace(); } diff --git a/src/Tests/Integration.Tests/Tests/Catalog/ProductFileAccessPolicyTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/ProductFileAccessPolicyTests.cs index 49bae83518..4c650a3752 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/ProductFileAccessPolicyTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/ProductFileAccessPolicyTests.cs @@ -229,7 +229,7 @@ private static async Task UploadImageAsync(HttpClient client, Guid product var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Catalog/ProductImageRemoveReorderTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/ProductImageRemoveReorderTests.cs index 122d8baafd..d84e9d771d 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/ProductImageRemoveReorderTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/ProductImageRemoveReorderTests.cs @@ -369,6 +369,6 @@ private static async Task GetProductAsync(HttpClient client, Guid pr var meta = await metaResp.DeserializeAsync(); meta.PublicUrl.ShouldNotBeNullOrWhiteSpace(); - return (presigned.FileAssetId, meta.PublicUrl!); + return (presigned.FileAssetId, meta.PublicUrl); } } diff --git a/src/Tests/Integration.Tests/Tests/Catalog/ProductImagesTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/ProductImagesTests.cs index 2d4795f4a9..81b8a22f39 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/ProductImagesTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/ProductImagesTests.cs @@ -291,7 +291,7 @@ private static async Task GetProductAsync(HttpClient client, Guid pr var meta = await metaResp.DeserializeAsync(); meta.PublicUrl.ShouldNotBeNullOrWhiteSpace("Public files should return a durable publicUrl from GetFileMetadata"); - return (presigned.FileAssetId, meta.PublicUrl!); + return (presigned.FileAssetId, meta.PublicUrl); } // Lightweight projection — the test only needs Id off the category row. Setter is required diff --git a/src/Tests/Integration.Tests/Tests/Catalog/ProductsEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Catalog/ProductsEndpointTests.cs index 462d7cfc33..582e946af9 100644 --- a/src/Tests/Integration.Tests/Tests/Catalog/ProductsEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Catalog/ProductsEndpointTests.cs @@ -230,7 +230,7 @@ public async Task DeleteProduct_Should_Hide_From_Search_But_Keep_Row_For_Restore var trash = await trashResponse.DeserializeAsync>(); var trashed = trash.Items.FirstOrDefault(p => p.Id == productId); trashed.ShouldNotBeNull("soft-deleted product should appear in /products/trash"); - trashed!.DeletedOnUtc.ShouldNotBeNull(); + trashed.DeletedOnUtc.ShouldNotBeNull(); trashed.DeletedBy.ShouldNotBeNullOrWhiteSpace(); } diff --git a/src/Tests/Integration.Tests/Tests/Chat/ChatChannelFileAccessTests.cs b/src/Tests/Integration.Tests/Tests/Chat/ChatChannelFileAccessTests.cs index e089942a24..746a105196 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/ChatChannelFileAccessTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/ChatChannelFileAccessTests.cs @@ -131,7 +131,7 @@ private static async Task CreateChannelAsync(HttpClient client, string nam var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/ChatSendMessageTests.cs b/src/Tests/Integration.Tests/Tests/Chat/ChatSendMessageTests.cs index 28bbd65535..5cf32207d2 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/ChatSendMessageTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/ChatSendMessageTests.cs @@ -396,7 +396,7 @@ private async Task ConfirmEmailAsync(string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/JoinChannelTests.cs b/src/Tests/Integration.Tests/Tests/Chat/JoinChannelTests.cs index 1167ad2a9b..3d60bae07d 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/JoinChannelTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/JoinChannelTests.cs @@ -157,7 +157,7 @@ private static async Task SendMessageAsync(HttpClient client, Guid channelId, st var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/MentionAndNotificationTests.cs b/src/Tests/Integration.Tests/Tests/Chat/MentionAndNotificationTests.cs index eaebe88f92..313fb1d127 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/MentionAndNotificationTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/MentionAndNotificationTests.cs @@ -48,10 +48,10 @@ public async Task SendingMessage_With_AtMention_Should_Persist_Notification_For_ var inbox = await ReadInboxAsync(aliceClient); var mention = inbox.FirstOrDefault(n => n.Type == "chat.mention"); mention.ShouldNotBeNull("Expected a chat.mention notification to land in Alice's inbox"); - mention!.Body.ShouldNotBeNullOrEmpty(); - mention.Body!.ShouldContain("take a look"); + mention.Body.ShouldNotBeNullOrEmpty(); + mention.Body.ShouldContain("take a look"); mention.Link.ShouldNotBeNull(); - mention.Link!.ShouldStartWith($"/chat/{channelId}"); + mention.Link.ShouldStartWith($"/chat/{channelId}"); mention.ReadAtUtc.ShouldBeNull(); } @@ -71,7 +71,7 @@ public async Task SendingMessage_With_AtMention_Should_Push_NotificationCreated_ var received = await inbox.WaitForFirstAsync(p => p.Type == "chat.mention", EventTimeout); received.ShouldNotBeNull("Expected NotificationCreated to fire on Bob's hub connection"); - received!.Title.ShouldNotBeNullOrWhiteSpace(); + received.Title.ShouldNotBeNullOrWhiteSpace(); received.Link.ShouldStartWith($"/chat/{channelId}"); } @@ -187,7 +187,7 @@ private async Task ConfirmEmailAsync(string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/PinMessageTests.cs b/src/Tests/Integration.Tests/Tests/Chat/PinMessageTests.cs index f7c202a59a..da0315d729 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/PinMessageTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/PinMessageTests.cs @@ -197,7 +197,7 @@ public async Task PinMessage_Should_Broadcast_ChatMessagePinned_On_Channel_Group var received = await inbox.WaitForFirstAsync(p => p.Id == messageId, EventTimeout); received.ShouldNotBeNull("Expected ChatMessagePinned to fire on Bob's hub connection"); - received!.IsPinned.ShouldBeTrue(); + received.IsPinned.ShouldBeTrue(); received.PinnedByUserId.ShouldNotBeNullOrEmpty(); } @@ -220,7 +220,7 @@ public async Task UnpinMessage_Should_Broadcast_ChatMessageUnpinned_On_Channel_G var received = await inbox.WaitForFirstAsync(p => p.Id == messageId, EventTimeout); received.ShouldNotBeNull("Expected ChatMessageUnpinned to fire on Carol's hub connection"); - received!.IsPinned.ShouldBeFalse(); + received.IsPinned.ShouldBeFalse(); } // ─── helpers (lifted from MentionAndNotificationTests pattern) ─── @@ -319,7 +319,7 @@ private async Task ConfirmEmailAsync(string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/PresenceTests.cs b/src/Tests/Integration.Tests/Tests/Chat/PresenceTests.cs index 8b1b84714f..179985e78e 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/PresenceTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/PresenceTests.cs @@ -219,7 +219,7 @@ private async Task ConfirmEmailAsync(string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/SearchMessagesTests.cs b/src/Tests/Integration.Tests/Tests/Chat/SearchMessagesTests.cs index 09f099c198..89ecdcfe66 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/SearchMessagesTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/SearchMessagesTests.cs @@ -147,7 +147,7 @@ private async Task RegisterAndConfirmAsync(HttpClient adminClient, string prefix var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Chat/TypingIndicatorTests.cs b/src/Tests/Integration.Tests/Tests/Chat/TypingIndicatorTests.cs index e1317b10c8..0a0be4bcc2 100644 --- a/src/Tests/Integration.Tests/Tests/Chat/TypingIndicatorTests.cs +++ b/src/Tests/Integration.Tests/Tests/Chat/TypingIndicatorTests.cs @@ -173,7 +173,7 @@ private static async Task AddMemberAsync(HttpClient client, Guid channelId, stri var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Eventing/OutboxRetryTests.cs b/src/Tests/Integration.Tests/Tests/Eventing/OutboxRetryTests.cs index 4bf1340a64..e68c76943e 100644 --- a/src/Tests/Integration.Tests/Tests/Eventing/OutboxRetryTests.cs +++ b/src/Tests/Integration.Tests/Tests/Eventing/OutboxRetryTests.cs @@ -36,7 +36,7 @@ public async Task MarkAsFailed_NotDead_Should_BackOff_And_ExcludeFromPendingUnti await store.MarkAsFailedAsync(message, "transient boom", isDead: false); message.NextRetryAt.ShouldNotBeNull("a non-dead failure must schedule a backed-off retry"); - message.NextRetryAt!.Value.ShouldBeGreaterThan( + message.NextRetryAt.Value.ShouldBeGreaterThan( DateTime.UtcNow.AddSeconds(20), "the first retry backs off by the base delay (30s), not the next 10s cycle"); diff --git a/src/Tests/Integration.Tests/Tests/Files/FileVisibilityAndSharingTests.cs b/src/Tests/Integration.Tests/Tests/Files/FileVisibilityAndSharingTests.cs index 719ddd9974..690f915be1 100644 --- a/src/Tests/Integration.Tests/Tests/Files/FileVisibilityAndSharingTests.cs +++ b/src/Tests/Integration.Tests/Tests/Files/FileVisibilityAndSharingTests.cs @@ -274,7 +274,7 @@ private async Task RegisterAndLoginAsync(string prefix) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(registered.UserId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Files/PurgeJobsTests.cs b/src/Tests/Integration.Tests/Tests/Files/PurgeJobsTests.cs index a6a2f8eaea..80e8bd7868 100644 --- a/src/Tests/Integration.Tests/Tests/Files/PurgeJobsTests.cs +++ b/src/Tests/Integration.Tests/Tests/Files/PurgeJobsTests.cs @@ -77,7 +77,7 @@ public void PurgeDeletedFilesJob_RunAsync_Should_Be_Annotated_With_AutomaticRetr var method = typeof(PurgeDeletedFilesJob).GetMethod( nameof(PurgeDeletedFilesJob.RunAsync), BindingFlags.Public | BindingFlags.Instance); method.ShouldNotBeNull(); - method!.GetCustomAttribute().ShouldNotBeNull(); + method.GetCustomAttribute().ShouldNotBeNull(); } #endregion @@ -122,7 +122,7 @@ public void PurgeOrphanedFilesJob_RunAsync_Should_Be_Annotated_With_AutomaticRet var method = typeof(PurgeOrphanedFilesJob).GetMethod( nameof(PurgeOrphanedFilesJob.RunAsync), BindingFlags.Public | BindingFlags.Instance); method.ShouldNotBeNull(); - method!.GetCustomAttribute().ShouldNotBeNull(); + method.GetCustomAttribute().ShouldNotBeNull(); } #endregion @@ -245,6 +245,6 @@ private async Task ReadStorageKeyAsync(Guid id) .Select(f => f.StorageKey) .FirstOrDefaultAsync(); key.ShouldNotBeNull(); - return key!; + return key; } } diff --git a/src/Tests/Integration.Tests/Tests/Files/StorageFlowTests.cs b/src/Tests/Integration.Tests/Tests/Files/StorageFlowTests.cs index 9061e75340..d2e9a89c01 100644 --- a/src/Tests/Integration.Tests/Tests/Files/StorageFlowTests.cs +++ b/src/Tests/Integration.Tests/Tests/Files/StorageFlowTests.cs @@ -64,7 +64,7 @@ public async Task DownloadUrl_Should_Request_Attachment_Disposition_With_Origina var disposition = getResp.Content.Headers.ContentDisposition; disposition.ShouldNotBeNull(); - disposition!.DispositionType.ShouldBe("attachment"); + disposition.DispositionType.ShouldBe("attachment"); // The original filename is echoed back so the browser surfaces it instead of the storage key. disposition.FileName!.Trim('"').ShouldBe("report-final.pdf"); } @@ -85,7 +85,7 @@ public async Task DownloadUrl_Should_Request_Inline_Disposition_When_Inline_True var disposition = getResp.Content.Headers.ContentDisposition; disposition.ShouldNotBeNull(); - disposition!.DispositionType.ShouldBe("inline"); + disposition.DispositionType.ShouldBe("inline"); } #endregion diff --git a/src/Tests/Integration.Tests/Tests/Health/TenantMigrationsHealthCheckTests.cs b/src/Tests/Integration.Tests/Tests/Health/TenantMigrationsHealthCheckTests.cs index 2c9704dc78..a66428f84c 100644 --- a/src/Tests/Integration.Tests/Tests/Health/TenantMigrationsHealthCheckTests.cs +++ b/src/Tests/Integration.Tests/Tests/Health/TenantMigrationsHealthCheckTests.cs @@ -46,7 +46,7 @@ public async Task CheckHealthAsync_Should_TransitionFromUnhealthyToHealthy_AsMig var beforeResult = await check.CheckHealthAsync(context, CancellationToken.None); beforeResult.Status.ShouldBe(HealthStatus.Unhealthy); beforeResult.Description.ShouldNotBeNull(); - beforeResult.Description!.ShouldContain("FSH.Starter.DbMigrator"); + beforeResult.Description.ShouldContain("FSH.Starter.DbMigrator"); // ── Apply migrations (what DbMigrator does in production) ──────── using (var scope = provider.CreateScope()) @@ -76,7 +76,7 @@ public async Task CheckHealthAsync_Should_ReturnUnhealthy_When_TenantProbeThrows var result = await check.CheckHealthAsync(context, CancellationToken.None); result.Status.ShouldBe(HealthStatus.Unhealthy); result.Description.ShouldNotBeNull(); - result.Description!.ShouldContain("error probing tenant", Case.Insensitive); + result.Description.ShouldContain("error probing tenant", Case.Insensitive); } private ServiceProvider BuildServiceProvider(bool badConnectionString = false) diff --git a/src/Tests/Integration.Tests/Tests/Impersonation/ImpersonationTests.cs b/src/Tests/Integration.Tests/Tests/Impersonation/ImpersonationTests.cs index 7fa142a43f..923abc5cfb 100644 --- a/src/Tests/Integration.Tests/Tests/Impersonation/ImpersonationTests.cs +++ b/src/Tests/Integration.Tests/Tests/Impersonation/ImpersonationTests.cs @@ -879,7 +879,7 @@ private async Task ConfirmEmailAsync(string tenantId, string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Multitenancy/AdjustTenantValidityTests.cs b/src/Tests/Integration.Tests/Tests/Multitenancy/AdjustTenantValidityTests.cs index 6f573ebb9e..e16a33f422 100644 --- a/src/Tests/Integration.Tests/Tests/Multitenancy/AdjustTenantValidityTests.cs +++ b/src/Tests/Integration.Tests/Tests/Multitenancy/AdjustTenantValidityTests.cs @@ -204,7 +204,7 @@ private static async Task GetStatusAsync(HttpClient client, string resp.StatusCode.ShouldBe(HttpStatusCode.OK); var status = await resp.Content.ReadFromJsonAsync(Json); status.ShouldNotBeNull(); - return status!; + return status; } private static async Task WaitForProvisioningAsync(HttpClient client, string tenantId, int maxRetries = 60) diff --git a/src/Tests/Integration.Tests/Tests/Multitenancy/MyTenantStatusTests.cs b/src/Tests/Integration.Tests/Tests/Multitenancy/MyTenantStatusTests.cs index 6b9f2fca30..8bdca2661e 100644 --- a/src/Tests/Integration.Tests/Tests/Multitenancy/MyTenantStatusTests.cs +++ b/src/Tests/Integration.Tests/Tests/Multitenancy/MyTenantStatusTests.cs @@ -45,7 +45,7 @@ public async Task GetMyStatus_Should_Return_CallersOwn_Plan_And_ExpiryState() var status = await resp.Content.ReadFromJsonAsync(Json); status.ShouldNotBeNull(); - status!.Id.ShouldBe(tenantId); + status.Id.ShouldBe(tenantId); status.Plan.ShouldBe(planKey); status.ExpiryState.ShouldBe("Active"); } diff --git a/src/Tests/Integration.Tests/Tests/Multitenancy/RenewTenantTests.cs b/src/Tests/Integration.Tests/Tests/Multitenancy/RenewTenantTests.cs index a56e608a3d..cb89d328dd 100644 --- a/src/Tests/Integration.Tests/Tests/Multitenancy/RenewTenantTests.cs +++ b/src/Tests/Integration.Tests/Tests/Multitenancy/RenewTenantTests.cs @@ -154,9 +154,9 @@ public async Task RenewTenant_Should_Advance_SubscriptionEndUtc_On_SamePlanRenew await OutboxDrain.DrainAsync(_factory.Services); - var after = await PollSubscriptionEndUtcAdvancedAsync(rootClient, tenantId, before!.Value); + var after = await PollSubscriptionEndUtcAdvancedAsync(rootClient, tenantId, before.Value); after.ShouldNotBeNull(); - after!.Value.ShouldBeGreaterThan(before.Value, + after.Value.ShouldBeGreaterThan(before.Value, "a same-plan renewal must extend Subscription.EndUtc, not just tenant ValidUpto"); after.Value.ShouldBe(result.ValidUpto, tolerance: TimeSpan.FromSeconds(5), "the subscription term should track the renewed validity"); @@ -265,7 +265,7 @@ private static async Task RenewAsync(HttpClient client, string tena response.StatusCode.ShouldBe(HttpStatusCode.OK, await response.Content.ReadAsStringAsync()); var result = await response.Content.ReadFromJsonAsync(Json); result.ShouldNotBeNull(); - return result!; + return result; } private static async Task CreatePlanAsync(HttpClient client, string key, decimal monthlyBasePrice) @@ -306,7 +306,7 @@ private static async Task GetStatusAsync(HttpClient client, string resp.StatusCode.ShouldBe(HttpStatusCode.OK); var status = await resp.Content.ReadFromJsonAsync(Json); status.ShouldNotBeNull(); - return status!; + return status; } private static async Task WaitForProvisioningAsync(HttpClient client, string tenantId, int maxRetries = 60) diff --git a/src/Tests/Integration.Tests/Tests/Multitenancy/TenantExpiryEnforcementTests.cs b/src/Tests/Integration.Tests/Tests/Multitenancy/TenantExpiryEnforcementTests.cs index 0f218983d1..4db020164e 100644 --- a/src/Tests/Integration.Tests/Tests/Multitenancy/TenantExpiryEnforcementTests.cs +++ b/src/Tests/Integration.Tests/Tests/Multitenancy/TenantExpiryEnforcementTests.cs @@ -64,7 +64,7 @@ public async Task LapsedTenant_WithinGrace_Should_Emit_GraceHeader() status.ShouldNotBe(HttpStatusCode.Forbidden); grace.ShouldNotBeNull("a tenant in the grace period must receive the X-Subscription-Grace header"); - int.Parse(grace!, CultureInfo.InvariantCulture).ShouldBeInRange(1, 7); + int.Parse(grace, CultureInfo.InvariantCulture).ShouldBeInRange(1, 7); } [Fact] @@ -107,7 +107,7 @@ private async Task SetTenantValidityAsync(string tenantId, DateTime validUpto) var tenant = await efStore.GetAsync(tenantId); tenant.ShouldNotBeNull(); // Set directly (SetValidity forbids moving the date backward, which is exactly what we need here). - tenant!.ValidUpto = DateTime.SpecifyKind(validUpto, DateTimeKind.Utc); + tenant.ValidUpto = DateTime.SpecifyKind(validUpto, DateTimeKind.Utc); await efStore.UpdateAsync(tenant); var cacheStore = stores.FirstOrDefault(s => s.GetType() == typeof(DistributedCacheStore)); diff --git a/src/Tests/Integration.Tests/Tests/Notifications/NotificationsEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Notifications/NotificationsEndpointTests.cs index 9c126b62a5..14b3da165c 100644 --- a/src/Tests/Integration.Tests/Tests/Notifications/NotificationsEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Notifications/NotificationsEndpointTests.cs @@ -393,7 +393,7 @@ private async Task ConfirmEmailAsync(string userId) var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByIdAsync(userId); user.ShouldNotBeNull(); - if (!user!.EmailConfirmed) + if (!user.EmailConfirmed) { user.EmailConfirmed = true; (await userManager.UpdateAsync(user)).Succeeded.ShouldBeTrue(); diff --git a/src/Tests/Integration.Tests/Tests/Sessions/IdentityUserSeeder.cs b/src/Tests/Integration.Tests/Tests/Sessions/IdentityUserSeeder.cs index bc343466e1..cb8ffd68fb 100644 --- a/src/Tests/Integration.Tests/Tests/Sessions/IdentityUserSeeder.cs +++ b/src/Tests/Integration.Tests/Tests/Sessions/IdentityUserSeeder.cs @@ -60,11 +60,11 @@ public static async Task CreateLoginableUserAsync( var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByEmailAsync(email); user.ShouldNotBeNull(); - var token = await userManager.GenerateEmailConfirmationTokenAsync(user!); - var confirm = await userManager.ConfirmEmailAsync(user!, token); + var token = await userManager.GenerateEmailConfirmationTokenAsync(user); + var confirm = await userManager.ConfirmEmailAsync(user, token); confirm.Succeeded.ShouldBeTrue(); - return new SeededUser(registered!.UserId, email, password); + return new SeededUser(registered.UserId, email, password); } } diff --git a/src/Tests/Integration.Tests/Tests/Tickets/TicketsEndpointTests.cs b/src/Tests/Integration.Tests/Tests/Tickets/TicketsEndpointTests.cs index eb4591ac24..cd32a7fed2 100644 --- a/src/Tests/Integration.Tests/Tests/Tickets/TicketsEndpointTests.cs +++ b/src/Tests/Integration.Tests/Tests/Tickets/TicketsEndpointTests.cs @@ -199,7 +199,7 @@ public async Task DeleteTicket_Should_HideFromSearch_But_Show_In_Trash() var trash = await trashResponse.DeserializeAsync>(); var trashed = trash.Items.FirstOrDefault(t => t.Id == ticketId); trashed.ShouldNotBeNull(); - trashed!.DeletedOnUtc.ShouldNotBeNull(); + trashed.DeletedOnUtc.ShouldNotBeNull(); } [Fact] diff --git a/src/Tests/Integration.Tests/Tests/Users/UserProfileTests.cs b/src/Tests/Integration.Tests/Tests/Users/UserProfileTests.cs index 937ff727e2..1b5dad3deb 100644 --- a/src/Tests/Integration.Tests/Tests/Users/UserProfileTests.cs +++ b/src/Tests/Integration.Tests/Tests/Users/UserProfileTests.cs @@ -129,7 +129,7 @@ public async Task GetProfile_Should_ReturnStrongETag_When_ProfileIsRead() // Assert — If-Match mandates strong comparison, so the tag must not be weak. response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Headers.ETag.ShouldNotBeNull(); - response.Headers.ETag!.IsWeak.ShouldBeFalse(); + response.Headers.ETag.IsWeak.ShouldBeFalse(); response.Headers.ETag.Tag.ShouldStartWith("\""); response.Headers.ETag.Tag.ShouldEndWith("\""); } @@ -327,7 +327,7 @@ public async Task GetProfile_Should_ExposeETagToCrossOriginCallers_When_ProfileI response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Headers.ETag.ShouldNotBeNull(); response.Headers.TryGetValues("Access-Control-Expose-Headers", out var exposedHeaders).ShouldBeTrue(); - exposedHeaders! + exposedHeaders .SelectMany(value => value.Split(',')) .Select(value => value.Trim()) .ShouldContain(value => string.Equals(value, "ETag", StringComparison.OrdinalIgnoreCase)); @@ -338,7 +338,7 @@ private static async Task ReadProfileETagAsync(HttpClient client) var response = await client.GetAsync($"{TestConstants.IdentityBasePath}/profile"); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Headers.ETag.ShouldNotBeNull(); - return response.Headers.ETag!.ToString(); + return response.Headers.ETag.ToString(); } private static async Task PutProfileAsync(HttpClient client, object body, string? ifMatch) diff --git a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDeliveryTests.cs b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDeliveryTests.cs index dc26b83913..90abbcb60b 100644 --- a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDeliveryTests.cs +++ b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDeliveryTests.cs @@ -346,7 +346,7 @@ private static async Task> GetDeliveriesAsync( response.StatusCode.ShouldBe(HttpStatusCode.OK); var result = await response.Content.ReadFromJsonAsync>(); result.ShouldNotBeNull(); - return result!; + return result; } private static void SetRootTenantContext(IServiceProvider sp) diff --git a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchJobTests.cs b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchJobTests.cs index 756e66c82f..ab034388ac 100644 --- a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchJobTests.cs +++ b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchJobTests.cs @@ -34,10 +34,10 @@ public void DispatchAsync_Should_BeAnnotated_WithAutomaticRetry_ExponentialBacko method.ShouldNotBeNull(); - var retry = method!.GetCustomAttribute(); + var retry = method.GetCustomAttribute(); retry.ShouldNotBeNull("WebhookDispatchJob.DispatchAsync must be decorated with [AutomaticRetry] so Hangfire reschedules failed deliveries."); - retry!.Attempts.ShouldBe(4); + retry.Attempts.ShouldBe(4); retry.OnAttemptsExceeded.ShouldBe(AttemptsExceededAction.Fail); var delaysField = typeof(AutomaticRetryAttribute).GetField( @@ -48,7 +48,7 @@ public void DispatchAsync_Should_BeAnnotated_WithAutomaticRetry_ExponentialBacko { var delays = (int[]?)delaysField.GetValue(retry); delays.ShouldNotBeNull(); - delays!.Length.ShouldBeGreaterThan(0); + delays.Length.ShouldBeGreaterThan(0); // Verify backoff actually grows (exponential-ish). for (int i = 1; i < delays.Length; i++) { @@ -103,7 +103,7 @@ await Should.ThrowAsync(() => .FirstOrDefaultAsync(d => d.SubscriptionId == subscriptionId && d.EventType == uniqueEvent); delivery.ShouldNotBeNull("Dispatch job must persist a WebhookDelivery row even when the attempt fails."); - delivery!.Success.ShouldBeFalse(); + delivery.Success.ShouldBeFalse(); delivery.AttemptCount.ShouldBe(1); delivery.ErrorMessage.ShouldNotBeNullOrWhiteSpace(); } diff --git a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchOutcomeTests.cs b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchOutcomeTests.cs index 13db2b9ee8..2d923fa625 100644 --- a/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchOutcomeTests.cs +++ b/src/Tests/Integration.Tests/Tests/Webhooks/WebhookDispatchOutcomeTests.cs @@ -47,7 +47,7 @@ public async Task DispatchAsync_Should_PersistSuccessRow_And_NotThrow_When_Remot transport.WasInvoked.ShouldBeTrue(); var delivery = await ReadLatestDeliveryAsync(capturingFactory, subscriptionId); delivery.ShouldNotBeNull(); - delivery!.Success.ShouldBeTrue(); + delivery.Success.ShouldBeTrue(); delivery.HttpStatusCode.ShouldBe(200); delivery.AttemptCount.ShouldBe(1); delivery.ErrorMessage.ShouldBeNull(); @@ -71,7 +71,7 @@ public async Task DispatchAsync_Should_PersistFailureRow_And_NotThrow_When_Remot var delivery = await ReadLatestDeliveryAsync(capturingFactory, subscriptionId); delivery.ShouldNotBeNull(); - delivery!.Success.ShouldBeFalse(); + delivery.Success.ShouldBeFalse(); delivery.HttpStatusCode.ShouldBe(400); } @@ -91,7 +91,7 @@ await Should.ThrowAsync(() => var delivery = await ReadLatestDeliveryAsync(capturingFactory, subscriptionId); delivery.ShouldNotBeNull(); - delivery!.Success.ShouldBeFalse(); + delivery.Success.ShouldBeFalse(); delivery.HttpStatusCode.ShouldBe(503); } diff --git a/src/Tests/Multitenancy.Tests/Services/FinbuckleEventTenantScopeTests.cs b/src/Tests/Multitenancy.Tests/Services/FinbuckleEventTenantScopeTests.cs index 8dc9a23836..a01c9aeca1 100644 --- a/src/Tests/Multitenancy.Tests/Services/FinbuckleEventTenantScopeTests.cs +++ b/src/Tests/Multitenancy.Tests/Services/FinbuckleEventTenantScopeTests.cs @@ -19,7 +19,7 @@ public void Begin_Should_SetTenantContext_When_TenantIdProvided() using (sut.Begin("acme")) { _accessor.MultiTenantContext.TenantInfo.ShouldNotBeNull(); - _accessor.MultiTenantContext.TenantInfo!.Id.ShouldBe("acme"); + _accessor.MultiTenantContext.TenantInfo.Id.ShouldBe("acme"); _accessor.MultiTenantContext.TenantInfo.Identifier.ShouldBe("acme"); } } @@ -37,7 +37,7 @@ public void Begin_Should_RestorePreviousContext_When_Disposed() _accessor.MultiTenantContext.TenantInfo!.Id.ShouldBe("acme"); } - _accessor.MultiTenantContext.TenantInfo!.Id.ShouldBe("root"); + _accessor.MultiTenantContext.TenantInfo.Id.ShouldBe("root"); } [Fact] @@ -55,7 +55,7 @@ public void Begin_Should_LeaveContextUntouched_When_TenantIdNullOrWhitespace() using (sut.Begin(" ")) { - _accessor.MultiTenantContext.TenantInfo!.Id.ShouldBe("root"); + _accessor.MultiTenantContext.TenantInfo.Id.ShouldBe("root"); } }