Refactored all "Result" related command and query classes from ReC.Application.OutResults to ReC.Application.Results. Updated all relevant using statements and reorganized files accordingly. No functional changes; this improves project structure and clarity.
147 lines
5.9 KiB
C#
147 lines
5.9 KiB
C#
using MediatR;
|
|
using Microsoft.Extensions.Configuration;
|
|
using ReC.Application.Common;
|
|
using ReC.Application.Common.Constants;
|
|
using ReC.Application.Common.Dto;
|
|
using ReC.Application.Common.Exceptions;
|
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
|
using ReC.Application.Results.Commands;
|
|
using ReC.Domain.Constants;
|
|
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace ReC.Application.RecActions.Commands;
|
|
|
|
public record InvokeRecActionViewCommand : IRequest<bool>
|
|
{
|
|
public RecActionViewDto Action { get; set; } = null!;
|
|
}
|
|
|
|
public static class InvokeRecActionViewCommandExtensions
|
|
{
|
|
public static InvokeRecActionViewCommand ToInvokeCommand(this RecActionViewDto dto) => new() { Action = dto };
|
|
}
|
|
|
|
public class InvokeRecActionViewCommandHandler(
|
|
ISender sender,
|
|
IHttpClientFactory clientFactory,
|
|
IConfiguration? config = null
|
|
) : IRequestHandler<InvokeRecActionViewCommand, bool>
|
|
{
|
|
public async Task<bool> Handle(InvokeRecActionViewCommand request, CancellationToken cancel)
|
|
{
|
|
var action = request.Action;
|
|
|
|
using var http = clientFactory.CreateClient(Http.ClientName);
|
|
|
|
if (action.RestType is not RestType restType)
|
|
throw new DataIntegrityException(
|
|
$"Rec action could not be invoked because the RestType value is null. " +
|
|
$"ProfileId: {action.ProfileId}, " +
|
|
$"Id: {action.Id}"
|
|
);
|
|
|
|
using var httpReq = restType
|
|
.ToHttpMethod()
|
|
.ToHttpRequestMessage(action.EndpointUri);
|
|
|
|
if (action.Body is not null)
|
|
{
|
|
using var reqBody = new StringContent(action.Body);
|
|
httpReq.Content = reqBody;
|
|
}
|
|
|
|
if (action.Headers is not null)
|
|
foreach (var header in action.Headers)
|
|
httpReq.Headers.Add(header.Key, header.Value);
|
|
|
|
switch (action.EndpointAuthType)
|
|
{
|
|
case EndpointAuthType.NoAuth:
|
|
break;
|
|
|
|
case EndpointAuthType.ApiKey:
|
|
if (action.EndpointAuthApiKey is string apiKey && action.EndpointAuthApiValue is string apiValue)
|
|
{
|
|
switch (action.EndpointAuthApiKeyAddTo)
|
|
{
|
|
case ApiKeyLocation.Header:
|
|
httpReq.Headers.Add(apiKey, apiValue);
|
|
break;
|
|
case ApiKeyLocation.Query:
|
|
var uriBuilder = new UriBuilder(httpReq.RequestUri!);
|
|
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
|
|
query[apiKey] = apiValue;
|
|
uriBuilder.Query = query.ToString();
|
|
httpReq.RequestUri = uriBuilder.Uri;
|
|
break;
|
|
default:
|
|
throw new DataIntegrityException(
|
|
$"The API key location '{action.EndpointAuthApiKeyAddTo}' is not supported. " +
|
|
$"ProfileId: {action.ProfileId}, " +
|
|
$"Id: {action.Id}"
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EndpointAuthType.BearerToken:
|
|
case EndpointAuthType.JwtBearer:
|
|
case EndpointAuthType.OAuth2:
|
|
if (action.EndpointAuthToken is string authToken)
|
|
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
|
|
break;
|
|
|
|
case EndpointAuthType.BasicAuth:
|
|
if (action.EndpointAuthUsername is string authUsername && action.EndpointAuthPassword is string authPassword)
|
|
{
|
|
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{authUsername}:{authPassword}"));
|
|
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
|
|
}
|
|
break;
|
|
|
|
case EndpointAuthType.NtlmAuth:
|
|
if (!string.IsNullOrWhiteSpace(action.EndpointAuthUsername))
|
|
{
|
|
var credentials = new NetworkCredential(
|
|
action.EndpointAuthUsername,
|
|
action.EndpointAuthPassword,
|
|
action.EndpointAuthDomain);
|
|
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
|
|
httpReq.Options.Set(new HttpRequestOptionsKey<CredentialCache>("Credentials"), credentialCache);
|
|
}
|
|
break;
|
|
|
|
case EndpointAuthType.DigestAuth:
|
|
case EndpointAuthType.OAuth1:
|
|
case EndpointAuthType.AwsSignature:
|
|
// These authentication methods require more complex implementations,
|
|
// often involving multi-step handshakes or specialized libraries.
|
|
// They are left as placeholders for future implementation.
|
|
default:
|
|
throw new NotImplementedException(
|
|
$"The authentication type '{action.EndpointAuthType}' is not supported yet. " +
|
|
$"ProfileId: {action.ProfileId}, " +
|
|
$"Id: {action.Id}"
|
|
);
|
|
}
|
|
|
|
using var response = await http.SendAsync(httpReq, cancel);
|
|
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
|
var resHeaders = response.Headers.ToDictionary();
|
|
|
|
var statusCode = (short)response.StatusCode;
|
|
|
|
await sender.ExecuteInsertProcedure(new InsertResultProcedure()
|
|
{
|
|
StatusId = statusCode,
|
|
ActionId = action.Id,
|
|
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
|
Body = resBody
|
|
}, config?["AddedWho"], cancel);
|
|
|
|
return response.IsSuccessStatusCode;
|
|
}
|
|
} |