Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Elsa.Server.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
<Project Path="src\Elsa\Agent\GitHubCopilot\Elsa.Agent.GitHubCopilot.csproj" />
<Project Path="src\Elsa\Agent\Workflows\Elsa.Agent.Workflows.csproj" />
</Folder>
<Folder Name="/src/Elsa/Attention/">
<Project Path="src/Elsa/Attention/Core/Elsa.Attention.Core.csproj" />
<Project Path="src/Elsa/Attention/Api/Elsa.Attention.Api.csproj" />
</Folder>
<Folder Name="/src/Elsa/Api/">
<Project Path="src/Elsa/Api/Capabilities/Elsa.Api.Capabilities.csproj" />
<Project Path="src/Elsa/Api/FastEndpoints/Elsa.Api.FastEndpoints.csproj" />
Expand Down Expand Up @@ -149,6 +153,7 @@
<Project Path="src/Elsa/Mediator/Elsa.Mediator.csproj" />
</Folder>
<Folder Name="/src/Elsa/Modularity/">
<Project Path="src/Elsa/Modularity/Attention/Elsa.Modularity.Attention.csproj" />
<Project Path="src/Elsa/Modularity/Api/Elsa.Modularity.Api.csproj" />
<Project Path="src/Elsa/Modularity/Core/Elsa.Modularity.Core.csproj" />
<Project Path="src/Elsa/Modularity/ExtensionBuilder/Elsa.Modularity.ExtensionBuilder.csproj" />
Expand Down Expand Up @@ -201,10 +206,18 @@
<Project Path="src/Elsa/Serialization/SystemText/Elsa.Serialization.SystemText.csproj" />
</Folder>
<Folder Name="/src/Elsa/Secrets/">
<Project Path="src/Elsa/Secrets/Attention/Elsa.Secrets.Attention.csproj" />
<Project Path="src/Elsa/Secrets/Api/Elsa.Secrets.Api.csproj" />
<Project Path="src/Elsa/Secrets/Core/Elsa.Secrets.Core.csproj" />
<Project Path="src/Elsa/Secrets/Elsa.Secrets.csproj" />
</Folder>
<Folder Name="/src/Elsa/Studio/Preferences/">
<Project Path="src/Elsa/Studio/Preferences/Core/Elsa.Studio.Preferences.Core.csproj" />
<Project Path="src/Elsa/Studio/Preferences/Api/Elsa.Studio.Preferences.Api.csproj" />
</Folder>
<Folder Name="/src/Elsa/Studio/Preferences/Persistence/">
<Project Path="src/Elsa/Studio/Preferences/Persistence/Groundwork/Elsa.Studio.Preferences.Persistence.Groundwork.csproj" />
</Folder>
<Folder Name="/src/Elsa/Secrets/Persistence/">
<Project Path="src/Elsa/Secrets/Persistence/Groundwork/Elsa.Secrets.Persistence.Groundwork.csproj" />
</Folder>
Expand All @@ -219,6 +232,12 @@
<Folder Name="/src/Elsa/Workflows/">
<Project Path="src/Elsa/Workflows/Primitives/Elsa.Workflows.Primitives.csproj" />
</Folder>
<Folder Name="/src/Elsa/Workflows/Dashboard/">
<Project Path="src/Elsa/Workflows/Dashboard/Elsa.Workflows.Dashboard.csproj" />
</Folder>
<Folder Name="/src/Elsa/Workflows/Dashboard/Persistence/">
<Project Path="src/Elsa/Workflows/Dashboard/Persistence/Groundwork/Elsa.Workflows.Dashboard.Persistence.Groundwork.csproj" />
</Folder>
<Folder Name="/src/Elsa/Workflows/Design/">
<Project Path="src/Elsa/Workflows/Design/Api/Elsa.Workflows.Design.Api.csproj" />
<Project Path="src/Elsa/Workflows/Design/CodeGeneration/Elsa.Workflows.Design.CodeGeneration.csproj" />
Expand Down Expand Up @@ -250,6 +269,7 @@
<Project Path="src/Elsa/Workflows/Publishing/Persistence/Groundwork/Elsa.Workflows.Publishing.Persistence.Groundwork.csproj" />
</Folder>
<Folder Name="/src/Elsa/Workflows/Runtime/">
<Project Path="src/Elsa/Workflows/Runtime/Attention/Elsa.Workflows.Runtime.Attention.csproj" />
<Project Path="src/Elsa/Workflows/Runtime/Api/Elsa.Workflows.Runtime.Api.csproj" />
<Project Path="src/Elsa/Workflows/Runtime/Core/Elsa.Workflows.Runtime.Core.csproj" />
<Project Path="src/Elsa/Workflows/Runtime/Elsa.Workflows.Runtime.csproj" />
Expand Down Expand Up @@ -365,6 +385,12 @@
<Folder Name="/tests/Elsa/Foundation/Identity/">
<Project Path="tests/Elsa/Foundation/Identity/Tests/Elsa.Foundation.Identity.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Attention/Core/">
<Project Path="tests/Elsa/Attention/Core/Tests/Elsa.Attention.Core.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Attention/Api/">
<Project Path="tests/Elsa/Attention/Api/Tests/Elsa.Attention.Api.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Foundation/Identity/AspNetCoreIdentity/Groundwork/">
<Project Path="tests/Elsa/Foundation/Identity/AspNetCoreIdentity/Groundwork/Tests/Elsa.Foundation.Identity.AspNetCoreIdentity.Groundwork.Tests.csproj" />
</Folder>
Expand All @@ -375,6 +401,9 @@
<Folder Name="/tests/Elsa/Modularity/">
<Project Path="tests/Elsa/Modularity/Tests/Elsa.Modularity.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Modularity/Attention/">
<Project Path="tests/Elsa/Modularity/Attention/Tests/Elsa.Modularity.Attention.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Primitives/">
<Project Path="tests/Elsa/Primitives/Tests/Elsa.Primitives.Tests.csproj" />
</Folder>
Expand Down Expand Up @@ -425,13 +454,25 @@
<Folder Name="/tests/Elsa/Secrets/">
<Project Path="tests/Elsa/Secrets/Tests/Elsa.Secrets.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Secrets/Attention/">
<Project Path="tests/Elsa/Secrets/Attention/Tests/Elsa.Secrets.Attention.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Studio/Preferences/">
<Project Path="tests/Elsa/Studio/Preferences/Tests/Elsa.Studio.Preferences.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Studio/Preferences/Persistence/Groundwork/">
<Project Path="tests/Elsa/Studio/Preferences/Persistence/Groundwork/Tests/Elsa.Studio.Preferences.Persistence.Groundwork.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Serialization/">
<Project Path="tests/Elsa/Serialization/Tests/Elsa.Serialization.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Workflows/" />
<Folder Name="/tests/Elsa/Workflows/Design/">
<Project Path="tests/Elsa/Workflows/Design/Tests/Elsa.Workflows.Design.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Workflows/Dashboard/">
<Project Path="tests/Elsa/Workflows/Dashboard/Tests/Elsa.Workflows.Dashboard.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Workflows/Design/CodeGeneration/">
<Project Path="tests/Elsa/Workflows/Design/CodeGeneration/Tests/Elsa.Workflows.Design.CodeGeneration.Tests.csproj" />
</Folder>
Expand All @@ -452,6 +493,9 @@
<Folder Name="/tests/Elsa/Workflows/Runtime/">
<Project Path="tests/Elsa/Workflows/Runtime/Tests/Elsa.Workflows.Runtime.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Workflows/Runtime/Attention/">
<Project Path="tests/Elsa/Workflows/Runtime/Attention/Tests/Elsa.Workflows.Runtime.Attention.Tests.csproj" />
</Folder>
<Folder Name="/tests/Elsa/Workflows/Runtime/Api/">
<Project Path="tests/Elsa/Workflows/Runtime/Api/Tests/Elsa.Workflows.Runtime.Api.Tests.csproj" />
</Folder>
Expand Down
1 change: 1 addition & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ environment variables. Standard .NET double-underscore (`__`) env keys override
| `ASPNETCORE_URLS` | Kestrel bind (already set in the image) | `http://+:8080` |
| `Elsa__ModuleManagement__ApiKey` | The Elsa host management key the server accepts on its `/_elsa/module-management` API (header `X-Elsa-Module-Management-Key`). Server-side only — the browser never sees or sends it. **Must match** Studio's `Studio__BackendModuleManagementApiKey`. | `elsa-docker-demo-key` |
| `Cors__AllowedOrigins__0`, `__1`, … | Browser origins allowed by the `ElsaStudio` CORS policy. The Studio container's **published host origin** must be listed. | `http://localhost:14000` |
| `CShells__Shells__default__Features__FoundationIdentityAspNetCoreIdentity__AllowedReturnUrlOrigins__0`, `__1`, … | Origins the development login provider may redirect back to after sign-in. Add the Studio origin when Studio is hosted separately from the backend. | `http://localhost:14000` |
| `CShells__Shells__default__Features__GroundworkUnifiedPersistencePostgreSql__ConnectionString` | Optional: override the Postgres connection string without editing the mounted `shells.json`. | *(commented out)* |

