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.
This commit is contained in:
2026-01-19 11:17:36 +01:00
parent 45e5327148
commit d608ab1a6d
3 changed files with 30 additions and 5 deletions

View File

@@ -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<string[]>() ?? Array.Empty<string>();
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<string[]>() ?? [];
policy.WithOrigins(origins)
.AllowAnyHeader()
.AllowAnyMethod();
}

View File

@@ -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;

View File

@@ -1,4 +1,5 @@
using DbFirst.Domain.Entities;
using System.Runtime.Intrinsics.X86;
namespace DbFirst.Domain.Repositories;
@@ -11,6 +12,12 @@ A generic Repository<T> isnt really worthwhile here:
• Operations arent symmetric (separate procs for insert/update/delete with output handling and reload), so a one-size-fits-all CRUD pattern doesnt 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<T> isnt really worthwhile here:
Con: If Domain logic needs repos, it would depend on Application, weakening the layer separation.
Recommendation: Keep the interface in Domain. Its 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<List<VwmyCatalog>> GetAllAsync(CancellationToken cancellationToken = default);