Compare commits
26 Commits
dcc0e8c806
...
6f5409f528
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f5409f528 | |||
| 03498275d7 | |||
| f8581deaf9 | |||
| 8ea7d47868 | |||
| 2bbfd96d62 | |||
| 4f364e3eb2 | |||
| 0c4d145e20 | |||
| 1757c0e055 | |||
| b1df50bc32 | |||
| a66a70fab3 | |||
| a84b5531b7 | |||
| 21e3171e11 | |||
| bbfff226de | |||
| 7a4885c86a | |||
| a46d97467d | |||
| 2f3a685e7d | |||
| d1e8f619f5 | |||
| 0ec913b95e | |||
| cb851a4ec6 | |||
| cd8f757c43 | |||
| 8aa43db909 | |||
| 2a9b52ebe1 | |||
| 988d48581b | |||
| 46ef5e0d02 | |||
| 5e4f113145 | |||
| 3e9edcd8af |
@ -11,7 +11,7 @@ public class ActionController(IMediator mediator) : ControllerBase
|
||||
[HttpPost("{profileId}")]
|
||||
public async Task<IActionResult> Invoke([FromRoute] int profileId)
|
||||
{
|
||||
await mediator.InvokeRecAction(profileId);
|
||||
await mediator.InvokeBatchRecAction(profileId);
|
||||
return Accepted();
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,13 @@ using ReC.Application;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var config = builder.Configuration;
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRecServices(options =>
|
||||
{
|
||||
options.LuckyPennySoftwareLicenseKey = builder.Configuration["LuckyPennySoftwareLicenseKey"];
|
||||
options.ConfigureRecActions(config.GetSection("RecAction"));
|
||||
});
|
||||
|
||||
builder.Services.AddRecInfrastructure(options =>
|
||||
|
||||
@ -6,5 +6,8 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"MediatRLicense": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg"
|
||||
"MediatRLicense": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg",
|
||||
"RecAction": {
|
||||
"MaxConcurrentInvocations": 5
|
||||
}
|
||||
}
|
||||
21
src/ReC.Application/Common/Behaviors/BodyQueryBehavior.cs
Normal file
21
src/ReC.Application/Common/Behaviors/BodyQueryBehavior.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ReC.Application.Common.Behaviors;
|
||||
|
||||
public class BodyQueryBehavior<TRecAction>(IRecDbContext dbContext) : IPipelineBehavior<TRecAction, Unit>
|
||||
where TRecAction : RecActionDto
|
||||
{
|
||||
public async Task<Unit> Handle(TRecAction action, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
|
||||
{
|
||||
if (action.BodyQuery is null)
|
||||
return await next(cancel);
|
||||
|
||||
var result = await dbContext.BodyQueryResults.FromSqlRaw(action.BodyQuery).FirstOrDefaultAsync(cancel);
|
||||
action.Body = result?.RawBody;
|
||||
|
||||
return await next(cancel);
|
||||
}
|
||||
}
|
||||
35
src/ReC.Application/Common/Behaviors/HeaderQueryBehavior.cs
Normal file
35
src/ReC.Application/Common/Behaviors/HeaderQueryBehavior.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ReC.Application.Common.Behaviors;
|
||||
|
||||
public class HeaderQueryBehavior<TRecAction>(IRecDbContext dbContext, ILogger<HeaderQueryBehavior<TRecAction>>? logger = null) : IPipelineBehavior<TRecAction, Unit>
|
||||
where TRecAction : RecActionDto
|
||||
{
|
||||
public async Task<Unit> Handle(TRecAction action, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
|
||||
{
|
||||
if (action.HeaderQuery is null)
|
||||
return await next(cancel);
|
||||
|
||||
var result = await dbContext.HeaderQueryResults.FromSqlRaw(action.HeaderQuery).FirstOrDefaultAsync(cancel);
|
||||
|
||||
if(result?.RawHeader is null)
|
||||
return await next(cancel);
|
||||
|
||||
var headerDict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(result.RawHeader);
|
||||
|
||||
if(headerDict is null)
|
||||
{
|
||||
logger?.LogWarning("Failed to deserialize header query result: {RawHeader}. Profile ID: {ProfileId}, Action ID: {ActionId}", result.RawHeader, action.ProfileId, action.ActionId);
|
||||
return await next(cancel);
|
||||
}
|
||||
|
||||
action.Headers = headerDict.ToDictionary(header => header.Key, kvp => kvp.Value.ToString());
|
||||
|
||||
return await next(cancel);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
using AutoMapper;
|
||||
using ReC.Domain.Entities;
|
||||
|
||||
namespace ReC.Application.Dto;
|
||||
namespace ReC.Application.Common.Dto;
|
||||
|
||||
public class DtoMappingProfile : Profile
|
||||
{
|
||||
@ -1,6 +1,6 @@
|
||||
namespace ReC.Application.Dto;
|
||||
namespace ReC.Application.Common.Dto;
|
||||
|
||||
public class RecActionDto
|
||||
public record RecActionDto
|
||||
{
|
||||
public long? ActionId { get; init; }
|
||||
|
||||
@ -54,7 +54,23 @@ public class RecActionDto
|
||||
|
||||
public string? HeaderQuery { get; init; }
|
||||
|
||||
public Dictionary<string, string>? Headers { get; set; }
|
||||
|
||||
public string? BodyQuery { get; init; }
|
||||
|
||||
public string? Body { get; set; }
|
||||
|
||||
public string? PostprocessingQuery { get; init; }
|
||||
|
||||
public UriBuilder ToEndpointUriBuilder()
|
||||
{
|
||||
var builder = EndpointUri is null ? new UriBuilder() : new UriBuilder(EndpointUri);
|
||||
|
||||
builder.Port = -1;
|
||||
|
||||
if (ProfileType is not null)
|
||||
builder.Scheme = ProfileType;
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
26
src/ReC.Application/Common/HttpExtensions.cs
Normal file
26
src/ReC.Application/Common/HttpExtensions.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ReC.Application.Common;
|
||||
|
||||
public static class HttpExtensions
|
||||
{
|
||||
private static readonly Dictionary<string, HttpMethod> _methods = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["GET"] = HttpMethod.Get,
|
||||
["POST"] = HttpMethod.Post,
|
||||
["PUT"] = HttpMethod.Put,
|
||||
["DELETE"] = HttpMethod.Delete,
|
||||
["PATCH"] = HttpMethod.Patch,
|
||||
["HEAD"] = HttpMethod.Head,
|
||||
["OPTIONS"] = HttpMethod.Options,
|
||||
["TRACE"] = HttpMethod.Trace,
|
||||
["CONNECT"] = HttpMethod.Connect
|
||||
};
|
||||
|
||||
public static HttpMethod ToHttpMethod(this string method) => _methods.TryGetValue(method, out var httpMethod)
|
||||
? httpMethod
|
||||
: new HttpMethod(method);
|
||||
|
||||
public static HttpRequestMessage ToHttpRequestMessage(this HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri)
|
||||
=> new(method, requestUri);
|
||||
}
|
||||
19
src/ReC.Application/Common/Interfaces/IRecDbContext.cs
Normal file
19
src/ReC.Application/Common/Interfaces/IRecDbContext.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ReC.Domain.Entities;
|
||||
|
||||
namespace ReC.Application.Common.Interfaces;
|
||||
|
||||
public interface IRecDbContext
|
||||
{
|
||||
public DbSet<EndpointParam> EndpointParams { get; }
|
||||
|
||||
public DbSet<RecAction> Actions { get; }
|
||||
|
||||
public DbSet<OutRes> OutRes { get; }
|
||||
|
||||
public DbSet<HeaderQueryResult> HeaderQueryResults { get; }
|
||||
|
||||
public DbSet<BodyQueryResult> BodyQueryResults { get; }
|
||||
|
||||
public Task<int> SaveChangesAsync(CancellationToken cancel = default);
|
||||
}
|
||||
6
src/ReC.Application/Common/Options/RecActionOptions.cs
Normal file
6
src/ReC.Application/Common/Options/RecActionOptions.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace ReC.Application.Common.Options;
|
||||
|
||||
public class RecActionOptions
|
||||
{
|
||||
public int MaxConcurrentInvocations { get; set; } = 5;
|
||||
}
|
||||
@ -1,4 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ReC.Application.Common.Behaviors;
|
||||
using ReC.Application.Common.Options;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ReC.Application;
|
||||
@ -10,6 +13,10 @@ public static class DependencyInjection
|
||||
var configOpt = new ConfigurationOptions();
|
||||
options.Invoke(configOpt);
|
||||
|
||||
configOpt.EnsureRequiredServices();
|
||||
|
||||
configOpt.ApplyConfigurations(services);
|
||||
|
||||
services.AddAutoMapper(cfg =>
|
||||
{
|
||||
cfg.AddMaps(Assembly.GetExecutingAssembly());
|
||||
@ -19,6 +26,7 @@ public static class DependencyInjection
|
||||
services.AddMediatR(cfg =>
|
||||
{
|
||||
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
|
||||
cfg.AddOpenBehaviors([typeof(BodyQueryBehavior<>), typeof(HeaderQueryBehavior<>)]);
|
||||
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
|
||||
});
|
||||
|
||||
@ -29,6 +37,74 @@ public static class DependencyInjection
|
||||
|
||||
public class ConfigurationOptions
|
||||
{
|
||||
public string? LuckyPennySoftwareLicenseKey { get; set; }
|
||||
|
||||
#region Required Services
|
||||
private readonly Dictionary<string, bool> _requiredServices = new()
|
||||
{
|
||||
{ nameof(ConfigureRecActions), false },
|
||||
{ nameof(LuckyPennySoftwareLicenseKey), false }
|
||||
};
|
||||
|
||||
internal void EnsureRequiredServices()
|
||||
{
|
||||
var missingServices = _requiredServices
|
||||
.Where(kvp => !kvp.Value)
|
||||
.Select(kvp => kvp.Key.Replace("Configure", string.Empty));
|
||||
if (missingServices.Any())
|
||||
throw new InvalidOperationException($"The following required services were not configured: {string.Join(", ", missingServices)}");
|
||||
}
|
||||
#endregion Required Services
|
||||
|
||||
#region Configuration
|
||||
private readonly Queue<Action<IServiceCollection>> _configActions = new();
|
||||
|
||||
internal void ApplyConfigurations(IServiceCollection services)
|
||||
{
|
||||
while (_configActions.Count > 0)
|
||||
{
|
||||
var action = _configActions.Dequeue();
|
||||
action(services);
|
||||
}
|
||||
}
|
||||
#endregion Configuration
|
||||
|
||||
#region LuckyPennySoftwareLicenseKey
|
||||
private string? _luckyPennySoftwareLicenseKey;
|
||||
|
||||
public string? LuckyPennySoftwareLicenseKey
|
||||
{
|
||||
get => _luckyPennySoftwareLicenseKey;
|
||||
set
|
||||
{
|
||||
_luckyPennySoftwareLicenseKey = value;
|
||||
if (value is not null)
|
||||
_requiredServices[nameof(LuckyPennySoftwareLicenseKey)] = true;
|
||||
}
|
||||
}
|
||||
#endregion LuckyPennySoftwareLicenseKey
|
||||
|
||||
#region ConfigureRecActions
|
||||
public ConfigurationOptions ConfigureRecActions(Action<RecActionOptions> configure)
|
||||
{
|
||||
_configActions.Enqueue(services => services.Configure(configure));
|
||||
|
||||
if(_requiredServices[nameof(ConfigureRecActions)])
|
||||
throw new InvalidOperationException("RecActionOptions have already been configured.");
|
||||
_requiredServices[nameof(ConfigureRecActions)] = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationOptions ConfigureRecActions(IConfiguration configuration)
|
||||
{
|
||||
_configActions.Enqueue(services => services.Configure<RecActionOptions>(configuration));
|
||||
|
||||
if (_requiredServices[nameof(ConfigureRecActions)])
|
||||
throw new InvalidOperationException("RecActionOptions have already been configured.");
|
||||
_requiredServices[nameof(ConfigureRecActions)] = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
#endregion ConfigureRecActions
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||
<PackageReference Include="MediatR" Version="13.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReC.Application.RecActions.Queries;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record InvokeBatchRecActionsCommand : ReadRecActionQueryBase, IRequest;
|
||||
|
||||
public static class InvokeBatchRecActionsCommandExtensions
|
||||
{
|
||||
public static Task InvokeBatchRecAction(this ISender sender, int profileId)
|
||||
=> sender.Send(new InvokeBatchRecActionsCommand { ProfileId = profileId });
|
||||
}
|
||||
|
||||
public class InvokeRecActionsCommandHandler(ISender sender, IHttpClientFactory clientFactory, ILogger<InvokeRecActionsCommandHandler>? logger = null) : IRequestHandler<InvokeBatchRecActionsCommand>
|
||||
{
|
||||
public async Task Handle(InvokeBatchRecActionsCommand request, CancellationToken cancel)
|
||||
{
|
||||
var actions = await sender.Send(request.ToReadQuery(), cancel);
|
||||
|
||||
var http = clientFactory.CreateClient();
|
||||
|
||||
using var semaphore = new SemaphoreSlim(5);
|
||||
|
||||
var tasks = actions.Select(async action =>
|
||||
{
|
||||
await semaphore.WaitAsync(cancel);
|
||||
try
|
||||
{
|
||||
await sender.Send(action.ToInvokeCommand(), cancel);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
logger?.LogError(
|
||||
ex,
|
||||
"Error invoking Rec action. ProfileId: {ProfileId}, ActionId: {ActionId}",
|
||||
action.ProfileId,
|
||||
action.ActionId
|
||||
);
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
}
|
||||
@ -1,57 +1,47 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReC.Application.RecActions.Queries;
|
||||
using ReC.Application.Common;
|
||||
using ReC.Application.Common.Dto;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public class InvokeRecActionCommand : ReadRecActionQuery, IRequest
|
||||
public record InvokeRecActionCommand : RecActionDto, IRequest
|
||||
{
|
||||
public InvokeRecActionCommand(RecActionDto root) : base(root) { }
|
||||
|
||||
public InvokeRecActionCommand() { }
|
||||
}
|
||||
|
||||
public static class InvokeRecActionCommandExtensions
|
||||
{
|
||||
public static Task InvokeRecAction(this ISender sender, int profileId)
|
||||
=> sender.Send(new InvokeRecActionCommand { ProfileId = profileId });
|
||||
public static InvokeRecActionCommand ToInvokeCommand(this RecActionDto dto) => new(dto);
|
||||
}
|
||||
|
||||
public class InvokeRecActionCommandHandler(ISender sender, IHttpClientFactory clientFactory, ILogger<InvokeRecActionCommandHandler>? logger = null) : IRequestHandler<InvokeRecActionCommand>
|
||||
public class InvokeRecActionCommandHandler(
|
||||
IHttpClientFactory clientFactory,
|
||||
ILogger<InvokeRecActionsCommandHandler>? logger = null
|
||||
) : IRequestHandler<InvokeRecActionCommand>
|
||||
{
|
||||
public async Task Handle(InvokeRecActionCommand request, CancellationToken cancel)
|
||||
{
|
||||
var actions = await sender.Send(request as ReadRecActionQuery, cancel);
|
||||
using var http = clientFactory.CreateClient();
|
||||
|
||||
var http = clientFactory.CreateClient();
|
||||
|
||||
using var semaphore = new SemaphoreSlim(5);
|
||||
|
||||
var tasks = actions.Select(async action =>
|
||||
if (request.RestType is null)
|
||||
{
|
||||
await semaphore.WaitAsync(cancel);
|
||||
try
|
||||
{
|
||||
if (action.RestType is null)
|
||||
{
|
||||
logger?.LogWarning(
|
||||
"Rec action could not be invoked because the RestType value is null. ProfileId: {ProfileId}, ActionId: {ActionId}",
|
||||
action.ProfileId,
|
||||
action.ActionId
|
||||
);
|
||||
return;
|
||||
}
|
||||
logger?.LogWarning(
|
||||
"Rec action could not be invoked because the RestType value is null. ProfileId: {ProfileId}, ActionId: {ActionId}",
|
||||
request.ProfileId,
|
||||
request.ActionId
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var method = new HttpMethod(action.RestType.ToUpper());
|
||||
var msg = new HttpRequestMessage(method, action.EndpointUri);
|
||||
using var httpReq = request.RestType
|
||||
.ToHttpMethod()
|
||||
.ToHttpRequestMessage(request.EndpointUri);
|
||||
|
||||
var response = await http.SendAsync(msg, cancel);
|
||||
var body = await response.Content.ReadAsStringAsync(cancel);
|
||||
var headers = response.Headers.ToDictionary();
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
using var response = await http.SendAsync(httpReq, cancel);
|
||||
var body = await response.Content.ReadAsStringAsync(cancel);
|
||||
var headers = response.Headers.ToDictionary();
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,22 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Dto;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using ReC.Domain.Entities;
|
||||
using AutoMapper;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using ReC.Application.Common.Dto;
|
||||
|
||||
namespace ReC.Application.RecActions.Queries;
|
||||
|
||||
public class ReadRecActionQuery : IRequest<IEnumerable<RecActionDto>>
|
||||
public record ReadRecActionQueryBase
|
||||
{
|
||||
public int ProfileId { get; init; }
|
||||
|
||||
public ReadRecActionQuery ToReadQuery() => new(this);
|
||||
}
|
||||
|
||||
public record ReadRecActionQuery(ReadRecActionQueryBase Root) : ReadRecActionQueryBase(Root), IRequest<IEnumerable<RecActionDto>>;
|
||||
|
||||
public class ReadRecActionQueryHandler(IRepository<RecAction> repo, IMapper mapper) : IRequestHandler<ReadRecActionQuery, IEnumerable<RecActionDto>>
|
||||
{
|
||||
public async Task<IEnumerable<RecActionDto>> Handle(ReadRecActionQuery request, CancellationToken cancel)
|
||||
|
||||
9
src/ReC.Domain/Entities/BodyQueryResult.cs.cs
Normal file
9
src/ReC.Domain/Entities/BodyQueryResult.cs.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace ReC.Domain.Entities;
|
||||
|
||||
public class BodyQueryResult
|
||||
{
|
||||
[Column("REQUEST_BODY")]
|
||||
public string? RawBody { get; init; }
|
||||
}
|
||||
9
src/ReC.Domain/Entities/HeaderQueryResult.cs
Normal file
9
src/ReC.Domain/Entities/HeaderQueryResult.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace ReC.Domain.Entities;
|
||||
|
||||
public class HeaderQueryResult
|
||||
{
|
||||
[Column("REQUEST_HEADER")]
|
||||
public string? RawHeader { get; init; }
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
using DigitalData.Core.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using ReC.Domain.Entities;
|
||||
|
||||
namespace ReC.Infrastructure;
|
||||
@ -16,7 +17,9 @@ public static class DependencyInjection
|
||||
if(configOpt.DbContextOptionsAction is null)
|
||||
throw new InvalidOperationException("DbContextOptionsAction must be configured.");
|
||||
|
||||
services.AddDbContext<RecDbContext>(configOpt.DbContextOptionsAction);
|
||||
services.AddDbContext<TRecDbContext>(configOpt.DbContextOptionsAction);
|
||||
|
||||
services.AddScoped<IRecDbContext>(provider => provider.GetRequiredService<TRecDbContext>());
|
||||
|
||||
services.AddDbRepository(opt => opt.RegisterFromAssembly<TRecDbContext>(typeof(RecAction).Assembly));
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ReC.Application\ReC.Application.csproj" />
|
||||
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using ReC.Domain.Entities;
|
||||
|
||||
namespace ReC.Infrastructure;
|
||||
|
||||
public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(options)
|
||||
public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(options), IRecDbContext
|
||||
{
|
||||
public DbSet<EndpointParam> EndpointParams { get; set; }
|
||||
|
||||
@ -11,10 +12,18 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
|
||||
|
||||
public DbSet<OutRes> OutRes { get; set; }
|
||||
|
||||
public DbSet<HeaderQueryResult> HeaderQueryResults { get; set; }
|
||||
|
||||
public DbSet<BodyQueryResult> BodyQueryResults { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<RecAction>().HasNoKey();
|
||||
|
||||
modelBuilder.Entity<HeaderQueryResult>().HasNoKey();
|
||||
|
||||
modelBuilder.Entity<BodyQueryResult>().HasNoKey();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user