`Cors:AllowedOrigins` defaults (in `appsettings.json`) are localhost dev values for running the
Expand Down
10 changes: 10 additions & 0 deletions src/Apps/Elsa.Server/Elsa.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
<ProjectReference Include="..\..\Elsa\Agent\Api\Elsa.Agent.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Agent\GitHubCopilot\Elsa.Agent.GitHubCopilot.csproj" />
<ProjectReference Include="..\..\Elsa\Agent\Workflows\Elsa.Agent.Workflows.csproj" />
<ProjectReference Include="..\..\Elsa\Attention\Core\Elsa.Attention.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Attention\Api\Elsa.Attention.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Activities\Design\Api\Elsa.Activities.Design.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Activities\Design\Core\Elsa.Activities.Design.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Activities\Design\Persistence\Core\Elsa.Activities.Design.Persistence.Core.csproj" />
Expand Down Expand Up @@ -72,10 +74,14 @@
<ProjectReference Include="..\..\Elsa\Foundation\Identity\Oidc\Elsa.Foundation.Identity.Oidc.csproj" />
<ProjectReference Include="..\..\Elsa\Foundation\Identity\OpenIddict\Elsa.Foundation.Identity.OpenIddict.csproj" />
<ProjectReference Include="..\..\Elsa\Secrets\Persistence\Groundwork\Elsa.Secrets.Persistence.Groundwork.csproj" />
<ProjectReference Include="..\..\Elsa\Secrets\Attention\Elsa.Secrets.Attention.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Dashboard\Elsa.Workflows.Dashboard.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Dashboard\Persistence\Groundwork\Elsa.Workflows.Dashboard.Persistence.Groundwork.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Design\JavaScript\Elsa.Workflows.Design.JavaScript.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Publishing\Api\Elsa.Workflows.Publishing.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Publishing\Persistence\Groundwork\Elsa.Workflows.Publishing.Persistence.Groundwork.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Runtime\Api\Elsa.Workflows.Runtime.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Workflows\Runtime\Attention\Elsa.Workflows.Runtime.Attention.csproj" />
<ProjectReference Include="..\..\Elsa\Caching\Core\Elsa.Caching.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Caching\Memory\Elsa.Caching.Memory.csproj" />
<ProjectReference Include="..\..\Elsa\Diagnostics\ConsoleLogStreaming\Elsa.Diagnostics.ConsoleLogStreaming.csproj" />
Expand All @@ -87,6 +93,7 @@
<ProjectReference Include="..\..\Elsa\Locking\FileSystem\Elsa.Locking.FileSystem.csproj" />
<ProjectReference Include="..\..\Elsa\Mediator\Elsa.Mediator.csproj" />
<ProjectReference Include="..\..\Elsa\Modularity\Api\Elsa.Modularity.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Modularity\Attention\Elsa.Modularity.Attention.csproj" />
<ProjectReference Include="..\..\Elsa\Modularity\Core\Elsa.Modularity.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Modularity\ExtensionBuilder\Elsa.Modularity.ExtensionBuilder.csproj" />
<ProjectReference Include="..\..\Elsa\Modularity\Nuplane\Elsa.Modularity.Nuplane.csproj" />
Expand All @@ -98,6 +105,9 @@
<ProjectReference Include="..\..\Elsa\Primitives\Hosting\Elsa.Primitives.Hosting.csproj" />
<ProjectReference Include="..\..\Elsa\Serialization\Newtonsoft\Elsa.Serialization.Newtonsoft.csproj" />
<ProjectReference Include="..\..\Elsa\Serialization\SystemText\Elsa.Serialization.SystemText.csproj" />
<ProjectReference Include="..\..\Elsa\Studio\Preferences\Core\Elsa.Studio.Preferences.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Studio\Preferences\Api\Elsa.Studio.Preferences.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Studio\Preferences\Persistence\Groundwork\Elsa.Studio.Preferences.Persistence.Groundwork.csproj" />
<ProjectReference Include="..\..\Elsa\Secrets\Api\Elsa.Secrets.Api.csproj" />
<ProjectReference Include="..\..\Elsa\Secrets\Core\Elsa.Secrets.Core.csproj" />
<ProjectReference Include="..\..\Elsa\Secrets\Elsa.Secrets.csproj" />
Expand Down
22 changes: 22 additions & 0 deletions src/Apps/Elsa.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,22 @@
using Elsa.Serialization.Newtonsoft;
using Elsa.Serialization.SystemText;
using Elsa.Tasks;
using Elsa.Attention.Api;
using Elsa.Modularity.Attention;
using Elsa.Secrets.Attention;
using Elsa.Studio.Preferences.Api;
using Elsa.Studio.Preferences.Core;
using Elsa.Studio.Preferences.Persistence.Groundwork;
using Elsa.Workflows.Design.Api;
using Elsa.Workflows.Dashboard;
using Elsa.Workflows.Publishing.Api;
using Elsa.Workflows.Publishing.Persistence.Groundwork;
using Elsa.Workflows.Runtime.Api;
using Elsa.Workflows.Runtime.Core.Models;
using Elsa.Workflows.Runtime.Http;
using Elsa.Workflows.Runtime.ReferenceGarbageCollection;
using Elsa.Workflows.Runtime.Resumption;
using Elsa.Workflows.Runtime.Attention;
using Nuplane;
using Nuplane.Admin;
using Nuplane.Loading.Hosting.Builder;
Expand All @@ -72,6 +80,12 @@
// keys + a seeded well-known admin, while Production hardens to durable stores, a persistent signing key
// (secret), and a configured initial admin (password supplied as a secret — never committed).
builder.Configuration.AddJsonFile($"shells.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
// WebApplication.CreateBuilder adds environment variables before these shell files. Re-add the environment and
// command-line providers after the shell layers so container environment variables override shells.json, while
// explicit command-line arguments retain the highest precedence.
builder.Configuration
.AddEnvironmentVariables()
.AddCommandLine(args);
var configuration = builder.Configuration;

// Console log streaming is a process-global, host-level diagnostic (not a shell feature): capture is a static tee on
Expand Down Expand Up @@ -245,8 +259,16 @@

typeof(OpenIddictIdentityFeature).Assembly,
typeof(ApiSecurityFeature).Assembly,
typeof(AttentionApiFeature).Assembly,
typeof(StudioPreferencesFeature).Assembly,
typeof(StudioPreferencesApiFeature).Assembly,
typeof(StudioPreferencesGroundworkPersistenceFeature).Assembly,
typeof(WorkflowsDashboardFeature).Assembly,

typeof(ModularityApiFeature).Assembly,
typeof(ModularityAttentionFeature).Assembly,
typeof(SecretsAttentionFeature).Assembly,
typeof(WorkflowsRuntimeAttentionFeature).Assembly,
typeof(StructuredLogsFeature).Assembly,
typeof(SqliteStructuredLogsPersistenceShellFeature).Assembly,
typeof(OpenTelemetryFeature).Assembly
Expand Down
7 changes: 7 additions & 0 deletions src/Apps/Elsa.Server/shells.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,16 @@
"SecretsApi": {},
"SecretsGroundworkPersistence": {},
"Serialization": {},
"AttentionApi": {},
"ModularityAttention": {},
"StudioPreferences": {},
"StudioPreferencesApi": {},
"StudioPreferencesGroundworkPersistence": {},
"Tasks": {},
"WeatherForecastSample": {},
"WorkflowsDesignApi": {},
"WorkflowsDashboard": {},
"WorkflowsRuntimeAttention": {},
"WorkflowsPublishingApi": {},
"WorkflowsPublishingGroundwork": {},
"WorkflowsRuntimeApi": {},
Expand Down
21 changes: 21 additions & 0 deletions src/Elsa/Attention/Api/AttentionApiFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using CShells.Features;
using Elsa.Api.FastEndpoints;
using Elsa.Platform.PackageManifest.Generator.Hints;
using Microsoft.Extensions.DependencyInjection;

namespace Elsa.Attention.Api;

[ManifestRuntimeKind(ElsaRuntimeKinds.Server)]
[ManifestFeatureCategory("Attention")]
[ShellFeature(
name: "AttentionApi",
DisplayName = "Attention API",
Description = "Aggregates permission-scoped attention contributors through a shared query endpoint.")]
public sealed class AttentionApiFeature : FastEndpointsFeatureBase
{
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
services.AddAttentionCore();
}
}
6 changes: 6 additions & 0 deletions src/Elsa/Attention/Api/AttentionRoutes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Elsa.Attention.Api;

