using FastEndpoints; using FrameworkBLL.EntityViewer; using GB5Shared.DTO.Framework.Login; using GB5Shared.FastEndPoint; using static GB5Shared.GB5Constant.Constant; namespace FrameworkSL.Endpoints.EntityViewer { // GET /EntityViewer/GetEntityViewer?ObjectTypeId=&ObjectId= // // The Entity Viewer's record read: given ObjectTypeId (MENTITY.ENTITYID) // and ObjectId (the record's PK), assembles EntityData (via the entity's // registered MWEBSERVICE GET endpoint) + Workflow status + OnDemand // qualifier Enrichment into one payload. Separate from GetEntityLayout, // which only resolves the display *schema* for an EntityCode. public class GetEntityViewer : BaseEndpoint> { private readonly IEntityViewerBLL _Bll; public GetEntityViewer(IEntityViewerBLL bll) => _Bll = bll; public override void Configure() { Get("/EntityViewer/GetEntityViewer"); AllowAnonymous(); } public record Params( [property: QueryParam] int ObjectTypeId, [property: QueryParam] int ObjectId, [property: FromHeader] string Login ); // Live, on-demand data (workflow status, external call) — never cached. protected override string? GetCacheKey(Params req, LoginDTO loginDTO) => null; protected override async Task> ExecuteAsync( Params req, LoginDTO loginDTO, CancellationToken ct) { try { // Zero-config {BaseURI}: the resolved MWEBSERVICE target (e.g. /prs/TimeSlip/GetTimeSlip) // is reachable through the same gateway host this request itself came in on — same // pattern as BaseEndpoint.RequestUrl / ActionExecuteEndpoint's frameworkBaseUrl, EXCEPT // this call is always fronted by the GB5Build YARP gateway (Postman -> :55 -> /fws -> // this service on :5000), and Program.cs's ForwardedHeadersOptions only trusts // XForwardedFor/XForwardedProto — NOT XForwardedHost — so HttpContext.Request.Host // alone would resolve to :5000 (this service's own bind port), not :55 (the gateway, // which is also where /prs/* is reachable). GB5Build's Program.cs sets X-Forwarded-Host // to its OWN Host on every proxied request specifically so downstream services can // recover it (see "Forwarding it here, once, covers every route" there) — read it // directly rather than relying on ASP.NET Core's Host-rewriting (which we don't enable). // Falls back to Request.Host for calls made directly against this service (no gateway). var requestHost = HttpContext.Request.Headers.TryGetValue("X-Forwarded-Host", out var forwardedHost) && !string.IsNullOrWhiteSpace(forwardedHost) ? forwardedHost.ToString() : HttpContext.Request.Host.Value; var result = await _Bll.GetEntityViewer(req.ObjectTypeId, req.ObjectId, loginDTO, requestHost, ct); return await GB5Shared.ResponseStandard.Response .CreateSuccessResponse(result, CacheKeyLevel.NOT_REQUIRED, loginDTO); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response .CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, loginDTO, ex.Message, 500); } } } }