From d608ab1a6ddc99ed21539b2dd985e3d438fc975b Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 19 Jan 2026 11:17:36 +0100 Subject: [PATCH] Refactor CORS config; add architectural commentary Refactored CORS setup to be environment-aware, restricting origins in production and relaxing in development. Added extensive comments and discussion on service and repository layer design, including clean architecture best practices and CQRS/MediatR considerations. No changes to business logic; documentation and intent clarified for maintainers. --- DbFirst.API/Program.cs | 12 +++++++----- DbFirst.Application/Catalogs/CatalogService.cs | 10 ++++++++++ DbFirst.Domain/Repositories/ICatalogRepository.cs | 13 +++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/DbFirst.API/Program.cs b/DbFirst.API/Program.cs index 12ce93e..58145d7 100644 --- a/DbFirst.API/Program.cs +++ b/DbFirst.API/Program.cs @@ -14,20 +14,22 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // TODO: allow listed origins configured in appsettings.json +// In any case, dont let them to free to use without cors. if there is no origin specified, block all. +// In development you can keep it easy. builder.Services.AddCors(options => -{ - var origins = builder.Configuration.GetSection("Cors:AllowedOrigins").Get() ?? Array.Empty(); +{ options.AddDefaultPolicy(policy => { - if (origins.Length > 0) + if(builder.Environment.IsDevelopment()) { - policy.WithOrigins(origins) + policy.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); } else { - policy.AllowAnyOrigin() + var origins = builder.Configuration.GetSection("Cors:AllowedOrigins").Get() ?? []; + policy.WithOrigins(origins) .AllowAnyHeader() .AllowAnyMethod(); } diff --git a/DbFirst.Application/Catalogs/CatalogService.cs b/DbFirst.Application/Catalogs/CatalogService.cs index 65a4946..4528710 100644 --- a/DbFirst.Application/Catalogs/CatalogService.cs +++ b/DbFirst.Application/Catalogs/CatalogService.cs @@ -21,7 +21,17 @@ Cons/Practical here: Conclusion: For this solution a generic service would be more overhead than benefit. If you later have multiple very similar entities without special logic, you could consider a lightweight generic interface/base; for now, the specialized service implementation is cleaner. */ +/* Hakan's Response: + * No, it absolutely makes sense to create a generic service using Options pattern. So, you can easily inject your SQL queries or stored procedure names via configuration. + * see: https://docs.microsoft.com/en-us/dotnet/core/extensions/options + */ + //TODO: implement CQRS pattern with MediatR + +/* Hakan's response + * Here is the main part. We dont even need a service layer if we implement CQRS with MediatR at least for CRUD operations. + */ + public class CatalogService : ICatalogService { private readonly ICatalogRepository _repository; diff --git a/DbFirst.Domain/Repositories/ICatalogRepository.cs b/DbFirst.Domain/Repositories/ICatalogRepository.cs index bd50be8..7b4d3d7 100644 --- a/DbFirst.Domain/Repositories/ICatalogRepository.cs +++ b/DbFirst.Domain/Repositories/ICatalogRepository.cs @@ -1,4 +1,5 @@ using DbFirst.Domain.Entities; +using System.Runtime.Intrinsics.X86; namespace DbFirst.Domain.Repositories; @@ -11,6 +12,12 @@ A generic Repository isn’t really worthwhile here: • Operations aren’t symmetric (separate procs for insert/update/delete with output handling and reload), so a one-size-fits-all CRUD pattern doesn’t fit well. • Better to keep the specialized repo.If you want reuse, extract small helpers (e.g., for proc calls/output parameters/reload) instead of forcing a generic repository. */ + +/* Hakan's Response: + * I think it still makes sense. An execute SQL method can be added to repository. The relevant SQL can be executed in the application layer. + * Because the application layer is no longer dependent on a method like CreateAsync. It is now directly dependent on that procedure. + */ + // TODO: move to application layer as a part of clean architecture /* Copilot's Response: @@ -22,6 +29,12 @@ A generic Repository isn’t really worthwhile here: Con: If Domain logic needs repos, it would depend on Application, weakening the layer separation. Recommendation: Keep the interface in Domain. It’s conventional, clean, and avoids a Domain -> Application dependency. Implementation stays in Infrastructure. */ +/* Hakan's Response: + * I don't think there's any point in keeping repository interfaces in the domain layer. These interfaces will be used in the application layer, not the domain layer. + * Furthermore, this is how they are used in the most popular clean architecture pattern. + * See: https://github.com/jasontaylordev/CleanArchitecture/blob/main/src/Infrastructure/Identity/IdentityService.cs + */ + public interface ICatalogRepository { Task> GetAllAsync(CancellationToken cancellationToken = default);