public static class AttentionRoutes
{
public const string Items = "/_elsa/attention/items";
}
45 changes: 45 additions & 0 deletions src/Elsa/Attention/Api/AttentionServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Elsa.Attention.Core;
using Elsa.Foundation.Identity.Abstractions.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

namespace Elsa.Attention.Api;

public static class AttentionServiceCollectionExtensions
{
public static IServiceCollection AddAttentionCore(
this IServiceCollection services,
Action<AttentionOptions>? configure = null)
{
var options = services.AddOptions<AttentionOptions>();
if (configure is not null)
options.Configure(configure);

services.TryAddScoped<IAttentionPermissionEvaluator, FoundationAttentionPermissionEvaluator>();
services.TryAddScoped<IAttentionContributorRegistry>(provider =>
new AttentionContributorRegistry(provider.GetServices<IAttentionContributor>()));
services.TryAddScoped<IAttentionAggregationService>(provider =>
new AttentionAggregationService(
provider.GetRequiredService<IAttentionContributorRegistry>(),
provider.GetRequiredService<IAttentionPermissionEvaluator>(),
provider.GetRequiredService<IOptions<AttentionOptions>>().Value));
return services;
}

private sealed class FoundationAttentionPermissionEvaluator(IPermissionEvaluator evaluator)
: IAttentionPermissionEvaluator
{
public async ValueTask<bool> IsAllowedAsync(
System.Security.Claims.ClaimsPrincipal principal,
string permission,
string? tenantId,
CancellationToken cancellationToken = default)
{
var result = await evaluator.EvaluateAsync(
new PermissionEvaluationContext(principal, permission, tenantId),
cancellationToken);
return result.Succeeded;
}
}
}
24 changes: 24 additions & 0 deletions src/Elsa/Attention/Api/Elsa.Attention.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CShells.Abstractions" />
<PackageReference Include="Elsa.Platform.PackageManifest.Generator" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Core\Elsa.Attention.Core.csproj" />
<ProjectReference Include="..\..\Api\FastEndpoints\Elsa.Api.FastEndpoints.csproj" />
<ProjectReference Include="..\..\Foundation\Identity\Abstractions\Elsa.Foundation.Identity.Abstractions.csproj" />
</ItemGroup>

