Compare commits

...

17 Commits

Author SHA1 Message Date
Developer 02
dcc0e8c806 Add logging to handle null RestType in RecActionCommand
Enhanced the `InvokeRecActionCommandHandler` class by adding
logging functionality using `ILogger`. Updated the constructor
to accept an optional logger parameter. Introduced a check for
`RestType` being `null` and added a warning log to handle such
cases gracefully. This prevents processing invalid actions and
improves system robustness.
2025-11-26 21:54:22 +01:00
Developer 02
73ee0302ef Limit concurrent HTTP requests with SemaphoreSlim
Introduced a `SemaphoreSlim` with a concurrency limit of 5 to
control the number of simultaneous HTTP requests. Updated the
HTTP request logic to use `WaitAsync` and `Release` for
managing access to the critical section. Wrapped the HTTP
request handling in a `try-finally` block to ensure proper
semaphore release, even in case of exceptions. This change
improves resource management and prevents overwhelming the
HTTP client or the target server.
2025-11-26 21:49:09 +01:00
Developer 02
d80e0d3562 Refactor HTTP requests to enable parallel execution
Replaced sequential `foreach` loop with LINQ's `Select` to create a collection of tasks for sending HTTP requests asynchronously. Added `Task.WhenAll` to execute all requests concurrently, improving performance. Removed the old `foreach` implementation in favor of a functional programming approach.
2025-11-26 21:47:23 +01:00
Developer 02
1e35e4a057 Add HttpClient registration to DI container
Added a call to `services.AddHttpClient();` in the `DependencyInjection` class within `DependencyInjection.cs`. This change registers the `HttpClient` service in the dependency injection container, allowing the application to use managed `HttpClient` instances.
2025-11-26 21:44:24 +01:00
Developer 02
7c00060f74 Refactor HTTP handling in InvokeRecActionCommand
Updated `ReC.Application.csproj` to include `Microsoft.Extensions.Http` for improved HTTP client management. Refactored `InvokeRecActionCommandHandler` to use `IHttpClientFactory` for creating `HttpClient` instances, enhancing resource efficiency. Simplified HTTP method handling by replacing the switch statement with a dynamic `HttpMethod` and `HttpRequestMessage` approach. Removed redundant `using` directives and renamed `header` to `headers` for clarity. Removed `BadRequestException` for unsupported REST types, streamlining error handling.
2025-11-26 21:35:53 +01:00
Developer 02
0837bca6cb Add response body and headers processing
In the `InvokeRecActionCommandHandler` class, added code to read the response content as a string and store it in a `body` variable. Also, converted response headers into a dictionary and stored them in a `header` variable. These changes facilitate further processing of the response content and headers.
2025-11-26 17:49:01 +01:00
Developer 02
904448ca45 Add support for more HTTP methods
Extended the switch expression in `InvokeRecActionCommand.cs` to handle additional HTTP methods: "PATCH", "HEAD", "OPTIONS", and "TRACE".
Implemented the appropriate asynchronous HTTP requests using `HttpClient`.
"PATCH" uses `http.PatchAsync`, while "HEAD", "OPTIONS", and "TRACE" use `http.SendAsync` with a new `HttpRequestMessage`.
A `BadRequestException` is thrown for unsupported methods.
2025-11-26 17:34:52 +01:00
Developer 02
c16d58788a Refactor switch statement to switch expression
Replaced the `switch` statement with a `switch` expression to handle HTTP methods (`GET`, `POST`, `PUT`, `DELETE`). This refactoring reduces boilerplate code and improves readability by directly assigning the HTTP request result to the `response` variable, eliminating the need for multiple `using` and `break` statements.
2025-11-26 17:34:42 +01:00
Developer 02
a854720c75 Add DELETE request handling in command handler
Implemented the handling of DELETE HTTP requests in the
InvokeRecActionCommandHandler class. Previously, the DELETE
case was unhandled, and now it uses http.DeleteAsync to
send a DELETE request to the specified action.EndpointUri,
supporting cancellation with the cancel token.
2025-11-26 17:29:58 +01:00
Developer 02
c6bcdc3fac Add PUT request handling in InvokeRecActionCommandHandler
Implemented HTTP PUT request handling in the
InvokeRecActionCommandHandler class. Previously, the PUT case
only had a placeholder comment. Now, it uses
http.PutAsync to send a PUT request to the specified
action.EndpointUri, aligning it with the existing POST
request handling.
2025-11-26 17:29:29 +01:00
Developer 02
a57f53b6a1 Add POST request handling in InvokeRecActionCommandHandler
Previously, the handling of HTTP POST requests in the
InvokeRecActionCommandHandler class was not implemented.
This commit adds the necessary code to handle POST requests
by using the http.PostAsync method. The POST request is sent
to the specified action.EndpointUri with null content and a
cancellation token. This change ensures that POST operations
are now properly executed within the command handler.
2025-11-26 17:29:06 +01:00
Developer 02
eb402504ff Refactor HTTP request handling in action loop
Updated the HTTP request handling logic within the action loop to dynamically construct requests based on the `RestType` and `EndpointUri` of each action. Expanded the switch statement to handle GET, POST, PUT, and DELETE methods, allowing for specific logic to be implemented for each. Removed the hardcoded URL and response content retrieval, indicating potential refactoring of response handling. The default case continues to throw a `BadRequestException` for unsupported REST types.
2025-11-26 17:28:26 +01:00
Developer 02
5b7fce8fd6 Make RestType handling case-insensitive in switch
Convert RestType to uppercase in the switch statement to
ensure case-insensitive matching of REST types. This change
handles variations like "get", "Get", and "GET" consistently.
Additionally, use the null-conditional operator to prevent
NullReferenceException when RestType is null.
2025-11-26 17:23:51 +01:00
Developer 02
9a0a37471e Add REST action handling in InvokeRecActionCommand
Refactor `using` directives in `InvokeRecActionCommand.cs` to include `DigitalData.Core.Exceptions` and `System.Net.Http`.

