< Summary

Information
Class: Elsa.Http.Features.HttpFeature
Assembly: Elsa.Http
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Http/Features/HttpFeature.cs
Line coverage
93%
Covered lines: 144
Uncovered lines: 10
Coverable lines: 154
Total lines: 269
Line coverage: 93.5%
Branch coverage
66%
Covered branches: 8
Total branches: 12
Branch coverage: 66.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Http/Features/HttpFeature.cs

#LineLine coverage
 1using System.Net;
 2using Elsa.Extensions;
 3using Elsa.Features.Abstractions;
 4using Elsa.Features.Attributes;
 5using Elsa.Features.Services;
 6using Elsa.Http.Bookmarks;
 7using Elsa.Http.ContentWriters;
 8using Elsa.Http.DownloadableContentHandlers;
 9using Elsa.Http.FileCaches;
 10using Elsa.Http.Handlers;
 11using Elsa.Http.Options;
 12using Elsa.Http.Parsers;
 13using Elsa.Http.PortResolvers;
 14using Elsa.Http.Resilience;
 15using Elsa.Http.Selectors;
 16using Elsa.Http.Services;
 17using Elsa.Http.Tasks;
 18using Elsa.Http.TriggerPayloadValidators;
 19using Elsa.Http.UIHints;
 20using Elsa.Resilience.Extensions;
 21using Elsa.Resilience.Features;
 22using Elsa.Workflows;
 23using Elsa.Workflows.Options;
 24using FluentStorage;
 25using Microsoft.AspNetCore.Http;
 26using Microsoft.AspNetCore.StaticFiles;
 27using Microsoft.Extensions.DependencyInjection;
 28using Microsoft.Extensions.DependencyInjection.Extensions;
 29using Microsoft.Extensions.Options;
 30using Elsa.Common.Serialization;
 31
 32namespace Elsa.Http.Features;
 33
 34/// <summary>
 35/// Installs services related to HTTP services and activities.
 36/// </summary>
 37[DependsOn(typeof(HttpJavaScriptFeature))]
 38[DependsOn(typeof(ResilienceFeature))]
 1139public class HttpFeature(IModule module) : FeatureBase(module)
 40{
 41841    private Func<IServiceProvider, IHttpEndpointRoutesProvider> _httpEndpointRouteProvider = sp => sp.GetRequiredService
 114842    private Func<IServiceProvider, IHttpEndpointBasePathProvider> _httpEndpointBasePathProvider = sp => sp.GetRequiredSe
 43
 44    /// <summary>
 45    /// A delegate to configure <see cref="HttpActivityOptions"/>.
 46    /// </summary>
 1447    public Action<HttpActivityOptions>? ConfigureHttpOptions { get; set; }
 48
 49    /// <summary>
 50    /// A delegate to configure <see cref="HttpFileCacheOptions"/>.
 51    /// </summary>
 1152    public Action<HttpFileCacheOptions>? ConfigureHttpFileCacheOptions { get; set; }
 53
 54    /// <summary>
 55    /// A delegate that is invoked when authorizing an inbound HTTP request.
 56    /// </summary>
 28257    public Func<IServiceProvider, IHttpEndpointAuthorizationHandler> HttpEndpointAuthorizationHandler { get; set; } = sp
 58
 59    /// <summary>
 60    /// A delegate that is invoked when an HTTP workflow faults.
 61    /// </summary>
 2262    public Func<IServiceProvider, IHttpEndpointFaultHandler> HttpEndpointWorkflowFaultHandler { get; set; } = sp => sp.G
 63
 64    /// <summary>
 65    /// A delegate to configure the <see cref="IContentTypeProvider"/>.
 66    /// </summary>
 2267    public Func<IServiceProvider, IContentTypeProvider> ContentTypeProvider { get; set; } = _ => new FileExtensionConten
 68
 69    /// <summary>
 70    /// A delegate to configure the <see cref="IFileCacheStorageProvider"/>.
 71    /// </summary>
 2272    public Func<IServiceProvider, IFileCacheStorageProvider> FileCache { get; set; } = sp =>
 1173    {
 074        var options = sp.GetRequiredService<IOptions<HttpFileCacheOptions>>().Value;
 075        var blobStorage = StorageFactory.Blobs.DirectoryFiles(options.LocalCacheDirectory);
 076        return new BlobFileCacheStorageProvider(blobStorage);
 1177    };
 78
 79    /// <summary>
 80    /// A delegate to configure the <see cref="HttpClient"/> used when by the <see cref="FlowSendHttpRequest"/> and <see
 81    /// </summary>
 2382    public Action<IServiceProvider, HttpClient> HttpClient { get; set; } = (_, _) => { };
 83
 84    /// <summary>
 85    /// A delegate to configure the <see cref="HttpClientBuilder"/> for <see cref="HttpClient"/>.
 86    /// </summary>
 3387    public Action<IHttpClientBuilder> HttpClientBuilder { get; set; } = _ => { };
 88
 89    /// <summary>
 90    /// A list of <see cref="IHttpCorrelationIdSelector"/> types to register with the service collection.
 91    /// </summary>
 2292    public ICollection<Type> HttpCorrelationIdSelectorTypes { get; } = new List<Type>
 1193    {
 1194        typeof(HeaderHttpCorrelationIdSelector),
 1195        typeof(QueryStringHttpCorrelationIdSelector)
 1196    };
 97
 98    /// <summary>
 99    /// A list of <see cref="IHttpWorkflowInstanceIdSelector"/> types to register with the service collection.
 100    /// </summary>
 22101    public ICollection<Type> HttpWorkflowInstanceIdSelectorTypes { get; } = new List<Type>
 11102    {
 11103        typeof(HeaderHttpWorkflowInstanceIdSelector),
 11104        typeof(QueryStringHttpWorkflowInstanceIdSelector)
 11105    };
 106
 107    public HttpFeature WithHttpEndpointRoutesProvider<T>() where T : IHttpEndpointRoutesProvider
 108    {
 0109        return WithHttpEndpointRoutesProvider(sp => sp.GetRequiredService<T>());
 110    }
 111
 112    public HttpFeature WithHttpEndpointRoutesProvider(Func<IServiceProvider, IHttpEndpointRoutesProvider> httpEndpointRo
 113    {
 0114        _httpEndpointRouteProvider = httpEndpointRouteProvider;
 0115        return this;
 116    }
 117
 118    public HttpFeature WithHttpEndpointBasePathProvider<T>() where T : class, IHttpEndpointBasePathProvider
 119    {
 0120        Services.TryAddScoped<T>();
 0121        return WithHttpEndpointBasePathProvider(sp => sp.GetRequiredService<T>());
 122    }
 123
 124    public HttpFeature WithHttpEndpointBasePathProvider(Func<IServiceProvider, IHttpEndpointBasePathProvider> httpEndpoi
 125    {
 0126        _httpEndpointBasePathProvider = httpEndpointBasePathProvider;
 0127        return this;
 128    }
 129
 130    /// <inheritdoc />
 131    public override void Configure()
 132    {
 11133        Module.UseWorkflowManagement(management =>
 11134        {
 11135            management.AddVariableTypes([
 11136                typeof(HttpRouteData),
 11137                typeof(HttpRequest),
 11138                typeof(HttpResponse),
 11139                typeof(HttpResponseMessage),
 11140                typeof(HttpHeaders),
 11141                typeof(IFormFile),
 11142                typeof(HttpFile),
 11143                typeof(Downloadable)
 11144            ], "HTTP");
 11145
 11146            management.AddActivitiesFrom<HttpFeature>();
 22147        });
 148
 22149        Module.UseResilience(resilience => resilience.AddResilienceStrategyType<HttpResilienceStrategy>());
 11150    }
 151
 152    /// <inheritdoc />
 153    public override void Apply()
 154    {
 11155        var configureOptions = ConfigureHttpOptions ?? (options =>
 11156        {
 7157            options.BasePath = "/workflows";
 7158            options.BaseUrl = new Uri("http://localhost");
 18159        });
 160
 11161        var configureFileCacheOptions = ConfigureHttpFileCacheOptions ?? (options => { options.TimeToLive = TimeSpan.Fro
 162
 11163        Services.Configure(configureOptions);
 11164        Services.Configure(configureFileCacheOptions);
 165
 11166        var httpClientBuilder = Services.AddHttpClient<SendHttpRequestBase>(HttpClient);
 11167        HttpClientBuilder(httpClientBuilder);
 168
 11169        Services
 11170            .AddScoped<IRouteMatcher, RouteMatcher>()
 11171            .AddScoped<IRouteTable, RouteTable>()
 11172            .AddScoped<IAbsoluteUrlProvider, DefaultAbsoluteUrlProvider>()
 11173            .AddScoped<IRouteTableUpdater, DefaultRouteTableUpdater>()
 11174            .AddScoped<IHttpWorkflowLookupService, HttpWorkflowLookupService>()
 11175            .AddScoped(ContentTypeProvider)
 11176            .AddHttpContextAccessor()
 11177
 11178            // Handlers.
 11179            .AddNotificationHandler<UpdateRouteTable>()
 11180
 11181            // Graceful shutdown: register HTTP ingress for diagnostic visibility in the runtime's IIngressSourceRegistr
 11182            // The middleware short-circuits to 503 when paused (FR-006).
 11183            .AddSingleton<Elsa.Workflows.Runtime.IIngressSource, Elsa.Http.IngressSources.HttpTriggerIngressSource>()
 11184
 11185            // Content parsers.
 11186            .AddSingleton<IHttpContentParser, JsonHttpContentParser>()
 11187            .AddSingleton<IHttpContentParser, XmlHttpContentParser>()
 11188            .AddSingleton<IHttpContentParser, PlainTextHttpContentParser>()
 11189            .AddSingleton<IHttpContentParser, TextHtmlHttpContentParser>()
 11190            .AddSingleton<IHttpContentParser, FileHttpContentParser>()
 11191
 11192            // HTTP content factories.
 11193            .AddScoped<IHttpContentFactory, TextContentFactory>()
 11194            .AddScoped<IHttpContentFactory, JsonContentFactory>()
 11195            .AddScoped<IHttpContentFactory, XmlContentFactory>()
 11196            .AddScoped<IHttpContentFactory, FormUrlEncodedHttpContentFactory>()
 11197
 11198            // Activity property options providers.
 11199            .AddScoped<IPropertyUIHandler, HttpContentTypeOptionsProvider>()
 11200            .AddScoped<IPropertyUIHandler, HttpEndpointPathUIHandler>()
 11201            .AddScoped(_httpEndpointBasePathProvider)
 11202
 11203            // Port resolvers.
 11204            .AddScoped<IActivityResolver, SendHttpRequestActivityResolver>()
 11205
 11206            // HTTP endpoint handlers.
 11207            .AddScoped<AuthenticationBasedHttpEndpointAuthorizationHandler>()
 11208            .AddScoped<AllowAnonymousHttpEndpointAuthorizationHandler>()
 11209            .AddScoped<DefaultHttpEndpointFaultHandler>()
 11210            .AddScoped<DefaultHttpEndpointRoutesProvider>()
 11211            .AddScoped<DefaultHttpEndpointBasePathProvider>()
 11212            .AddScoped(HttpEndpointWorkflowFaultHandler)
 11213            .AddScoped(HttpEndpointAuthorizationHandler)
 11214            .AddScoped(_httpEndpointRouteProvider)
 11215
 11216            // Startup tasks.
 11217            .AddStartupTask<UpdateRouteTableStartupTask>()
 11218
 11219            // Downloadable content handlers.
 11220            .AddScoped<IDownloadableManager, DefaultDownloadableManager>()
 11221            .AddScoped<IDownloadableContentHandler, MultiDownloadableContentHandler>()
 11222            .AddScoped<IDownloadableContentHandler, BinaryDownloadableContentHandler>()
 11223            .AddScoped<IDownloadableContentHandler, StreamDownloadableContentHandler>()
 11224            .AddScoped<IDownloadableContentHandler, FormFileDownloadableContentHandler>()
 11225            .AddScoped<IDownloadableContentHandler, DownloadableDownloadableContentHandler>()
 11226            .AddScoped<IDownloadableContentHandler, UrlDownloadableContentHandler>()
 11227            .AddScoped<IDownloadableContentHandler, StringDownloadableContentHandler>()
 11228            .AddScoped<IDownloadableContentHandler, HttpFileDownloadableContentHandler>()
 11229
 11230            //Trigger payload validators.
 11231            .AddTriggerPayloadValidator<HttpEndpointTriggerPayloadValidator, HttpEndpointBookmarkPayload>()
 11232
 11233            // File caches.
 11234            .AddScoped(FileCache)
 11235            .AddScoped<ZipManager>()
 11236
 11237            // AuthenticationBasedHttpEndpointAuthorizationHandler requires Authorization services.
 11238            // We could consider creating a separate module for installing authorization services.
 11239            .AddAuthorization();
 240
 241        // HTTP clients.
 11242        Services.AddHttpClient<IFileDownloader, HttpClientFileDownloader>();
 243
 244        // Add selectors.
 66245        foreach (var httpCorrelationIdSelectorType in HttpCorrelationIdSelectorTypes)
 22246            Services.AddScoped(typeof(IHttpCorrelationIdSelector), httpCorrelationIdSelectorType);
 247
 66248        foreach (var httpWorkflowInstanceIdSelectorType in HttpWorkflowInstanceIdSelectorTypes)
 22249            Services.AddScoped(typeof(IHttpWorkflowInstanceIdSelector), httpWorkflowInstanceIdSelectorType);
 250
 11251        Services.Configure<SerializationTypeOptions>(options =>
 11252        {
 10253            options.RegisterTypeAlias(typeof(HttpRequest), "HttpRequest");
 10254            options.RegisterTypeAlias(typeof(HttpResponse), "HttpResponse");
 10255            options.RegisterTypeAlias(typeof(HttpResponseMessage), "HttpResponseMessage");
 10256            options.RegisterTypeAlias(typeof(HttpHeaders), "HttpHeaders");
 10257            options.RegisterTypeAlias(typeof(HttpRouteData), "RouteData");
 10258            options.RegisterTypeAlias(typeof(IFormFile), "FormFile");
 10259            options.RegisterTypeAlias(typeof(IFormFile[]), "FormFile[]");
 10260            options.RegisterTypeAlias(typeof(HttpFile), "HttpFile");
 10261            options.RegisterTypeAlias(typeof(HttpFile[]), "HttpFile[]");
 10262            options.RegisterTypeAlias(typeof(Downloadable), "Downloadable");
 10263            options.RegisterTypeAlias(typeof(Downloadable[]), "Downloadable[]");
 10264            options.RegisterTypeAlias(typeof(HttpStatusCode), nameof(HttpStatusCode));
 10265            options.RegisterTypeAlias(typeof(HttpRequestException), nameof(HttpRequestException));
 10266            options.RegisterTypeAlias(typeof(HttpEndpointBookmarkPayload), nameof(HttpEndpointBookmarkPayload));
 21267        });
 11268    }
 269}