</Project>
41 changes: 41 additions & 0 deletions src/Elsa/Attention/Api/Endpoints/GetAttentionItems.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Elsa.Api.FastEndpoints.Abstractions;
using Elsa.Attention.Core;
using Elsa.Foundation.Identity.Abstractions.Authorization;
using Microsoft.AspNetCore.Http;

namespace Elsa.Attention.Api.Endpoints;

internal sealed class GetAttentionItems(IAttentionAggregationService aggregationService)
: ElsaEndpointWithoutRequest<AttentionAggregationResult>
{
public override void Configure()
{
Get(AttentionRoutes.Items);
ConfigurePermissions();
}

public override async Task HandleAsync(CancellationToken cancellationToken)
{
var contributorIds = HttpContext.Request.Query["contributorId"]
.Select(value => value ?? string.Empty)
.ToArray();
var context = new AttentionQueryContext(
HttpContext.User,
HttpContext.User.FindFirst(IdentityClaimTypes.TenantId)?.Value);

try
{
var response = await aggregationService.AggregateAsync(
new AttentionQuery(context, contributorIds.Length == 0 ? null : contributorIds),
cancellationToken);
await Send.OkAsync(response, cancellationToken);
}
catch (AttentionQueryException exception)
{
await Send.StringAsync(
exception.Message,
StatusCodes.Status400BadRequest,
cancellation: cancellationToken);
}
}
}
Loading
Loading