Replaced all usages of InvokeReferencesDto with InvokeReferences across controllers, commands, and DTOs. This change standardizes the reference type naming by removing the "Dto" suffix, with no changes to the structure or behavior.
207 lines
8.6 KiB
C#
207 lines
8.6 KiB
C#
using MediatR;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Options;
|
|
using ReC.Application.Common.Constants;
|
|
using ReC.Application.Common.Dto;
|
|
using ReC.Application.Common.Exceptions;
|
|
using ReC.Application.Common.Options;
|
|
using ReC.Application.Results.Commands;
|
|
using ReC.Domain.Constants;
|
|
using ReC.Domain.Views;
|
|
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace ReC.Application.RecActions.Commands;
|
|
|
|
public record InvokeRecActionViewCommand : IRequest
|
|
{
|
|
public RecActionViewDto Action { get; set; } = null!;
|
|
public required InvokeReferences References { get; set; }
|
|
}
|
|
|
|
public record InvokeReferences
|
|
{
|
|
public required string BatchId { get; init; }
|
|
public string? Reference1 { get; init; }
|
|
public string? Reference2 { get; init; }
|
|
public string? Reference3 { get; init; }
|
|
public string? Reference4 { get; init; }
|
|
public string? Reference5 { get; init; }
|
|
}
|
|
|
|
public class InvokeRecActionViewCommandHandler(
|
|
IOptions<RecActionOptions> options,
|
|
ISender sender,
|
|
IHttpClientFactory clientFactory,
|
|
IConfiguration? config = null
|
|
) : IRequestHandler<InvokeRecActionViewCommand>
|
|
{
|
|
private readonly RecActionOptions _options = options.Value;
|
|
|
|
public async Task Handle(InvokeRecActionViewCommand request, CancellationToken cancel)
|
|
{
|
|
var action = request.Action;
|
|
HttpClient? ntlmClient = null;
|
|
|
|
try
|
|
{
|
|
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 = CreateHttpRequestMessage(restType, action.EndpointUri);
|
|
|
|
if (action.Body is not null)
|
|
httpReq.Content = new StringContent(action.Body);
|
|
|
|
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))
|
|
{
|
|
if (_options.UseHttp1ForNtlm)
|
|
{
|
|
httpReq.Version = HttpVersion.Version11;
|
|
httpReq.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
|
|
}
|
|
var endpointAuthPassword = action.EndpointAuthPassword
|
|
#if DEBUG
|
|
?.Replace("%NTLM_PW%", config?.GetValue<string>("%NTLM_PW%"))
|
|
#endif
|
|
;
|
|
var credentials = new NetworkCredential(
|
|
action.EndpointAuthUsername,
|
|
endpointAuthPassword,
|
|
action.EndpointAuthDomain);
|
|
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
|
|
var ntlmHandler = new HttpClientHandler
|
|
{
|
|
Credentials = credentialCache,
|
|
UseDefaultCredentials = false
|
|
};
|
|
ntlmClient = new HttpClient(ntlmHandler, disposeHandler: true);
|
|
}
|
|
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}"
|
|
);
|
|
}
|
|
|
|
var http = ntlmClient ?? clientFactory.CreateClient(Http.ClientName);
|
|
using var response = await http.SendAsync(httpReq, cancel);
|
|
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
|
var resHeaders = response.Headers.ToDictionary();
|
|
|
|
await sender.Send(new InsertResultCommand()
|
|
{
|
|
Status = response.StatusCode.ToRecStatus(),
|
|
ActionId = action.Id,
|
|
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
|
Body = resBody,
|
|
Info = (short)response.StatusCode,
|
|
Type = ResultType.Main,
|
|
References = request.References
|
|
}, cancel);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
await sender.Send(new InsertResultCommand()
|
|
{
|
|
Status = RecStatus.Error,
|
|
ActionId = action.Id,
|
|
Error = ex.ToString(),
|
|
Type = ResultType.Main,
|
|
References = request.References
|
|
}, cancel);
|
|
|
|
if (action.ErrorAction == ErrorAction.Stop)
|
|
throw new RecActionException(action.Id, action.ProfileId, ex);
|
|
}
|
|
finally
|
|
{
|
|
ntlmClient?.Dispose();
|
|
}
|
|
}
|
|
|
|
private static HttpRequestMessage CreateHttpRequestMessage(RestType restType, string? endpointUri)
|
|
{
|
|
var method = restType switch
|
|
{
|
|
RestType.Get => HttpMethod.Get,
|
|
RestType.Post => HttpMethod.Post,
|
|
RestType.Put => HttpMethod.Put,
|
|
RestType.Delete => HttpMethod.Delete,
|
|
RestType.Patch => HttpMethod.Patch,
|
|
RestType.Head => HttpMethod.Head,
|
|
RestType.Options => HttpMethod.Options,
|
|
RestType.Trace => HttpMethod.Trace,
|
|
RestType.Connect => HttpMethod.Connect,
|
|
RestType.None => throw new ArgumentOutOfRangeException(nameof(restType), $"The RestType value '{restType}' is not valid."),
|
|
_ => new HttpMethod(restType.ToString().ToUpperInvariant())
|
|
};
|
|
|
|
return new HttpRequestMessage(method, endpointUri);
|
|
}
|
|
} |