First Commit
This commit is contained in:
22
Helpers/ADS.Helpers.Middleware/ADS.Helpers.Middleware.csproj
Normal file
22
Helpers/ADS.Helpers.Middleware/ADS.Helpers.Middleware.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ADS.Helpers.Base\ADS.Helpers.Base.csproj" />
|
||||
<ProjectReference Include="..\ADS.Helpers.MultiTenant\ADS.Helpers.MultiTenant.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ADS.Helpers.Middleware.ADSException;
|
||||
|
||||
using ADS.Helpers.Middleware.Http;
|
||||
|
||||
public sealed class AdsExceptionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IAdsErrorLogger _logger;
|
||||
|
||||
public AdsExceptionMiddleware(RequestDelegate next, IAdsErrorLogger logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (System.UnauthorizedAccessException ex)
|
||||
{
|
||||
await Handle(context, HttpStatusCode.Unauthorized, ex, AdsErrorKind.Controlled);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
await Handle(context, HttpStatusCode.BadRequest, ex, AdsErrorKind.Controlled);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
await Handle(context, HttpStatusCode.BadRequest, ex, AdsErrorKind.Controlled);
|
||||
}
|
||||
catch (Microsoft.Data.SqlClient.SqlException ex)
|
||||
{
|
||||
await Handle(context, HttpStatusCode.InternalServerError, ex, AdsErrorKind.Sql);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Handle(context, HttpStatusCode.InternalServerError, ex, AdsErrorKind.Unhandled);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Handle(HttpContext ctx, HttpStatusCode code, Exception ex, AdsErrorKind kind)
|
||||
{
|
||||
await _logger.LogAsync(new AdsErrorEvent
|
||||
{
|
||||
Kind = kind,
|
||||
Path = ctx.Request.Path.ToString(),
|
||||
Method = ctx.Request.Method,
|
||||
TraceId = ctx.TraceIdentifier,
|
||||
Message = ex.Message,
|
||||
Exception = ex.ToString()
|
||||
});
|
||||
|
||||
ctx.Response.StatusCode = (int)code;
|
||||
ctx.Response.ContentType = "application/json";
|
||||
|
||||
var payload = new ApiResponse<object>
|
||||
{
|
||||
StatusCode = (int)code,
|
||||
StatusCodeText = code.ToString(),
|
||||
ConsoleMessage = ex.Message,
|
||||
ScreenMessage = new UiMessage
|
||||
{
|
||||
MessageType = 2, // ejemplo: 1=info,2=error,3=warn
|
||||
Message = "Ocurrió un error al procesar la solicitud.",
|
||||
MessageCode = 0
|
||||
},
|
||||
Value = null
|
||||
};
|
||||
|
||||
await ctx.Response.WriteAsync(JsonSerializer.Serialize(payload, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ADS.Helpers.Middleware.ADSException;
|
||||
|
||||
public sealed class FileAdsErrorLogger : IAdsErrorLogger
|
||||
{
|
||||
private readonly string _folder;
|
||||
|
||||
public FileAdsErrorLogger(IOptions<LoggingOptions> options)
|
||||
{
|
||||
_folder = options.Value.LogFolder ?? "logs";
|
||||
Directory.CreateDirectory(_folder);
|
||||
}
|
||||
|
||||
public Task LogAsync(AdsErrorEvent evt, CancellationToken ct = default)
|
||||
{
|
||||
var day = DateTime.UtcNow.ToString("yyyy-MM-dd");
|
||||
var path = Path.Combine(_folder, $"ads-errors-{day}.jsonl");
|
||||
|
||||
var line = JsonSerializer.Serialize(evt);
|
||||
return File.AppendAllTextAsync(path, line + Environment.NewLine, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace ADS.Helpers.Middleware.ADSException;
|
||||
|
||||
public enum AdsErrorKind
|
||||
{
|
||||
Sql = 1,
|
||||
Controlled = 2,
|
||||
Unhandled = 3
|
||||
}
|
||||
|
||||
public sealed class AdsErrorEvent
|
||||
{
|
||||
public AdsErrorKind Kind { get; init; }
|
||||
public string? Path { get; init; }
|
||||
public string? Method { get; init; }
|
||||
public string? TraceId { get; init; }
|
||||
public string? Message { get; init; }
|
||||
public string? Exception { get; init; }
|
||||
public DateTime Utc { get; init; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public interface IAdsErrorLogger
|
||||
{
|
||||
Task LogAsync(AdsErrorEvent evt, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ADS.Helpers.Middleware.ADSException;
|
||||
|
||||
public sealed class LoggingOptions
|
||||
{
|
||||
public string LogFolder { get; set; } = "logs";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using ADS.Helpers.Middleware.ADSException;
|
||||
using ADS.Helpers.Middleware.Http;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ADS.Helpers.Middleware.ADSExtensions;
|
||||
|
||||
public static class AdsApiResponseExtensions
|
||||
{
|
||||
public static IServiceCollection AddAdsApiResponse(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
// Leer configuración desde appsettings de la API
|
||||
services.Configure<LoggingOptions>(
|
||||
configuration.GetSection("LoggingOptions"));
|
||||
|
||||
services.AddSingleton<IAdsErrorLogger, FileAdsErrorLogger>();
|
||||
|
||||
services.AddControllers(o =>
|
||||
{
|
||||
o.Filters.Add<ApiResponseWrapFilter>();
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseAdsApiResponse(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseMiddleware<AdsExceptionMiddleware>();
|
||||
return app;
|
||||
}
|
||||
}
|
||||
76
Helpers/ADS.Helpers.Middleware/Extensions/AdsExtensions.cs
Normal file
76
Helpers/ADS.Helpers.Middleware/Extensions/AdsExtensions.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using ADS.Helpers.Middleware.Tenant;
|
||||
using ADS.Helpers.Middleware.Logging;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ADS.Helpers.MultiTenant.Abstractions;
|
||||
using ADS.Helpers.MultiTenant.Resolvers;
|
||||
using ADS.Helpers.MultiTenant.Context;
|
||||
using ADS.Helpers.Base.Abstractions;
|
||||
using ADS.Helpers.MultiTenant.Configuration;
|
||||
using ADS.Helpers.MultiTenant.Stores;
|
||||
using ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
namespace ADS.Helpers.Middleware.Extensions;
|
||||
|
||||
public static class AdsExtensions
|
||||
{
|
||||
// IServiceCollection extensions
|
||||
public static IServiceCollection AddAdsLogging(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//services.AddLogging();
|
||||
|
||||
// Ejemplo si tenías esto:
|
||||
services.AddSingleton<IAppLogger, DefaultAppLogger>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAdsMultiTenant(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// Aquí va lo que ya tengas para tenant: options, accessor, resolver, etc.
|
||||
services.Configure<TenantOptions>(configuration.GetSection("MultiTenant"));
|
||||
services.AddSingleton<ITenantContextAccessor, TenantContextAccessor>();
|
||||
// services.AddSingleton<ITenantStore, InMemoryTenantStore>();// reemplazado por ConfigurationTenantStore
|
||||
services.AddSingleton<ITenantStore, ConfigurationTenantStore>();
|
||||
services.AddScoped<ITenantResolver, HeaderTenantResolver>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAdsMiddlewares(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// Si este método es solo un "orquestador" de otros registros:
|
||||
services.AddAdsLogging(configuration);
|
||||
services.AddAdsMultiTenant(configuration);
|
||||
|
||||
// Y aquí agregas otros (ExceptionHandling, CorrelationId, etc.)
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
// IApplicationBuilder extensions
|
||||
public static IApplicationBuilder UseAdsTenant(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseMiddleware<TenantMiddleware>();
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseAdsMiddlewares(this IApplicationBuilder app)
|
||||
{
|
||||
// Orden típico: errores/correlation/tenant/etc (según tu diseño)
|
||||
app.UseAdsTenant();
|
||||
return app;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAdsInternalUser(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IInternalUserContextAccessor, InternalUserContextAccessor>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseAdsInternalUser(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseMiddleware<InternalUserContextMiddleware>();
|
||||
}
|
||||
|
||||
}
|
||||
20
Helpers/ADS.Helpers.Middleware/Http/ApiResponse.cs
Normal file
20
Helpers/ADS.Helpers.Middleware/Http/ApiResponse.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace ADS.Helpers.Middleware.Http;
|
||||
|
||||
public sealed class ApiResponse<T>
|
||||
{
|
||||
public int StatusCode { get; init; }
|
||||
public int TotalRows { get; init; }
|
||||
public string StatusCodeText { get; init; } = string.Empty;
|
||||
|
||||
public string? ConsoleMessage { get; init; }
|
||||
public UiMessage? ScreenMessage { get; init; }
|
||||
|
||||
public T? Value { get; init; }
|
||||
}
|
||||
|
||||
public sealed class UiMessage
|
||||
{
|
||||
public int MessageType { get; init; }
|
||||
public string Message { get; init; } = "";
|
||||
public int MessageCode { get; init; }
|
||||
}
|
||||
62
Helpers/ADS.Helpers.Middleware/Http/ApiResponseWrapFilter.cs
Normal file
62
Helpers/ADS.Helpers.Middleware/Http/ApiResponseWrapFilter.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace ADS.Helpers.Middleware.Http;
|
||||
|
||||
public sealed class ApiResponseWrapFilter : IAsyncResultFilter
|
||||
{
|
||||
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
||||
{
|
||||
// Si es FileResult / Stream / etc., no lo toques
|
||||
if (context.Result is FileResult)
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Result is ObjectResult obj)
|
||||
{
|
||||
// Si ya viene envuelto, no reenvolver
|
||||
if (obj.Value is not null)
|
||||
{
|
||||
var t = obj.Value.GetType();
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ApiResponse<>))
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var code = obj.StatusCode ?? 200;
|
||||
context.Result = new ObjectResult(new ApiResponse<object>
|
||||
{
|
||||
StatusCode = code,
|
||||
StatusCodeText = ReasonPhrase(code),
|
||||
Value = obj.Value
|
||||
})
|
||||
{ StatusCode = code };
|
||||
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
// Si no es ObjectResult (por ejemplo EmptyResult), déjalo pasar
|
||||
await next();
|
||||
}
|
||||
|
||||
private static string ReasonPhrase(int code) => code switch
|
||||
{
|
||||
200 => "OK",
|
||||
201 => "Created",
|
||||
202 => "Accepted",
|
||||
204 => "NoContent",
|
||||
400 => "BadRequest",
|
||||
401 => "Unauthorized",
|
||||
403 => "Forbidden",
|
||||
404 => "NotFound",
|
||||
409 => "Conflict",
|
||||
422 => "UnprocessableEntity",
|
||||
500 => "ServerError",
|
||||
_ => "Status"
|
||||
};
|
||||
}
|
||||
9
Helpers/ADS.Helpers.Middleware/Http/PagedQuery.cs
Normal file
9
Helpers/ADS.Helpers.Middleware/Http/PagedQuery.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace ADS.Helpers.Middleware.Http;
|
||||
|
||||
public sealed class PagedQuery
|
||||
{
|
||||
public string? Search { get; init; }
|
||||
public int Page { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 50;
|
||||
public bool Pagination { get; init; } = true;
|
||||
}
|
||||
11
Helpers/ADS.Helpers.Middleware/Http/RequestOf.cs
Normal file
11
Helpers/ADS.Helpers.Middleware/Http/RequestOf.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace ADS.Helpers.Middleware.Http;
|
||||
|
||||
public sealed class RequestOf<T>
|
||||
{
|
||||
public T? Value { get; init; }
|
||||
|
||||
public string? Search { get; init; }
|
||||
public int Page { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 50;
|
||||
public bool Pagination { get; init; } = true;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
public interface IInternalUserContextAccessor
|
||||
{
|
||||
InternalUserContext? Current { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
public class InternalAuthorizeAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
var allowAnonymous = context.ActionDescriptor.EndpointMetadata
|
||||
.OfType<AllowAnonymousAttribute>()
|
||||
.Any();
|
||||
|
||||
if (allowAnonymous)
|
||||
return;
|
||||
|
||||
var accessor = context.HttpContext.RequestServices
|
||||
.GetService(typeof(IInternalUserContextAccessor)) as IInternalUserContextAccessor;
|
||||
|
||||
if (accessor?.Current == null)
|
||||
{
|
||||
context.Result = new UnauthorizedResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
public class InternalUserContext
|
||||
{
|
||||
public int CveUser { get; set; }
|
||||
public int CveEmpresa { get; set; }
|
||||
public int CveCliente { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
public class InternalUserContextAccessor : IInternalUserContextAccessor
|
||||
{
|
||||
public InternalUserContext? Current { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using ADS.Helpers.MultiTenant.InternalRouting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ADS.Helpers.Middleware.InternalUser;
|
||||
|
||||
public class InternalUserContextMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public InternalUserContextMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(
|
||||
HttpContext context,
|
||||
IInternalUserContextAccessor accessor,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
var cveUserHeader = context.Request.Headers[InternalHeaders.CveUser].FirstOrDefault();
|
||||
var cveEmpresaHeader = context.Request.Headers[InternalHeaders.CveEmpresa].FirstOrDefault();
|
||||
var cveClienteHeader = context.Request.Headers[InternalHeaders.CveCliente].FirstOrDefault();
|
||||
var timestampHeader = context.Request.Headers[InternalHeaders.Timestamp].FirstOrDefault();
|
||||
var signatureHeader = context.Request.Headers[InternalHeaders.User_Signature].FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(cveUserHeader) &&
|
||||
!string.IsNullOrWhiteSpace(cveEmpresaHeader) &&
|
||||
!string.IsNullOrWhiteSpace(cveClienteHeader) &&
|
||||
!string.IsNullOrWhiteSpace(timestampHeader) &&
|
||||
!string.IsNullOrWhiteSpace(signatureHeader))
|
||||
{
|
||||
var secret = configuration["InternalRouting:SharedSecret"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(secret))
|
||||
throw new InvalidOperationException("InternalRouting:SharedSecret no está configurado.");
|
||||
|
||||
var raw = $"{cveUserHeader}|{cveEmpresaHeader}|{cveClienteHeader}|{timestampHeader}";
|
||||
var expectedSignature = ComputeHmacSha256(raw, secret);
|
||||
|
||||
if (signatureHeader == expectedSignature)
|
||||
{
|
||||
accessor.Current = new InternalUserContext
|
||||
{
|
||||
CveUser = int.Parse(cveUserHeader),
|
||||
CveEmpresa = int.Parse(cveEmpresaHeader),
|
||||
CveCliente = int.Parse(cveClienteHeader)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
|
||||
private static string ComputeHmacSha256(string value, string secret)
|
||||
{
|
||||
var key = Encoding.UTF8.GetBytes(secret);
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
|
||||
using var hmac = new HMACSHA256(key);
|
||||
var hash = hmac.ComputeHash(bytes);
|
||||
|
||||
return Convert.ToBase64String(hash);
|
||||
}
|
||||
}
|
||||
24
Helpers/ADS.Helpers.Middleware/Logging/DefaultAppLogger.cs
Normal file
24
Helpers/ADS.Helpers.Middleware/Logging/DefaultAppLogger.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using ADS.Helpers.Base.Abstractions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ADS.Helpers.Middleware.Logging;
|
||||
|
||||
public sealed class DefaultAppLogger : IAppLogger
|
||||
{
|
||||
private readonly ILogger<DefaultAppLogger> _logger;
|
||||
|
||||
public DefaultAppLogger(ILogger<DefaultAppLogger> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Info(string source, string code, string message, object? data = null)
|
||||
=> _logger.LogInformation("{Source} {Code} {Message} {@Data}", source, code, message, data);
|
||||
|
||||
public void Warn(string source, string code, string message, object? data = null)
|
||||
=> _logger.LogWarning("{Source} {Code} {Message} {@Data}", source, code, message, data);
|
||||
|
||||
public void Error(string source, string code, string message, Exception? ex = null, object? data = null)
|
||||
=> _logger.LogError(ex, "{Source} {Code} {Message} {@Data}", source, code, message, data);
|
||||
}
|
||||
57
Helpers/ADS.Helpers.Middleware/Tenant/TenantMiddleware.cs
Normal file
57
Helpers/ADS.Helpers.Middleware/Tenant/TenantMiddleware.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Threading.Tasks;
|
||||
using ADS.Helpers.Base.Abstractions;
|
||||
using ADS.Helpers.MultiTenant.Abstractions;
|
||||
using ADS.Helpers.MultiTenant.Context;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace ADS.Helpers.Middleware.Tenant;
|
||||
|
||||
public sealed class TenantMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public TenantMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
// Scoped dependencies se resuelven aquí (por request)
|
||||
public async Task InvokeAsync(
|
||||
HttpContext context,
|
||||
ITenantResolver tenantResolver,
|
||||
ITenantStore tenantStore,
|
||||
ITenantContextAccessor tenantContextAccessor,
|
||||
IAppLogger log)
|
||||
{
|
||||
var tenantKey = tenantResolver.Resolve(context);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tenantKey))
|
||||
{
|
||||
log.Warn("ADS.MultiTenant", "TENANT_NOT_RESOLVED", "Tenant key could not be resolved.");
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
await context.Response.WriteAsync("Tenant not resolved.");
|
||||
return;
|
||||
}
|
||||
|
||||
var tenant = await tenantStore.GetAsync(tenantKey);
|
||||
|
||||
if (tenant is null)
|
||||
{
|
||||
log.Warn("ADS.MultiTenant", "TENANT_NOT_FOUND", $"Tenant '{tenantKey}' not found.");
|
||||
context.Response.StatusCode = StatusCodes.Status404NotFound;
|
||||
await context.Response.WriteAsync("Tenant not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
tenantContextAccessor.SetCurrent(tenant);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tenantContextAccessor.SetCurrent(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user