< 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))]
 739public class HttpFeature(IModule module) : FeatureBase(module)
 40{
 40641    private Func<IServiceProvider, IHttpEndpointRoutesProvider> _httpEndpointRouteProvider = sp => sp.GetRequiredService
 501742    private Func<IServiceProvider, IHttpEndpointBasePathProvider> _httpEndpointBasePathProvider = sp => sp.GetRequiredSe
 43
 44    /// <summary>
 45    /// A delegate to configure <see cref="HttpActivityOptions"/>.
 46    /// </summary>
 1047    public Action<HttpActivityOptions>? ConfigureHttpOptions { get; set; }
 48
 49    /// <summary>
 50    /// A delegate to configure <see cref="HttpFileCacheOptions"/>.
 51    /// </summary>
 752    public Action<HttpFileCacheOptions>? ConfigureHttpFileCacheOptions { get; set; }
 53
 54    /// <summary>
 55    /// A delegate that is invoked when authorizing an inbound HTTP request.
 56    /// </summary>
 27457    public Func<IServiceProvider, IHttpEndpointAuthorizationHandler> HttpEndpointAuthorizationHandler { get; set; } = sp
 58
 59    /// <summary>
 60    /// A delegate that is invoked when an HTTP workflow faults.
 61    /// </summary>
 1462    public Func<IServiceProvider, IHttpEndpointFaultHandler> HttpEndpointWorkflowFaultHandler { get; set; } = sp => sp.G
 63
 64    /// <summary>
 65    /// A delegate to configure the <see cref="IContentTypeProvider"/>.
 66    /// </summary>
 1467    public Func<IServiceProvider, IContentTypeProvider> ContentTypeProvider { get; set; } = _ => new FileExtensionConten
 68
 69    /// <summary>
 70    /// A delegate to configure the <see cref="IFileCacheStorageProvider"/>.
 71    /// </summary>
 1472    public Func<IServiceProvider, IFileCacheStorageProvider> FileCache { get; set; } = sp =>
 773    {
 074        var options = sp.GetRequiredService<IOptions<HttpFileCacheOptions>>().Value;
 075        var blobStorage = StorageFactory.Blobs.DirectoryFiles(options.LocalCacheDirectory);
 076        return new BlobFileCacheStorageProvider(blobStorage);
 777    };
 78
 79    /// <summary>
 80    /// A delegate to configure the <see cref="HttpClient"/> used when by the <see cref="FlowSendHttpRequest"/> and <see
 81    /// </summary>
 1582    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>
 2187    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>
 1492    public ICollection<Type> HttpCorrelationIdSelectorTypes { get; } = new List<Type>
 793    {
 794        typeof(HeaderHttpCorrelationIdSelector),
 795        typeof(QueryStringHttpCorrelationIdSelector)
 796    };
 97
 98    /// <summary>
 99    /// A list of <see cref="IHttpWorkflowInstanceIdSelector"/> types to register with the service collection.
 100    /// </summary>
 14101    public ICollection<Type> HttpWorkflowInstanceIdSelectorTypes { get; } = new List<Type>
 7102    {
 7103        typeof(HeaderHttpWorkflowInstanceIdSelector),
 7104        typeof(QueryStringHttpWorkflowInstanceIdSelector)
 7105    };
 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    {
 7133        Module.UseWorkflowManagement(management =>
 7134        {
 7135            management.AddVariableTypes([
 7136                typeof(HttpRouteData),
 7137                typeof(HttpRequest),
 7138                typeof(HttpResponse),
 7139                typeof(HttpResponseMessage),
 7140                typeof(HttpHeaders),
 7141                typeof(IFormFile),
 7142                typeof(HttpFile),
 7143                typeof(Downloadable)
 7144            ], "HTTP");
 7145
 7146            management.AddActivitiesFrom<HttpFeature>();
 14147        });
 148
 14149        Module.UseResilience(resilience => resilience.AddResilienceStrategyType<HttpResilienceStrategy>());
 7150    }
 151
 152    /// <inheritdoc />
 153    public override void Apply()
 154    {
 7155        var configureOptions = ConfigureHttpOptions ?? (options =>
 7156        {
 4157            options.BasePath = "/workflows";
 4158            options.BaseUrl = new Uri("http://localhost");
 11159        });
 160
 7161        var configureFileCacheOptions = ConfigureHttpFileCacheOptions ?? (options => { options.TimeToLive = TimeSpan.Fro
 162
 7163        Services.Configure(configureOptions);
 7164        Services.Configure(configureFileCacheOptions);
 165
 7166        var httpClientBuilder = Services.AddHttpClient<SendHttpRequestBase>(HttpClient);
 7167        HttpClientBuilder(httpClientBuilder);
 168
 7169        Services
 7170            .AddScoped<IRouteMatcher, RouteMatcher>()
 7171            .AddScoped<IRouteTable, RouteTable>()
 7172            .AddScoped<IAbsoluteUrlProvider, DefaultAbsoluteUrlProvider>()
 7173            .AddScoped<IRouteTableUpdater, DefaultRouteTableUpdater>()
 7174            .AddScoped<IHttpWorkflowLookupService, HttpWorkflowLookupService>()
 7175            .AddScoped(ContentTypeProvider)
 7176            .AddHttpContextAccessor()
 7177
 7178            // Handlers.
 7179            .AddNotificationHandler<UpdateRouteTable>()
 7180
 7181            // Graceful shutdown: register HTTP ingress for diagnostic visibility in the runtime's IIngressSourceRegistr
 7182            // The middleware short-circuits to 503 when paused (FR-006).
 7183            .AddSingleton<Elsa.Workflows.Runtime.IIngressSource, Elsa.Http.IngressSources.HttpTriggerIngressSource>()
 7184
 7185            // Content parsers.
 7186            .AddSingleton<IHttpContentParser, JsonHttpContentParser>()
 7187            .AddSingleton<IHttpContentParser, XmlHttpContentParser>()
 7188            .AddSingleton<IHttpContentParser, PlainTextHttpContentParser>()
 7189            .AddSingleton<IHttpContentParser, TextHtmlHttpContentParser>()
 7190            .AddSingleton<IHttpContentParser, FileHttpContentParser>()
 7191
 7192            // HTTP content factories.
 7193            .AddScoped<IHttpContentFactory, TextContentFactory>()
 7194            .AddScoped<IHttpContentFactory, JsonContentFactory>()
 7195            .AddScoped<IHttpContentFactory, XmlContentFactory>()
 7196            .AddScoped<IHttpContentFactory, FormUrlEncodedHttpContentFactory>()
 7197
 7198            // Activity property options providers.
 7199            .AddScoped<IPropertyUIHandler, HttpContentTypeOptionsProvider>()
 7200            .AddScoped<IPropertyUIHandler, HttpEndpointPathUIHandler>()
 7201            .AddScoped(_httpEndpointBasePathProvider)
 7202
 7203            // Port resolvers.
 7204            .AddScoped<IActivityResolver, SendHttpRequestActivityResolver>()
 7205
 7206            // HTTP endpoint handlers.
 7207            .AddScoped<AuthenticationBasedHttpEndpointAuthorizationHandler>()
 7208            .AddScoped<AllowAnonymousHttpEndpointAuthorizationHandler>()
 7209            .AddScoped<DefaultHttpEndpointFaultHandler>()
 7210            .AddScoped<DefaultHttpEndpointRoutesProvider>()
 7211            .AddScoped<DefaultHttpEndpointBasePathProvider>()
 7212            .AddScoped(HttpEndpointWorkflowFaultHandler)
 7213            .AddScoped(HttpEndpointAuthorizationHandler)
 7214            .AddScoped(_httpEndpointRouteProvider)
 7215
 7216            // Startup tasks.
 7217            .AddStartupTask<UpdateRouteTableStartupTask>()
 7218
 7219            // Downloadable content handlers.
 7220            .AddScoped<IDownloadableManager, DefaultDownloadableManager>()
 7221            .AddScoped<IDownloadableContentHandler, MultiDownloadableContentHandler>()
 7222            .AddScoped<IDownloadableContentHandler, BinaryDownloadableContentHandler>()
 7223            .AddScoped<IDownloadableContentHandler, StreamDownloadableContentHandler>()
 7224            .AddScoped<IDownloadableContentHandler, FormFileDownloadableContentHandler>()
 7225            .AddScoped<IDownloadableContentHandler, DownloadableDownloadableContentHandler>()
 7226            .AddScoped<IDownloadableContentHandler, UrlDownloadableContentHandler>()
 7227            .AddScoped<IDownloadableContentHandler, StringDownloadableContentHandler>()
 7228            .AddScoped<IDownloadableContentHandler, HttpFileDownloadableContentHandler>()
 7229
 7230            //Trigger payload validators.
 7231            .AddTriggerPayloadValidator<HttpEndpointTriggerPayloadValidator, HttpEndpointBookmarkPayload>()
 7232
 7233            // File caches.
 7234            .AddScoped(FileCache)
 7235            .AddScoped<ZipManager>()
 7236
 7237            // AuthenticationBasedHttpEndpointAuthorizationHandler requires Authorization services.
 7238            // We could consider creating a separate module for installing authorization services.
 7239            .AddAuthorization();
 240
 241        // HTTP clients.
 7242        Services.AddHttpClient<IFileDownloader, HttpClientFileDownloader>();
 243
 244        // Add selectors.
 42245        foreach (var httpCorrelationIdSelectorType in HttpCorrelationIdSelectorTypes)
 14246            Services.AddScoped(typeof(IHttpCorrelationIdSelector), httpCorrelationIdSelectorType);
 247
 42248        foreach (var httpWorkflowInstanceIdSelectorType in HttpWorkflowInstanceIdSelectorTypes)
 14249            Services.AddScoped(typeof(IHttpWorkflowInstanceIdSelector), httpWorkflowInstanceIdSelectorType);
 250
 7251        Services.Configure<SerializationTypeOptions>(options =>
 7252        {
 7253            options.RegisterTypeAlias(typeof(HttpRequest), "HttpRequest");
 7254            options.RegisterTypeAlias(typeof(HttpResponse), "HttpResponse");
 7255            options.RegisterTypeAlias(typeof(HttpResponseMessage), "HttpResponseMessage");
 7256            options.RegisterTypeAlias(typeof(HttpHeaders), "HttpHeaders");
 7257            options.RegisterTypeAlias(typeof(HttpRouteData), "RouteData");
 7258            options.RegisterTypeAlias(typeof(IFormFile), "FormFile");
 7259            options.RegisterTypeAlias(typeof(IFormFile[]), "FormFile[]");
 7260            options.RegisterTypeAlias(typeof(HttpFile), "HttpFile");
 7261            options.RegisterTypeAlias(typeof(HttpFile[]), "HttpFile[]");
 7262            options.RegisterTypeAlias(typeof(Downloadable), "Downloadable");
 7263            options.RegisterTypeAlias(typeof(Downloadable[]), "Downloadable[]");
 7264            options.RegisterTypeAlias(typeof(HttpStatusCode), nameof(HttpStatusCode));
 7265            options.RegisterTypeAlias(typeof(HttpRequestException), nameof(HttpRequestException));
 7266            options.RegisterTypeAlias(typeof(HttpEndpointBookmarkPayload), nameof(HttpEndpointBookmarkPayload));
 14267        });
 7268    }
 269}