Compare commits
11 Commits
feat/clien
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 34efb662ec | |||
| dcbff90ed8 | |||
| 404a1c4793 | |||
| 1cdd28738a | |||
| 45c7259ce8 | |||
| 6d9985051e | |||
| b9f5a3f10c | |||
| 243cc97aa2 | |||
| bb43bfa064 | |||
| b4966585ae | |||
| ae548d530f |
5
ReC.sln
5
ReC.sln
@ -15,11 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReC.Application", "src\ReC.
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReC.Client", "src\ReC.Client\ReC.Client.csproj", "{DA3A6BDD-8045-478F-860B-D1F0EB97F02B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
assets\icon.png = assets\icon.png
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 7.1 KiB |
@ -1,6 +1,7 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.API.Extensions;
|
||||
using ReC.Application.OutResults.Commands;
|
||||
using ReC.Application.OutResults.Queries;
|
||||
|
||||
namespace ReC.API.Controllers;
|
||||
@ -55,6 +56,34 @@ public class OutResController(IMediator mediator, IConfiguration config) : Contr
|
||||
_ => Ok(res),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes output results based on the provided criteria.
|
||||
/// </summary>
|
||||
/// <param name="command">The command containing the deletion criteria, such as ActionId or ProfileId.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>An empty response indicating success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteOutResCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all output results for a fake/test profile.
|
||||
/// </summary>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>An empty response indicating success.</returns>
|
||||
[HttpDelete("fake")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Delete(CancellationToken cancel)
|
||||
{
|
||||
await mediator.Send(new DeleteOutResCommand() { ProfileId = config.GetFakeProfileId() }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -4,6 +4,7 @@ using NLog.Web;
|
||||
using ReC.API.Middleware;
|
||||
using ReC.Application;
|
||||
using ReC.Infrastructure;
|
||||
using System.Reflection;
|
||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
@ -48,7 +49,12 @@ try
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
c.IncludeXmlComments(xmlPath);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@ -57,7 +63,7 @@ try
|
||||
#pragma warning restore CS0618
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
if (app.Environment.IsDevelopment() || config.GetValue<bool>("UseSwagger"))
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
@ -10,13 +10,15 @@
|
||||
<Product>ReC.API</Product>
|
||||
<PackageIcon>Assets\icon.ico</PackageIcon>
|
||||
<PackageTags>digital data rest-caller rec api</PackageTags>
|
||||
<Version>1.0.0-beta</Version>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<Version>1.0.1-beta</Version>
|
||||
<AssemblyVersion>1.0.1.0</AssemblyVersion>
|
||||
<FileVersion>1.0.1.0</FileVersion>
|
||||
<InformationalVersion>1.0.0-beta</InformationalVersion>
|
||||
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.11" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"UseSwagger": true,
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=SDD-VMP04-SQL19\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||
},
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using MediatR;
|
||||
using ReC.Domain.Entities;
|
||||
|
||||
namespace ReC.Application.OutResults.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the command to delete output results based on specified criteria.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Deletion can be performed by providing either an <see cref="ActionId"/> or a <see cref="ProfileId"/>.
|
||||
/// At least one of these properties must be set for the operation to proceed.
|
||||
/// </remarks>
|
||||
public record DeleteOutResCommand : IRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for the action whose output results should be deleted.
|
||||
/// </summary>
|
||||
public long? ActionId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for the profile whose associated action's output results should be deleted.
|
||||
/// </summary>
|
||||
public long? ProfileId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the execution of the <see cref="DeleteOutResCommand"/>.
|
||||
/// </summary>
|
||||
public class DeleteOutResCommandHandler(IRepository<OutRes> repo) : IRequestHandler<DeleteOutResCommand>
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes the delete command by removing matching <see cref="OutRes"/> entities from the repository.
|
||||
/// </summary>
|
||||
/// <param name="request">The command containing the deletion criteria.</param>
|
||||
/// <param name="cancel">A cancellation token that can be used to cancel the work.</param>
|
||||
/// <returns>A task that represents the asynchronous delete operation.</returns>
|
||||
/// <remarks>
|
||||
/// The handler deletes records where <c>OutRes.ActionId</c> matches <see cref="DeleteOutResCommand.ActionId"/>
|
||||
/// or where the associated <c>Action.ProfileId</c> matches <see cref="DeleteOutResCommand.ProfileId"/>.
|
||||
/// </remarks>
|
||||
public Task Handle(DeleteOutResCommand request, CancellationToken cancel)
|
||||
{
|
||||
return repo.DeleteAsync(x => x.ActionId == request.ActionId || x.Action!.ProfileId == request.ProfileId, cancel);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace ReC.Application.OutResults.Commands;
|
||||
|
||||
public class DeleteOutResCommandValidator : AbstractValidator<DeleteOutResCommand>
|
||||
{
|
||||
public DeleteOutResCommandValidator()
|
||||
{
|
||||
RuleFor(x => x)
|
||||
.Must(x => x.ActionId.HasValue || x.ProfileId.HasValue)
|
||||
.WithMessage("At least one of ActionId or ProfileId must be provided.")
|
||||
.WithName("Identifier");
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
#endif
|
||||
|
||||
namespace ReC.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for setting up the ReC client in an <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
public static class DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds and configures the <see cref="HttpClient"/> for the <see cref="ReCClient"/> to the specified <see cref="IServiceCollection"/>
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
|
||||
/// <param name="apiUri">The base URI of the ReC API.</param>
|
||||
/// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
|
||||
public static IHttpClientBuilder AddRecClient(this IServiceCollection services, string apiUri)
|
||||
{
|
||||
services.AddScoped<ReCClient>();
|
||||
return services.AddHttpClient(ReCClient.ClientName, client =>
|
||||
{
|
||||
client.BaseAddress = new Uri(apiUri);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds and configures the <see cref="HttpClient"/> for the <see cref="ReCClient"/> to the specified <see cref="IServiceCollection"/>
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
|
||||
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
||||
/// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
|
||||
public static IHttpClientBuilder AddRecClient(this IServiceCollection services, Action<HttpClient> configureClient)
|
||||
{
|
||||
services.AddScoped<ReCClient>();
|
||||
return services.AddHttpClient(ReCClient.ClientName, configureClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,36 +2,10 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net8.0</TargetFrameworks>
|
||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).xml</DocumentationFile>
|
||||
<PackageId>ReC.Client</PackageId>
|
||||
<Authors>Digital Data GmbH</Authors>
|
||||
<Company>Digital Data GmbH</Company>
|
||||
<Product>ReC.Client</Product>
|
||||
<Copyright>Copyright 2025</Copyright>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>http://git.dd:3000/AppStd/Rec.git</RepositoryUrl>
|
||||
<PackageTags>digital data rec api</PackageTags>
|
||||
<Version>1.0.0-beta</Version>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<Description>Client-Bibliothek für die Interaktion mit der ReC.API, die typisierten HTTP-Zugriff und DI-Integration bietet.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'net462'">
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\assets\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,124 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace ReC.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// A client for interacting with the ReC API.
|
||||
/// </summary>
|
||||
public class ReCClient
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
|
||||
/// <summary>
|
||||
/// A unique name for the HttpClient used by the ReCClient.
|
||||
/// </summary>
|
||||
public static readonly string ClientName = Guid.NewGuid().ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReCClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The factory to create HttpClients.</param>
|
||||
public ReCClient(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_http = httpClientFactory.CreateClient(ClientName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously invokes a ReC action for a specific profile.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method sends a POST request to the <c>api/RecAction/invoke/{profileId}</c> endpoint.
|
||||
/// </remarks>
|
||||
/// <param name="profileId">The ID of the profile to invoke the action for.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the asynchronous operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous operation. The task result is <see langword="true"/> if the request was successful; otherwise, <see langword="false"/>.</returns>
|
||||
public async Task<bool> InvokeRecActionAsync(int profileId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var resp = await _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null, cancellationToken);
|
||||
return resp.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronously invokes a ReC action for a specific profile.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method sends a POST request to the <c>api/RecAction/invoke/{profileId}</c> endpoint.
|
||||
/// This is the synchronous version of <see cref="InvokeRecActionAsync(int, CancellationToken)"/>.
|
||||
/// </remarks>
|
||||
/// <param name="profileId">The ID of the profile to invoke the action for.</param>
|
||||
/// <returns><see langword="true"/> if the request was successful; otherwise, <see langword="false"/>.</returns>
|
||||
[Obsolete("Use InvokeRecActionAsync instead to avoid potential deadlocks and improve performance.")]
|
||||
public bool InvokeRecAction(int profileId)
|
||||
{
|
||||
var resp = _http.PostAsync($"api/RecAction/invoke/{profileId}", content: null).GetAwaiter().GetResult();
|
||||
return resp.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
#region Static
|
||||
private static readonly IServiceCollection Services = new ServiceCollection();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
private static IServiceProvider? Provider = null;
|
||||
#else
|
||||
private static IServiceProvider Provider = null;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Configures and builds the static <see cref="IServiceProvider"/> for creating <see cref="ReCClient"/> instances.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method should only be called once during application startup.
|
||||
/// </remarks>
|
||||
/// <param name="apiUri">The base URI of the ReC API.</param>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||
public static void BuildStaticClient(string apiUri)
|
||||
{
|
||||
if(Provider != null)
|
||||
throw new InvalidOperationException("Static Provider is already built.");
|
||||
|
||||
Services.AddRecClient(apiUri);
|
||||
Provider = Services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures and builds the static <see cref="IServiceProvider"/> for creating <see cref="ReCClient"/> instances.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method should only be called once during application startup.
|
||||
/// </remarks>
|
||||
/// <param name="configureClient">An action to configure the <see cref="HttpClient"/>.</param>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the static provider has already been built.</exception>
|
||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||
public static void BuildStaticClient(Action<HttpClient> configureClient)
|
||||
{
|
||||
if (Provider != null)
|
||||
throw new InvalidOperationException("Static Provider is already built.");
|
||||
|
||||
Services.AddRecClient(configureClient);
|
||||
Provider = Services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ReCClient"/> instance using the statically configured provider.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the <see cref="ReCClient"/>.</returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if <see cref="BuildStaticClient(string)"/> has not been called yet.</exception>
|
||||
[Obsolete("Use a local service collection instead of the static provider.")]
|
||||
public static ReCClient Create()
|
||||
{
|
||||
if (Provider == null)
|
||||
throw new InvalidOperationException("Static Provider is not built. Call BuildStaticClient first.");
|
||||
|
||||
return Provider.GetRequiredService<ReCClient>();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -34,8 +34,8 @@ public class RecActionView
|
||||
[MaxLength(20)]
|
||||
public string? ProfileType { get; set; }
|
||||
|
||||
[Column("PROFILE_SEQUENCE")]
|
||||
public byte? ProfileSequence { get; set; }
|
||||
[Column("SEQUENCE")]
|
||||
public byte? Sequence { get; set; }
|
||||
|
||||
[Column("ENDPOINT_ID")]
|
||||
public long? EndpointId { get; set; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user