Implement logic in `InvokeRecActionCommandHandler` to handle different REST actions using `HttpClient`. Introduce a `switch` statement to process "GET", "POST", "PUT", and "DELETE" actions, with a `BadRequestException` for unsupported types. Read HTTP response content asynchronously.
2025-11-26 17:23:14 +01:00
Developer 02
dcd399a92e add logic to read actions 2025-11-26 17:17:32 +01:00
Developer 02
59152a5621 umdate inveokeRecActionCommand 2025-11-26 17:16:01 +01:00
Developer 02
20ca2c2e48 init ReadRecAction query 2025-11-26 17:12:30 +01:00
4 changed files with 70 additions and 2 deletions

View File

@ -22,6 +22,8 @@ public static class DependencyInjection
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey; cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
}); });
services.AddHttpClient();
return services; return services;
} }

View File

@ -8,7 +8,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="15.1.0" /> <PackageReference Include="AutoMapper" Version="15.1.0" />
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.5.0" />
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
<PackageReference Include="MediatR" Version="13.1.0" /> <PackageReference Include="MediatR" Version="13.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,10 +1,11 @@
using MediatR; using MediatR;
using Microsoft.Extensions.Logging;
using ReC.Application.RecActions.Queries;
namespace ReC.Application.RecActions.Commands; namespace ReC.Application.RecActions.Commands;
public class InvokeRecActionCommand : IRequest public class InvokeRecActionCommand : ReadRecActionQuery, IRequest
{ {
public int ProfileId { get; init; }
} }
public static class InvokeRecActionCommandExtensions public static class InvokeRecActionCommandExtensions
@ -12,3 +13,45 @@ public static class InvokeRecActionCommandExtensions
public static Task InvokeRecAction(this ISender sender, int profileId) public static Task InvokeRecAction(this ISender sender, int profileId)
=> sender.Send(new InvokeRecActionCommand { ProfileId = profileId }); => sender.Send(new InvokeRecActionCommand { ProfileId = profileId });
} }
public class InvokeRecActionCommandHandler(ISender sender, IHttpClientFactory clientFactory, ILogger<InvokeRecActionCommandHandler>? logger = null) : IRequestHandler<InvokeRecActionCommand>
{
public async Task Handle(InvokeRecActionCommand request, CancellationToken cancel)
{
var actions = await sender.Send(request as ReadRecActionQuery, cancel);
var http = clientFactory.CreateClient();
using var semaphore = new SemaphoreSlim(5);
var tasks = actions.Select(async action =>
{
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;
}
var method = new HttpMethod(action.RestType.ToUpper());
var msg = new HttpRequestMessage(method, action.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);
}
}

View File

@ -1,5 +1,10 @@
using MediatR; using MediatR;
using ReC.Application.Dto; using ReC.Application.Dto;
using DigitalData.Core.Abstraction.Application.Repository;
using ReC.Domain.Entities;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using DigitalData.Core.Exceptions;
namespace ReC.Application.RecActions.Queries; namespace ReC.Application.RecActions.Queries;
@ -7,3 +12,16 @@ public class ReadRecActionQuery : IRequest<IEnumerable<RecActionDto>>
{ {
public int ProfileId { get; init; } public int ProfileId { get; init; }
} }
public class ReadRecActionQueryHandler(IRepository<RecAction> repo, IMapper mapper) : IRequestHandler<ReadRecActionQuery, IEnumerable<RecActionDto>>
{
public async Task<IEnumerable<RecActionDto>> Handle(ReadRecActionQuery request, CancellationToken cancel)
{
var actions = await repo.Where(x => x.ProfileId == request.ProfileId).ToListAsync(cancel);
if(actions.Count != 0)
throw new NotFoundException($"No actions found for the profile {request.ProfileId}.");
return mapper.Map<IEnumerable<RecActionDto>>(actions);
}
}