151 lines
4.9 KiB
C#
151 lines
4.9 KiB
C#
using System.Text.Json;
|
|
|
|
namespace Management.Services;
|
|
|
|
/// <summary>
|
|
/// HTTP client for calling the Registration Azure Function.
|
|
///
|
|
/// Configuration (appsettings.json):
|
|
/// "Registration": {
|
|
/// "BaseUrl": "https://your-function-app.azurewebsites.net/api",
|
|
/// "FunctionKey": "your-function-key-here"
|
|
/// }
|
|
///
|
|
/// Registered in DI as a typed HttpClient.
|
|
/// </summary>
|
|
public class RegistrationClient
|
|
{
|
|
private readonly HttpClient _http;
|
|
private readonly ILogger<RegistrationClient> _log;
|
|
|
|
private static readonly JsonSerializerOptions JsonOpts = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
PropertyNameCaseInsensitive = true
|
|
};
|
|
|
|
public RegistrationClient(HttpClient http, IConfiguration config, ILogger<RegistrationClient> log)
|
|
{
|
|
_http = http;
|
|
_log = log;
|
|
|
|
var baseUrl = config["Registration:BaseUrl"];
|
|
var functionKey = config["Registration:FunctionKey"];
|
|
|
|
if (!string.IsNullOrWhiteSpace(baseUrl))
|
|
{
|
|
try
|
|
{
|
|
_http.BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/");
|
|
}
|
|
catch (UriFormatException ex)
|
|
{
|
|
log.LogWarning(ex, "[RegistrationClient] Invalid BaseUrl: {BaseUrl}", baseUrl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log.LogWarning("[RegistrationClient] Registration:BaseUrl not configured — registration proxy disabled");
|
|
}
|
|
|
|
// Function key sent as query param (Azure Functions default auth)
|
|
if (!string.IsNullOrWhiteSpace(functionKey))
|
|
{
|
|
// Store key for per-request query string injection
|
|
_functionKey = functionKey;
|
|
}
|
|
|
|
_log.LogInformation("[RegistrationClient] Configured. BaseUrl={BaseUrl} KeyPresent={HasKey}",
|
|
_http.BaseAddress, !string.IsNullOrWhiteSpace(functionKey));
|
|
}
|
|
|
|
private readonly string? _functionKey;
|
|
|
|
// ── API Methods ──
|
|
|
|
public async Task<JsonDocument?> GetPendingAsync(CancellationToken ct)
|
|
{
|
|
return await GetAsync("registration/pending", ct);
|
|
}
|
|
|
|
public async Task<JsonDocument?> GetByIdAsync(string registrationId, CancellationToken ct)
|
|
{
|
|
return await GetAsync($"registration/item/{registrationId}", ct);
|
|
}
|
|
|
|
public async Task<JsonDocument?> RejectAsync(string registrationId, string? reason, CancellationToken ct)
|
|
{
|
|
return await PostAsync($"registration/action/{registrationId}/reject", new { reason }, ct);
|
|
}
|
|
|
|
public async Task<JsonDocument?> CompleteAsync(string registrationId, string? platformClientId, CancellationToken ct)
|
|
{
|
|
return await PostAsync($"registration/action/{registrationId}/complete", new { platformClientId }, ct);
|
|
}
|
|
|
|
// ── Internal HTTP helpers ──
|
|
|
|
private async Task<JsonDocument?> GetAsync(string path, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var url = AppendKey(path);
|
|
_log.LogInformation("[RegistrationClient] GET {Path}", path);
|
|
|
|
var response = await _http.GetAsync(url, ct);
|
|
var body = await response.Content.ReadAsStringAsync(ct);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
_log.LogWarning("[RegistrationClient] GET {Path} → {Status}: {Body}",
|
|
path, (int)response.StatusCode, body[..Math.Min(200, body.Length)]);
|
|
return null;
|
|
}
|
|
|
|
return JsonDocument.Parse(body);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_log.LogError(ex, "[RegistrationClient] GET {Path} failed", path);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private async Task<JsonDocument?> PostAsync(string path, object? payload, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var url = AppendKey(path);
|
|
var json = payload != null ? JsonSerializer.Serialize(payload, JsonOpts) : "{}";
|
|
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
|
|
|
|
_log.LogInformation("[RegistrationClient] POST {Path}", path);
|
|
|
|
var response = await _http.PostAsync(url, content, ct);
|
|
var body = await response.Content.ReadAsStringAsync(ct);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
_log.LogWarning("[RegistrationClient] POST {Path} → {Status}: {Body}",
|
|
path, (int)response.StatusCode, body[..Math.Min(200, body.Length)]);
|
|
}
|
|
|
|
return JsonDocument.Parse(body);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_log.LogError(ex, "[RegistrationClient] POST {Path} failed", path);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private string AppendKey(string path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_functionKey))
|
|
return path;
|
|
|
|
var separator = path.Contains('?') ? '&' : '?';
|
|
return $"{path}{separator}code={_functionKey}";
|
|
}
|
|
}
|