Implement multitenant HTTP routing (#6031)
* Add tenant awareness to bookmark handling and route resolution Added tenant ID support across various components, including bookmark updates, route resolution, and middleware processing. This ensures that bookmark and route operations can now appropriately handle tenant-specific data, improving the system's multitenancy capabilities. * Add Multitenant HTTP Routing feature to Tenants module Introduced a new MultitenantHttpRoutingFeature class to the Elsa.Tenants.AspNetCore module, enhancing the tenant resolution capabilities. Moved RoutePrefixTenantResolver from Elsa.Http to Elsa.Tenants.AspNetCore and updated relevant project references and namespaces accordingly. This refactor improves modularity and separation of concerns between HTTP and tenancy features. * Refactor route handling and tenant configuration Removed redundant `RouteTableExtensions` and replaced with new route providers and updaters, enhancing flexibility and modularity. Introduced tenant-specific HTTP endpoint configurations for better customization and configuration management. * Rename HttpEndpointBookmarkStimulus to HttpEndpointBookmarkPayload Refactor various classes and methods to reflect the renaming from `HttpEndpointBookmarkStimulus` to `HttpEndpointBookmarkPayload`. Add and configure new extension methods for tenant route handling, update the route provider to support multi-tenancy, and adjust the tenants provider to bind configuration properly. * Add HeaderTenantResolver and refactor Http namespace. Introduce HeaderTenantResolver to resolve tenants via HTTP headers. Refactor multiple classes and interfaces to move from the Elsa.Http.Models namespace directly into Elsa.Http for clarity and consistency. * Add Host-based tenant resolution Implemented a HostTenantResolver to resolve tenants based on the request's host and updated tenant configurations with host information. Modified the tenant resolver pipeline and added the new host resolver to the service registrations. * Add tenant-aware caching and accessor support Enhanced caching by incorporating tenant identifiers into cache keys for more granular cache management. Introduced ITenantAccessor dependencies in various services to retrieve the current tenant information. This ensures that cache entries are correctly isolated per tenant. * Reorder tenant resolvers for pipeline setup. Reordered the tenant resolvers in the pipeline to prioritize HostTenantResolver before RoutePrefixTenantResolver. This ensures that tenant resolution is correctly aligned with host-based resolving before checking the route prefix. * Remove unused imports This commit eliminates redundant `using` directives across multiple files to streamline the codebase. This cleanup helps improve code readability and maintainability by removing unnecessary dependencies.
This commit is contained in:
parent
9808020d57
commit
7e7a899bbf
|
|
@ -95,7 +95,7 @@
|
|||
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.4.3" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1"/>
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageVersion Include="Testcontainers" Version="3.9.0" />
|
||||
<PackageVersion Include="Testcontainers.RabbitMq" Version="3.9.0" />
|
||||
<PackageVersion Include="Testcontainers.Redis" Version="3.9.0" />
|
||||
|
|
@ -130,6 +130,7 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
||||
|
|
@ -164,6 +165,7 @@
|
|||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="8.0.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||
|
|
|
|||
2
Elsa.sln
2
Elsa.sln
|
|
@ -301,8 +301,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integrations", "integration
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.OrchardCore", "src\modules\Elsa.OrchardCore\Elsa.OrchardCore.csproj", "{B0460856-7E6D-4B1E-B243-8E20662FC32E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.AspNet.OrchardCoreIntegration", "samples\aspnet\Elsa.Samples.AspNet.OrchardCoreIntegration\Elsa.Samples.AspNet.OrchardCoreIntegration.csproj", "{1451B84D-F224-4D5D-9A0D-985A8BD23D7B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "agents", "agents", "{50470834-4CD8-479A-8B58-0A1869BA5D37}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Agents.Core", "src\modules\Elsa.Agents.Core\Elsa.Agents.Core.csproj", "{5BD671F0-9603-4C2F-8364-54B02986EAA2}"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using Elsa.EntityFrameworkCore.Modules.Management;
|
|||
using Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.Http.Multitenancy;
|
||||
using Elsa.Identity.Multitenancy;
|
||||
using Elsa.MassTransit.Extensions;
|
||||
using Elsa.MongoDb.Extensions;
|
||||
|
|
@ -26,6 +25,7 @@ using Elsa.Secrets.Extensions;
|
|||
using Elsa.Secrets.Persistence;
|
||||
using Elsa.Server.Web;
|
||||
using Elsa.Server.Web.Filters;
|
||||
using Elsa.Tenants.AspNetCore;
|
||||
using Elsa.Tenants.Extensions;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Api;
|
||||
|
|
@ -442,16 +442,16 @@ services
|
|||
.UseSecrets()
|
||||
.UseSecretsManagement(management =>
|
||||
{
|
||||
management.ConfigureOptions(options => configuration.GetSection("Secrets:Management").Bind(options));
|
||||
if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql)
|
||||
management.UseEntityFrameworkCore(ef =>
|
||||
ef.UseSqlServer(sqlServerConnectionString)
|
||||
);
|
||||
else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql)
|
||||
management.UseEntityFrameworkCore(ef =>
|
||||
ef.UsePostgreSql(postgresConnectionString)
|
||||
);
|
||||
else
|
||||
management.ConfigureOptions(options => configuration.GetSection("Secrets:Management").Bind(options));
|
||||
if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql)
|
||||
management.UseEntityFrameworkCore(ef =>
|
||||
ef.UseSqlServer(sqlServerConnectionString)
|
||||
);
|
||||
else if (sqlDatabaseProvider == SqlDatabaseProvider.PostgreSql)
|
||||
management.UseEntityFrameworkCore(ef =>
|
||||
ef.UsePostgreSql(postgresConnectionString)
|
||||
);
|
||||
else
|
||||
management.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString));
|
||||
})
|
||||
.UseSecretsApi()
|
||||
|
|
@ -467,10 +467,15 @@ services
|
|||
{
|
||||
configuration.GetSection("Multitenancy").Bind(options);
|
||||
options.TenantResolverPipelineBuilder
|
||||
.Append<HostTenantResolver>()
|
||||
.Append<RoutePrefixTenantResolver>()
|
||||
.Append<HeaderTenantResolver>()
|
||||
.Append<ClaimsTenantResolver>();
|
||||
};
|
||||
tenants.UseConfigurationBasedTenantsProvider();
|
||||
});
|
||||
|
||||
elsa.UseTenantHttpRouting();
|
||||
}
|
||||
|
||||
elsa.InstallDropIns(options => options.DropInRootDirectory = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "DropIns"));
|
||||
|
|
|
|||
|
|
@ -25,21 +25,57 @@
|
|||
"Multitenancy": {
|
||||
"Tenants": [
|
||||
{
|
||||
"Id": "default",
|
||||
"Name": "Default"
|
||||
"Id": null,
|
||||
"Name": "Default",
|
||||
"Configuration": {
|
||||
"Http": {
|
||||
"Prefix": "",
|
||||
"Host": "localhost:5001"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": "tenant-1",
|
||||
"Name": "Tenant 1"
|
||||
"Name": "Tenant 1",
|
||||
"Configuration": {
|
||||
"Http": {
|
||||
"Prefix": "tenant-1",
|
||||
"Host": "localhost:5002"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=App_Data/elsa.tenant-1.sqlite.db;Cache=Shared;"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": "tenant-2",
|
||||
"Name": "Tenant 2"
|
||||
"Name": "Tenant 2",
|
||||
"Configuration": {
|
||||
"Http": {
|
||||
"Prefix": "tenant-2",
|
||||
"Host": "localhost:5003"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=App_Data/elsa.tenant-2.sqlite.db;Cache=Shared;"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": "tenant-2a",
|
||||
"TenantId": "tenant-2",
|
||||
"Name": "Tenant 2a"
|
||||
"Name": "Tenant 2a",
|
||||
"Configuration": {
|
||||
"Http": {
|
||||
"Prefix": "tenant-2a",
|
||||
"Host": "localhost:5004"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=App_Data/elsa.tenant-2a.sqlite.db;Cache=Shared;"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -84,7 +120,7 @@
|
|||
"Roles": [
|
||||
"admin"
|
||||
],
|
||||
"TenantId": "default"
|
||||
"TenantId": null
|
||||
},
|
||||
{
|
||||
"id": "b0cd0e506e713a9d",
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ using Elsa.JavaScript.Libraries.Extensions;
|
|||
using Elsa.ServerAndStudio.Web.Extensions;
|
||||
using Elsa.MassTransit.Extensions;
|
||||
using Elsa.ServerAndStudio.Web.Enums;
|
||||
using Jint;
|
||||
using Jint.Runtime.Modules;
|
||||
using Medallion.Threading.FileSystem;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ using Microsoft.AspNetCore.Components.Web;
|
|||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.JSInterop;
|
||||
using Elsa.Studio.Models;
|
||||
|
||||
// Build the host.
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System.Linq.Expressions;
|
||||
using Elsa.Api.Client.Resources.WorkflowInstances.Models;
|
||||
using Elsa.Api.Client.Shared.Models;
|
||||
|
||||
namespace Elsa.Api.Client.Resources.ActivityExecutions.Models;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Abstractions;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using Elsa.Workflows;
|
|||
using Elsa.Workflows.Models;
|
||||
using Humanizer;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.Agents.Activities.ActivityProviders;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Extensions;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Filters;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Agents.Api.Endpoints.Agents.IsUniqueName;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Agents.Persistence.Filters;
|
||||
using Elsa.Extensions;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Agents.Api.Endpoints.ApiKeys.Get;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Agents.Api.Endpoints.Services.Get;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Agents.Persistence.Contracts;
|
||||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.Agents.Persistence.Filters;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Agents.Persistence.Entities;
|
||||
using Elsa.EntityFrameworkCore;
|
||||
using Elsa.EntityFrameworkCore.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Workflows;
|
|||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Filters;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
|
||||
namespace Elsa.Alterations.Core.Services;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.AzureServiceBus.Models;
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Helpers;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.AzureServiceBus.Models;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using Azure.Messaging.ServiceBus;
|
||||
using Elsa.AzureServiceBus.Activities;
|
||||
using Elsa.AzureServiceBus.Models;
|
||||
using Elsa.Workflows.Helpers;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="DistributedLock.Core" />
|
||||
<PackageReference Include="LinqKit.Core" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Elsa.Common.Entities;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Elsa.Common.Multitenancy;
|
||||
|
||||
|
|
@ -13,9 +14,9 @@ public class Tenant : Entity
|
|||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration.
|
||||
/// </summary>
|
||||
IDictionary<string, object> Configuration { get; set; } = new Dictionary<string, object>();
|
||||
public IConfiguration Configuration { get; set; } = new ConfigurationBuilder().Build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using Elsa.Elasticsearch.Common;
|
|||
using Elsa.Elasticsearch.Shared.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.OrderDefinitions;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Common.Entities;
|
||||
using Elsa.EntityFrameworkCore.Common.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Elsa.EntityFrameworkCore.Common;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Elsa.EntityFrameworkCore.Modules.Labels;
|
|||
using Elsa.EntityFrameworkCore.Modules.Management;
|
||||
using Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
using Elsa.EntityFrameworkCore.PostgreSql.Handlers;
|
||||
using Elsa.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Elsa.Workflows.Management;
|
|||
using Elsa.Workflows.Management.Compression;
|
||||
using Elsa.Workflows.Management.Options;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Extensions;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.EntityFrameworkCore.Common;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using JetBrains.Annotations;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using Elsa.EntityFrameworkCore.Common;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using JetBrains.Annotations;
|
||||
using Open.Linq.AsyncExtensions;
|
||||
|
||||
namespace Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using Elsa.Features.Attributes;
|
|||
using Elsa.Features.Services;
|
||||
using Elsa.Hangfire.Services;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
using Elsa.Workflows.Runtime.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Contracts;
|
||||
|
||||
namespace Elsa.Hangfire.Jobs;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Scheduling;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Messages;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Hangfire.Extensions;
|
||||
using Elsa.Hangfire.Jobs;
|
||||
using Elsa.Scheduling;
|
||||
using Elsa.Workflows.Runtime.Requests;
|
||||
using Hangfire;
|
||||
using Hangfire.Storage;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Abstractions;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Abstractions;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Abstractions;
|
||||
|
|
|
|||
|
|
@ -3,14 +3,12 @@ using System.Reflection;
|
|||
using System.Runtime.CompilerServices;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.UIHints;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Attributes;
|
||||
using Elsa.Workflows.UIHints;
|
||||
using Elsa.Workflows.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using HttpHeaders = Elsa.Http.Models.HttpHeaders;
|
||||
|
||||
namespace Elsa.Http;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Text.Json;
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.Bookmarks;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.UIHints;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Attributes;
|
||||
|
|
@ -208,7 +207,6 @@ public class HttpEndpoint : Trigger<HttpRequest>
|
|||
// Read route data, if any.
|
||||
var path = context.GetWorkflowInput<PathString>(RequestPathInputKey);
|
||||
var routeData = GetRouteData(httpContext, path);
|
||||
|
||||
var routeDictionary = routeData.Values.ToDictionary(route => route.Key, route => route.Value!);
|
||||
var queryStringDictionary = httpContext.Request.Query.ToObjectDictionary();
|
||||
var headersDictionary = httpContext.Request.Headers.ToObjectDictionary();
|
||||
|
|
@ -499,7 +497,7 @@ public class HttpEndpoint : Trigger<HttpRequest>
|
|||
|
||||
var matchingRouteQuery =
|
||||
from route in routeTable
|
||||
let routeValues = routeMatcher.Match(route, path)
|
||||
let routeValues = routeMatcher.Match(route.Route, path)
|
||||
where routeValues != null
|
||||
select new { route, routeValues };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Attributes;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Elsa.Workflows.Attributes;
|
|||
using Elsa.Workflows.UIHints;
|
||||
using Elsa.Workflows.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using HttpHeaders = Elsa.Http.Models.HttpHeaders;
|
||||
|
||||
namespace Elsa.Http;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System.Security.Cryptography;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Exceptions;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.Http.Services;
|
||||
using Elsa.Workflows;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using System.Net;
|
|||
using System.Runtime.CompilerServices;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.UIHints;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Attributes;
|
||||
|
|
@ -72,7 +71,6 @@ public class WriteHttpResponse : Activity
|
|||
{
|
||||
// We're executing in a non-HTTP context (e.g. in a virtual actor).
|
||||
// Create a bookmark to allow the invoker to export the state and resume execution from there.
|
||||
|
||||
context.CreateBookmark(OnResumeAsync, BookmarkMetadata.HttpCrossBoundary);
|
||||
return;
|
||||
}
|
||||
|
|
@ -135,11 +133,11 @@ public class WriteHttpResponse : Activity
|
|||
await response.WriteAsync("The response includes a type that cannot be serialized.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the configuration is set to flush immediatly the response to the caller.
|
||||
var options = context.GetRequiredService<IOptions<HttpActivityOptions>>();
|
||||
if (options.Value.WriteHttpResponseSynchronously)
|
||||
}
|
||||
|
||||
// Check if the configuration is set to flush immediatly the response to the caller.
|
||||
var options = context.GetRequiredService<IOptions<HttpActivityOptions>>();
|
||||
if (options.Value.WriteHttpResponseSynchronously)
|
||||
await response.CompleteAsync();
|
||||
|
||||
// Complete activity.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Options;
|
||||
|
||||
namespace Elsa.Http.Contexts;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
using Elsa.Http.Bookmarks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Http.Contexts;
|
||||
|
||||
[UsedImplicitly]
|
||||
public record HttpEndpointRouteProviderContext(HttpEndpointBookmarkPayload Payload, string? TenantId, CancellationToken CancellationToken);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a way to convert a relative URL to an absolute URL.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides downloadables from the specified content, if supported.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Options;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides downloadables from the specified content, if supported.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using FluentStorage.Blobs;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a provider of a file cache storage.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.Http.Options;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// A general-purpose downloader of files from a given URL.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.Http.Contexts;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// A strategy that reads a <see cref="HttpResponseMessage"/> of a given content type.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a way to select the correlation ID for a request.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// A handler that is invoked when authorizing an inbound HTTP request.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Implement this to control what to return to the client in case an unhandled exception occurs while executing the workflow.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
using Elsa.Http.Contexts;
|
||||
|
||||
namespace Elsa.Http;
|
||||
|
||||
public interface IHttpEndpointRoutesProvider
|
||||
{
|
||||
Task<IEnumerable<HttpRouteData>> GetRoutesAsync(HttpEndpointRouteProviderContext context);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a way to select the workflow instance ID for a request.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a service that looks up HTTP workflows and triggers.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.Caching;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a service that caches HTTP workflows and triggers.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Matches a given request path against the specified route template.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
namespace Elsa.Http.Contracts;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of all routes provided by <see cref="HttpEndpoint"/> activities.
|
||||
/// </summary>
|
||||
public interface IRouteTable : IEnumerable<string>
|
||||
public interface IRouteTable : IEnumerable<HttpRouteData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a route to the table.
|
||||
|
|
@ -11,6 +11,12 @@ public interface IRouteTable : IEnumerable<string>
|
|||
/// <param name="route">The route to add.</param>
|
||||
void Add(string route);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a route to the table.
|
||||
/// </summary>
|
||||
/// <param name="httpRouteData">The route to add.</param>
|
||||
void Add(HttpRouteData httpRouteData);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a route from the table.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
namespace Elsa.Http.Contracts;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the route table based on current workflow triggers and bookmarks.
|
||||
|
|
@ -6,8 +10,42 @@ namespace Elsa.Http.Contracts;
|
|||
public interface IRouteTableUpdater
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the route table.
|
||||
/// Updates the route table based on current workflow triggers and bookmarks.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task UpdateAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds routes to the route table based on the specified triggers.
|
||||
/// </summary>
|
||||
/// <param name="triggers">The triggers to create routes for.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task AddRoutesAsync(IEnumerable<StoredTrigger> triggers, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds routes to the route table based on the specified bookmarks.
|
||||
/// </summary>
|
||||
/// <param name="bookmarks">The bookmarks to create routes for.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task AddRoutesAsync(IEnumerable<StoredBookmark> bookmarks, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds routes to the route table based on the specified bookmarks.
|
||||
/// </summary>
|
||||
/// <param name="bookmarks">The bookmarks to create routes for.</param>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task AddRoutesAsync(IEnumerable<Bookmark> bookmarks, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Removes routes from the route table based on the specified triggers.
|
||||
/// </summary>
|
||||
/// <param name="triggers">The triggers to remove routes for.</param>
|
||||
void RemoveRoutes(IEnumerable<StoredTrigger> triggers);
|
||||
|
||||
/// <summary>
|
||||
/// Removes routes from the route table based on the specified bookmarks.
|
||||
/// </summary>
|
||||
/// <param name="bookmarks">The bookmarks to remove routes for.</param>
|
||||
void RemoveRoutes(IEnumerable<Bookmark> bookmarks);
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Collections;
|
||||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Text;
|
||||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.DownloadableContentHandlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using Elsa.Http.Abstractions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Options;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
<ProjectReference Include="..\Elsa.Liquid\Elsa.Liquid.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Runtime.ProtoActor\Elsa.Workflows.Runtime.ProtoActor.csproj" />
|
||||
<ProjectReference Include="..\Elsa.SasTokens\Elsa.SasTokens.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Tenants\Elsa.Tenants.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Core\Elsa.Workflows.Core.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Runtime\Elsa.Workflows.Runtime.csproj" />
|
||||
<ProjectReference Include="..\Elsa.JavaScript\Elsa.JavaScript.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Chttpendpoint/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Chttptrigger/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=constants/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=constants/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=contracts/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.SasTokens.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Elsa.Http;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Models;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
using Elsa.Http;
|
||||
using Elsa.Http.Bookmarks;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Workflows.Helpers;
|
||||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Adds extensions to <see cref="IRouteTable"/>.
|
||||
/// </summary>
|
||||
public static class RouteTableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds routes from the specified set of triggers.
|
||||
/// </summary>
|
||||
public static void AddRoutes(this IRouteTable routeTable, IEnumerable<StoredTrigger> triggers)
|
||||
{
|
||||
var paths = Filter(triggers).Select(x => x.GetPayload<HttpEndpointBookmarkPayload>().Path).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
||||
routeTable.AddRange(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds routes from the specified set of bookmarks.
|
||||
/// </summary>
|
||||
public static void AddRoutes(this IRouteTable routeTable, IEnumerable<StoredBookmark> bookmarks)
|
||||
{
|
||||
var paths = Filter(bookmarks).Select(x => x.GetPayload<HttpEndpointBookmarkPayload>().Path).ToList();
|
||||
routeTable.AddRange(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds routes from the specified set of bookmarks.
|
||||
/// </summary>
|
||||
public static void AddRoutes(this IRouteTable routeTable, IEnumerable<Bookmark> bookmarks)
|
||||
{
|
||||
var paths = Filter(bookmarks).Select(x => x.GetPayload<HttpEndpointBookmarkPayload>().Path).ToList();
|
||||
routeTable.AddRange(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes routes from the specified set of triggers.
|
||||
/// </summary>
|
||||
public static void RemoveRoutes(this IRouteTable routeTable, IEnumerable<StoredTrigger> triggers)
|
||||
{
|
||||
var paths = Filter(triggers).Select(x => x.GetPayload<HttpEndpointBookmarkPayload>().Path).ToList();
|
||||
routeTable.RemoveRange(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes routes from the specified set of bookmarks.
|
||||
/// </summary>
|
||||
public static void RemoveRoutes(this IRouteTable routeTable, IEnumerable<Bookmark> bookmarks)
|
||||
{
|
||||
var paths = Filter(bookmarks).Select(x => x.GetPayload<HttpEndpointBookmarkPayload>().Path).ToList();
|
||||
routeTable.RemoveRange(paths);
|
||||
}
|
||||
|
||||
private static IEnumerable<StoredTrigger> Filter(IEnumerable<StoredTrigger> triggers)
|
||||
{
|
||||
var triggerName = ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
return triggers.Where(x => x.Name == triggerName && x.Payload != null);
|
||||
}
|
||||
|
||||
private static IEnumerable<StoredBookmark> Filter(IEnumerable<StoredBookmark> bookmarks)
|
||||
{
|
||||
var activityTypeName = ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
return bookmarks.Where(x => x.ActivityTypeName == activityTypeName && x.Payload != null);
|
||||
}
|
||||
|
||||
private static IEnumerable<Bookmark> Filter(IEnumerable<Bookmark> bookmarks)
|
||||
{
|
||||
var bookmarkName = ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
return bookmarks.Where(x => x.Name == bookmarkName && x.Payload != null);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
|
|||
11
src/modules/Elsa.Http/Extensions/StringArrayExtensions.cs
Normal file
11
src/modules/Elsa.Http/Extensions/StringArrayExtensions.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
public static class StringArrayExtensions
|
||||
{
|
||||
public static string JoinSegments(this IEnumerable<string?> segments, string separator = "/")
|
||||
{
|
||||
return string.Join(separator, segments.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x!.Trim('/')));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -20,4 +21,4 @@ public static class StringValueExtensions
|
|||
item.Value[0]!
|
||||
: item.Value.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Handlers;
|
||||
using Elsa.Http.Services;
|
||||
using Elsa.Workflows.Management.Features;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
using Elsa.Common.Multitenancy;
|
||||
using Elsa.Expressions.Options;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.DownloadableContentHandlers;
|
||||
using Elsa.Http.FileCaches;
|
||||
using Elsa.Http.Handlers;
|
||||
using Elsa.Http.HostedServices;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Multitenancy;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.Http.Parsers;
|
||||
using Elsa.Http.PortResolvers;
|
||||
|
|
@ -23,7 +19,6 @@ using Elsa.Workflows.Management.Requests;
|
|||
using Elsa.Workflows.Management.Responses;
|
||||
using FluentStorage;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -34,12 +29,9 @@ namespace Elsa.Http.Features;
|
|||
/// Installs services related to HTTP services and activities.
|
||||
/// </summary>
|
||||
[DependsOn(typeof(HttpJavaScriptFeature))]
|
||||
public class HttpFeature : FeatureBase
|
||||
public class HttpFeature(IModule module) : FeatureBase(module)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public HttpFeature(IModule module) : base(module)
|
||||
{
|
||||
}
|
||||
private Func<IServiceProvider, IHttpEndpointRoutesProvider> _httpEndpointRouteProvider = sp => sp.GetRequiredService<DefaultHttpEndpointRoutesProvider>();
|
||||
|
||||
/// <summary>
|
||||
/// A delegate to configure <see cref="HttpActivityOptions"/>.
|
||||
|
|
@ -104,14 +96,24 @@ public class HttpFeature : FeatureBase
|
|||
typeof(QueryStringHttpWorkflowInstanceIdSelector)
|
||||
};
|
||||
|
||||
public HttpFeature WithHttpEndpointRoutesProvider<T>() where T : IHttpEndpointRoutesProvider
|
||||
{
|
||||
return WithHttpEndpointRoutesProvider(sp => sp.GetRequiredService<T>());
|
||||
}
|
||||
|
||||
public HttpFeature WithHttpEndpointRoutesProvider(Func<IServiceProvider, IHttpEndpointRoutesProvider> httpEndpointRouteProvider)
|
||||
{
|
||||
_httpEndpointRouteProvider = httpEndpointRouteProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Module.UseWorkflowManagement(management =>
|
||||
{
|
||||
management.AddVariableTypes(new[]
|
||||
{
|
||||
typeof(RouteData),
|
||||
management.AddVariableTypes([
|
||||
typeof(HttpRouteData),
|
||||
typeof(HttpRequest),
|
||||
typeof(HttpResponse),
|
||||
typeof(HttpResponseMessage),
|
||||
|
|
@ -119,7 +121,7 @@ public class HttpFeature : FeatureBase
|
|||
typeof(IFormFile),
|
||||
typeof(HttpFile),
|
||||
typeof(Downloadable)
|
||||
}, "HTTP");
|
||||
], "HTTP");
|
||||
|
||||
management.AddActivitiesFrom<HttpFeature>();
|
||||
});
|
||||
|
|
@ -184,8 +186,10 @@ public class HttpFeature : FeatureBase
|
|||
.AddScoped<AuthenticationBasedHttpEndpointAuthorizationHandler>()
|
||||
.AddScoped<AllowAnonymousHttpEndpointAuthorizationHandler>()
|
||||
.AddScoped<DefaultHttpEndpointFaultHandler>()
|
||||
.AddScoped<DefaultHttpEndpointRoutesProvider>()
|
||||
.AddScoped(HttpEndpointWorkflowFaultHandler)
|
||||
.AddScoped(HttpEndpointAuthorizationHandler)
|
||||
.AddScoped(_httpEndpointRouteProvider)
|
||||
|
||||
// Downloadable content handlers.
|
||||
.AddScoped<IDownloadableManager, DefaultDownloadableManager>()
|
||||
|
|
@ -208,9 +212,6 @@ public class HttpFeature : FeatureBase
|
|||
|
||||
// HTTP clients.
|
||||
Services.AddHttpClient<IFileDownloader, HttpClientFileDownloader>();
|
||||
|
||||
// Tenant resolvers.
|
||||
Services.AddScoped<ITenantResolver, RoutePrefixTenantResolver>();
|
||||
|
||||
// Add selectors.
|
||||
foreach (var httpCorrelationIdSelectorType in HttpCorrelationIdSelectorTypes)
|
||||
|
|
@ -225,7 +226,7 @@ public class HttpFeature : FeatureBase
|
|||
options.AddTypeAlias<HttpResponse>("HttpResponse");
|
||||
options.AddTypeAlias<HttpResponseMessage>("HttpResponseMessage");
|
||||
options.AddTypeAlias<HttpHeaders>("HttpHeaders");
|
||||
options.AddTypeAlias<RouteData>("RouteData");
|
||||
options.AddTypeAlias<HttpRouteData>("RouteData");
|
||||
options.AddTypeAlias<IFormFile>("FormFile");
|
||||
options.AddTypeAlias<IFormFile[]>("FormFile[]");
|
||||
options.AddTypeAlias<HttpFile>("HttpFile");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using FluentStorage.Blobs;
|
||||
|
||||
namespace Elsa.Http.FileCaches;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Handlers;
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Http.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Exceptions;
|
||||
|
||||
namespace Elsa.Http.Handlers;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using System.Net.Mime;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Workflows;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Http.Bookmarks;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Workflows.Management.Entities;
|
||||
using Elsa.Workflows.Management.Notifications;
|
||||
|
|
|
|||
|
|
@ -1,38 +1,31 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Workflows.Runtime.Notifications;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Http.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// A handler that updates the route table when workflow triggers and bookmarks are indexed.
|
||||
/// </summary>
|
||||
public class UpdateRouteTable :
|
||||
[UsedImplicitly]
|
||||
public class UpdateRouteTable(IRouteTableUpdater routeTableUpdater, IOptions<HttpActivityOptions> options) :
|
||||
INotificationHandler<WorkflowTriggersIndexed>,
|
||||
INotificationHandler<WorkflowBookmarksIndexed>
|
||||
{
|
||||
private readonly IRouteTable _routeTable;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpdateRouteTable"/> class.
|
||||
/// </summary>
|
||||
public UpdateRouteTable(IRouteTable routeTable) => _routeTable = routeTable;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task HandleAsync(WorkflowTriggersIndexed notification, CancellationToken cancellationToken)
|
||||
public async Task HandleAsync(WorkflowTriggersIndexed notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_routeTable.RemoveRoutes(notification.IndexedWorkflowTriggers.RemovedTriggers);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowTriggers.AddedTriggers);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowTriggers.UnchangedTriggers);
|
||||
return Task.CompletedTask;
|
||||
routeTableUpdater.RemoveRoutes(notification.IndexedWorkflowTriggers.RemovedTriggers);
|
||||
await routeTableUpdater.AddRoutesAsync(notification.IndexedWorkflowTriggers.AddedTriggers, cancellationToken);
|
||||
await routeTableUpdater.AddRoutesAsync(notification.IndexedWorkflowTriggers.UnchangedTriggers, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task HandleAsync(WorkflowBookmarksIndexed notification, CancellationToken cancellationToken)
|
||||
public async Task HandleAsync(WorkflowBookmarksIndexed notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_routeTable.RemoveRoutes(notification.IndexedWorkflowBookmarks.RemovedBookmarks);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowBookmarks.AddedBookmarks);
|
||||
return Task.CompletedTask;
|
||||
routeTableUpdater.RemoveRoutes(notification.IndexedWorkflowBookmarks.RemovedBookmarks);
|
||||
await routeTableUpdater.AddRoutesAsync(notification.IndexedWorkflowBookmarks.AddedBookmarks, notification.IndexedWorkflowBookmarks.WorkflowExecutionContext, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Http.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Elsa.Http.HostedServices;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Http.Bookmarks;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using JetBrains.Annotations;
|
||||
|
|
@ -17,8 +15,6 @@ using Elsa.Workflows.Runtime.Entities;
|
|||
using FastEndpoints;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Elsa.Common.Multitenancy;
|
||||
using Elsa.Tenants;
|
||||
using Elsa.Tenants.Extensions;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Entities;
|
||||
|
|
@ -33,7 +29,7 @@ namespace Elsa.Http.Middleware;
|
|||
/// An ASP.NET middleware component that tries to match the inbound request path to an associated workflow and then run that workflow.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class HttpWorkflowsMiddleware(RequestDelegate next, IOptions<HttpActivityOptions> options)
|
||||
public class HttpWorkflowsMiddleware(RequestDelegate next, ITenantAccessor tenantAccessor, IOptions<HttpActivityOptions> options)
|
||||
{
|
||||
private readonly string _activityTypeName = ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
|
||||
|
|
@ -59,7 +55,7 @@ public class HttpWorkflowsMiddleware(RequestDelegate next, IOptions<HttpActivity
|
|||
path = path[basePath.Length..];
|
||||
}
|
||||
|
||||
var matchingPath = GetMatchingRoute(serviceProvider, path);
|
||||
var matchingPath = GetMatchingRoute(serviceProvider, path).Route;
|
||||
var input = new Dictionary<string, object>
|
||||
{
|
||||
[HttpEndpoint.HttpContextInputKey] = true,
|
||||
|
|
@ -252,23 +248,23 @@ public class HttpWorkflowsMiddleware(RequestDelegate next, IOptions<HttpActivity
|
|||
return result;
|
||||
}
|
||||
|
||||
private string GetMatchingRoute(IServiceProvider serviceProvider, string path)
|
||||
private HttpRouteData GetMatchingRoute(IServiceProvider serviceProvider, string path)
|
||||
{
|
||||
var routeMatcher = serviceProvider.GetRequiredService<IRouteMatcher>();
|
||||
var routeTable = serviceProvider.GetRequiredService<IRouteTable>();
|
||||
|
||||
var matchingRouteQuery =
|
||||
from route in routeTable
|
||||
let routeValues = routeMatcher.Match(route, path)
|
||||
from routeData in routeTable
|
||||
let routeValues = routeMatcher.Match(routeData.Route, path)
|
||||
where routeValues != null
|
||||
select new
|
||||
{
|
||||
route,
|
||||
route = routeData,
|
||||
routeValues
|
||||
};
|
||||
|
||||
var matchingRoute = matchingRouteQuery.FirstOrDefault();
|
||||
var routeTemplate = matchingRoute?.route ?? path;
|
||||
var routeTemplate = matchingRoute?.route ?? new HttpRouteData(path);
|
||||
|
||||
return routeTemplate;
|
||||
}
|
||||
|
|
@ -366,7 +362,7 @@ public class HttpWorkflowsMiddleware(RequestDelegate next, IOptions<HttpActivity
|
|||
{
|
||||
var httpEndpointAuthorizationHandler = serviceProvider.GetRequiredService<IHttpEndpointAuthorizationHandler>();
|
||||
|
||||
if (bookmarkPayload.Authorize ?? false)
|
||||
if (bookmarkPayload.Authorize == false)
|
||||
return true;
|
||||
|
||||
return await httpEndpointAuthorizationHandler.AuthorizeAsync(new AuthorizeHttpEndpointContext(httpContext, workflow, bookmarkPayload.Policy));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Elsa.Workflows.Activities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the context for authorizing an HTTP endpoint.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a downloadable object.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the payload of an event, serialized as a secured token.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Elsa.Workflows.State;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Provides context about the faulted workflow.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Net.Http.Headers;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a downloadable object.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Http.Serialization;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the headers of an HTTP message.
|
||||
|
|
|
|||
31
src/modules/Elsa.Http/Models/HttpRouteData.cs
Normal file
31
src/modules/Elsa.Http/Models/HttpRouteData.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Elsa.Http;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class HttpRouteData
|
||||
{
|
||||
public HttpRouteData()
|
||||
{
|
||||
}
|
||||
|
||||
public HttpRouteData(string route) : this()
|
||||
{
|
||||
Route = route;
|
||||
}
|
||||
|
||||
public HttpRouteData(string route, RouteValueDictionary dataTokens) : this(route)
|
||||
{
|
||||
DataTokens = dataTokens;
|
||||
}
|
||||
|
||||
public HttpRouteData(string route, RouteValueDictionary dataTokens, RouteValueDictionary routeValues) : this(route, dataTokens)
|
||||
{
|
||||
RouteValues = routeValues;
|
||||
}
|
||||
|
||||
public string Route { get; set; } = default!;
|
||||
public RouteValueDictionary DataTokens { get; set; } = new();
|
||||
public RouteValueDictionary RouteValues { get; set; } = new();
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using Elsa.Workflows;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// A binding between an HTTP status code and an activity.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Elsa.Workflows.Models;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
|
||||
namespace Elsa.Http.Models;
|
||||
namespace Elsa.Http;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of a workflow lookup.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.Models;
|
||||
|
||||
namespace Elsa.Http.Parsers;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Text.Json;
|
|||
using System.Text.Json.Serialization;
|
||||
using Elsa.Expressions.Helpers;
|
||||
using Elsa.Http.Contexts;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Workflows.Serialization.Converters;
|
||||
|
||||
namespace Elsa.Http.Parsers;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue