diff --git a/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscourseActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscourseActionHandler.cs index 58f5d296f..0d1bc38ee 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscourseActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscourseActionHandler.cs @@ -68,19 +68,17 @@ public sealed class DiscourseActionHandler : RuleActionHandler ExecuteJobAsync(DiscourseJob job, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) + var httpClient = httpClientFactory.CreateClient("DiscourseAction"); + + var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl) { - using (var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl) - { - Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") - }) - { - request.Headers.TryAddWithoutValidation("Api-Key", job.ApiKey); - request.Headers.TryAddWithoutValidation("Api-Username", job.ApiUserName); - - return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); - } - } + Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") + }; + + request.Headers.TryAddWithoutValidation("Api-Key", job.ApiKey); + request.Headers.TryAddWithoutValidation("Api-Username", job.ApiUserName); + + return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscoursePlugin.cs b/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscoursePlugin.cs index a0c38a8cd..630777e9e 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscoursePlugin.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Discourse/DiscoursePlugin.cs @@ -15,6 +15,8 @@ public sealed class DiscoursePlugin : IPlugin { public void ConfigureServices(IServiceCollection services, IConfiguration config) { + services.AddHttpClient("DiscourseAction"); + services.AddRuleAction(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyActionHandler.cs index 2d00ffa6f..c1ec23a40 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyActionHandler.cs @@ -47,19 +47,14 @@ public sealed class FastlyActionHandler : RuleActionHandler ExecuteJobAsync(FastlyJob job, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) - { - httpClient.Timeout = TimeSpan.FromSeconds(2); + var httpClient = httpClientFactory.CreateClient("FastlyAction"); - var requestUrl = $"https://api.fastly.com/service/{job.FastlyServiceID}/purge/{job.Key}"; + var requestUrl = $"/service/{job.FastlyServiceID}/purge/{job.Key}"; + var request = new HttpRequestMessage(HttpMethod.Post, requestUrl); - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) - { - request.Headers.Add("Fastly-Key", job.FastlyApiKey); + request.Headers.Add("Fastly-Key", job.FastlyApiKey); - return await httpClient.OneWayRequestAsync(request, ct: ct); - } - } + return await httpClient.OneWayRequestAsync(request, ct: ct); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyPlugin.cs b/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyPlugin.cs index 6c8205c6a..ff85f78f4 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyPlugin.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Fastly/FastlyPlugin.cs @@ -15,6 +15,12 @@ public sealed class FastlyPlugin : IPlugin { public void ConfigureServices(IServiceCollection services, IConfiguration config) { + services.AddHttpClient("Fastly", options => + { + options.BaseAddress = new Uri("https://api.fastly.com"); + options.Timeout = TimeSpan.FromSeconds(2); + }); + services.AddRuleAction(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Medium/MediumActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Medium/MediumActionHandler.cs index c1dfa1bee..7ad90bffc 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Medium/MediumActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Medium/MediumActionHandler.cs @@ -80,50 +80,44 @@ public sealed class MediumActionHandler : RuleActionHandler ExecuteJobAsync(MediumJob job, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) - { - httpClient.Timeout = TimeSpan.FromSeconds(4); - httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); - httpClient.DefaultRequestHeaders.Add("Accept-Charset", "utf-8"); - httpClient.DefaultRequestHeaders.Add("User-Agent", "Squidex Headless CMS"); - - string path; + var httpClient = httpClientFactory.CreateClient("MediumAction"); - if (!string.IsNullOrWhiteSpace(job.PublicationId)) - { - path = $"v1/publications/{job.PublicationId}/posts"; - } - else - { - HttpResponseMessage response = null; + string path; - var meRequest = BuildMeRequest(job); - try - { - response = await httpClient.SendAsync(meRequest, ct); + if (!string.IsNullOrWhiteSpace(job.PublicationId)) + { + path = $"/v1/publications/{job.PublicationId}/posts"; + } + else + { + HttpResponseMessage response = null; - var responseString = await response.Content.ReadAsStringAsync(ct); - var responseJson = serializer.Deserialize(responseString); + var meRequest = BuildGetRequest(job, "/v1/me"); + try + { + response = await httpClient.SendAsync(meRequest, ct); - var id = responseJson.Data?.Id; + var responseString = await response.Content.ReadAsStringAsync(ct); + var responseJson = serializer.Deserialize(responseString); - path = $"v1/users/{id}/posts"; - } - catch (Exception ex) - { - var requestDump = DumpFormatter.BuildDump(meRequest, response, ex.ToString()); + var id = responseJson.Data?.Id; - return Result.Failed(ex, requestDump); - } + path = $"/v1/users/{id}/posts"; } + catch (Exception ex) + { + var requestDump = DumpFormatter.BuildDump(meRequest, response, ex.ToString()); - return await httpClient.OneWayRequestAsync(BuildPostRequest(job, path), job.RequestBody, ct); + return Result.Failed(ex, requestDump); + } } + + return await httpClient.OneWayRequestAsync(BuildPostRequest(job, path), job.RequestBody, ct); } private static HttpRequestMessage BuildPostRequest(MediumJob job, string path) { - var request = new HttpRequestMessage(HttpMethod.Post, $"https://api.medium.com/{path}") + var request = new HttpRequestMessage(HttpMethod.Post, path) { Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") }; @@ -133,9 +127,9 @@ public sealed class MediumActionHandler : RuleActionHandler + { + options.BaseAddress = new Uri("https://api.medium.com/"); + options.Timeout = TimeSpan.FromSeconds(4); + options.DefaultRequestHeaders.Add("Accept", "application/json"); + options.DefaultRequestHeaders.Add("Accept-Charset", "utf-8"); + options.DefaultRequestHeaders.Add("User-Agent", "Squidex Headless CMS"); + }); + services.AddRuleAction(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderActionHandler.cs index 1690d371b..98686646d 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderActionHandler.cs @@ -36,15 +36,14 @@ public sealed class PrerenderActionHandler : RuleActionHandler ExecuteJobAsync(PrerenderJob job, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) + var httpClient = httpClientFactory.CreateClient("Prerender"); + + var request = new HttpRequestMessage(HttpMethod.Post, "/recache") { - var request = new HttpRequestMessage(HttpMethod.Post, "https://api.prerender.io/recache") - { - Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") - }; + Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") + }; - return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); - } + return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderPlugin.cs b/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderPlugin.cs index 8ab112f58..559875744 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderPlugin.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Prerender/PrerenderPlugin.cs @@ -15,6 +15,11 @@ public sealed class PrerenderPlugin : IPlugin { public void ConfigureServices(IServiceCollection services, IConfiguration config) { + services.AddHttpClient("PrerenderAction", options => + { + options.BaseAddress = new Uri("https://api.prerender.io"); + }); + services.AddRuleAction(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Slack/SlackActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Slack/SlackActionHandler.cs index ec92ef45d..76305e534 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Slack/SlackActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Slack/SlackActionHandler.cs @@ -41,17 +41,14 @@ public sealed class SlackActionHandler : RuleActionHandler ExecuteJobAsync(SlackJob job, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) - { - httpClient.Timeout = TimeSpan.FromSeconds(2); + var httpClient = httpClientFactory.CreateClient("SlackAction"); - var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl) - { - Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") - }; + var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl) + { + Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") + }; - return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); - } + return await httpClient.OneWayRequestAsync(request, job.RequestBody, ct); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Slack/SlackPlugin.cs b/backend/extensions/Squidex.Extensions/Actions/Slack/SlackPlugin.cs index b1ec0236e..81f848194 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Slack/SlackPlugin.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Slack/SlackPlugin.cs @@ -15,6 +15,11 @@ public sealed class SlackPlugin : IPlugin { public void ConfigureServices(IServiceCollection services, IConfiguration config) { + services.AddHttpClient("SlackAction", options => + { + options.Timeout = TimeSpan.FromSeconds(2); + }); + services.AddRuleAction(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Typesense/TypesenseActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Typesense/TypesenseActionHandler.cs index b8519c544..6127ef233 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Typesense/TypesenseActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Typesense/TypesenseActionHandler.cs @@ -109,7 +109,7 @@ public sealed class TypesenseActionHandler : RuleActionHandler(); } } diff --git a/backend/extensions/Squidex.Extensions/Actions/Webhook/WebhookActionHandler.cs b/backend/extensions/Squidex.Extensions/Actions/Webhook/WebhookActionHandler.cs index 924111c5f..b8f6bedcf 100644 --- a/backend/extensions/Squidex.Extensions/Actions/Webhook/WebhookActionHandler.cs +++ b/backend/extensions/Squidex.Extensions/Actions/Webhook/WebhookActionHandler.cs @@ -90,7 +90,7 @@ public sealed class WebhookActionHandler : RuleActionHandler ExecuteJobAsync(WebhookJob job, CancellationToken ct = default) { - var httpClient = httpClientFactory.CreateClient(); + var httpClient = httpClientFactory.CreateClient("WebhookAction"); var method = HttpMethod.Post; @@ -110,7 +110,7 @@ public sealed class WebhookActionHandler : RuleActionHandler + { + options.DefaultRequestHeaders.Add("User-Agent", "Squidex Webhook"); + options.DefaultRequestHeaders.Add("X-Application", "Squidex Webhook"); + }); + services.AddRuleAction(); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs index 9650f4166..9a49685e5 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs @@ -91,20 +91,16 @@ public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor throw new JavaScriptException("URL is not valid."); } - using (var httpClient = httpClientFactory.CreateClient()) - { - using (var request = CreateRequest(context, method, uri, body, headers)) - { - using (var response = await httpClient.SendAsync(request, ct)) - { - response.EnsureSuccessStatusCode(); + var httpClient = httpClientFactory.CreateClient("Jint"); - var responseObject = await ParseResponseasync(context, response, ct); + var request = CreateRequest(context, method, uri, body, headers); + var response = await httpClient.SendAsync(request, ct); - scheduler.Run(callback, responseObject); - } - } - } + response.EnsureSuccessStatusCode(); + + var responseObject = await ParseResponseasync(context, response, ct); + + scheduler.Run(callback, responseObject); }); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs index c6b59a711..1ee2ea687 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs @@ -105,35 +105,31 @@ public static class AtlasIndexDefinition return "t.iv"; } - public static async Task CreateIndexAsync(AtlasOptions options, + public static async Task CreateIndexAsync(AtlasOptions options, IHttpClientFactory httpClientFactory, string database, string collectionName, CancellationToken ct) { var (index, name) = Create(database, collectionName); - using (var httpClient = new HttpClient(new HttpClientHandler - { - Credentials = new NetworkCredential(options.PublicKey, options.PrivateKey, "cloud.mongodb.com") - })) - { - var url = $"https://cloud.mongodb.com/api/atlas/v1.0/groups/{options.GroupId}/clusters/{options.ClusterName}/fts/indexes"; + var httpClient = httpClientFactory.CreateClient("Atlas"); - var result = await httpClient.PostAsJsonAsync(url, index, ct); + var url = $"/api/atlas/v1.0/groups/{options.GroupId}/clusters/{options.ClusterName}/fts/indexes"; - if (result.IsSuccessStatusCode) - { - return name; - } + var result = await httpClient.PostAsJsonAsync(url, index, ct); + + if (result.IsSuccessStatusCode) + { + return name; + } - var error = await result.Content.ReadFromJsonAsync(cancellationToken: ct); + var error = await result.Content.ReadFromJsonAsync(cancellationToken: ct); - if (error?.ErrorCode != "ATLAS_FTS_DUPLICATE_INDEX") - { - var message = new ConfigurationError($"Creating index failed with {result.StatusCode}: {error?.Detail}"); + if (error?.ErrorCode == "ATLAS_FTS_DUPLICATE_INDEX") + { + var message = new ConfigurationError($"Creating index failed with {result.StatusCode}: {error?.Detail}"); - throw new ConfigurationException(message); - } + throw new ConfigurationException(message); } return name; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasTextIndex.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasTextIndex.cs index 212927f4d..ef810c946 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasTextIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasTextIndex.cs @@ -26,11 +26,13 @@ public sealed class AtlasTextIndex : MongoTextIndexBase options) + public AtlasTextIndex(IMongoDatabase database, IHttpClientFactory httpClientFactory, IOptions options) : base(database) { + this.httpClientFactory = httpClientFactory; this.options = options.Value; } @@ -39,7 +41,7 @@ public sealed class AtlasTextIndex : MongoTextIndexBase options) { this.httpClientFactory = httpClientFactory; - this.options = options.Value; } public async Task GetRepositoryUrl(string name, CancellationToken ct = default) { - using (var httpClient = httpClientFactory.CreateClient()) + var httpClient = httpClientFactory.CreateClient(); + + var result = new List