From 8db845f27a26ad55cf394e3363987ca2e969c363 Mon Sep 17 00:00:00 2001 From: Mohammad Mahdi Date: Wed, 4 Nov 2026 17:05:41 +0330 Subject: [PATCH] feat: utilize IHttpClientFactory for improved HTTP client management - Replaced direct `HttpClient` dependencies with `IHttpClientFactory` in `GithubService`, `ForgejoService`, and `ReleaseAssetDownloadService`. - Added DI-configured HTTP client registrations for GitHub, Forgejo, and asset downloads in `Program.cs`. - Consolidated HTTP client setup to enhance maintainability, configurability, and resource lifecycle management. --- Program.cs | 19 ++++++++++++------- Services/ForgejoService.cs | 24 ++++++++++++++++-------- Services/GithubService.cs | 7 ++++--- Services/ReleaseAssetDownloadService.cs | 4 +++- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Program.cs b/Program.cs index d47fcbd..973a4a0 100644 --- a/Program.cs +++ b/Program.cs @@ -8,27 +8,32 @@ var builder = Host.CreateApplicationBuilder(args); var config = AppConfigLoader.LoadConfigFromEnv(); builder.Services.AddSingleton(config); -var repositoryConfig = await RepoConfigLoader.LoadConfigAsync( - config.RepositoryConfigFilePath); +var repositoryConfig = await RepoConfigLoader.LoadConfigAsync(config.RepositoryConfigFilePath); builder.Services.AddSingleton(repositoryConfig); -builder.Services.AddHttpClient(client => +builder.Services.AddHttpClient("github", client => { client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.UserAgent.ParseAdd("ForgejoReleaseSync"); client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); }); -builder.Services.AddHttpClient(client => +builder.Services.AddHttpClient("forgejo", client => +{ + client.BaseAddress = new Uri(config.ForgejoInstacne.TrimEnd('/') + "/"); + client.DefaultRequestHeaders.UserAgent.ParseAdd("ForgejoReleaseSync"); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("token", config.ForgejoToken); +}); + +builder.Services.AddHttpClient("asset-download", client => { - client.BaseAddress = new Uri(config.ForgejoInstacne); client.DefaultRequestHeaders.UserAgent.ParseAdd("ForgejoReleaseSync"); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", config.ForgejoToken); }); -builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); var app = builder.Build(); diff --git a/Services/ForgejoService.cs b/Services/ForgejoService.cs index b6c3474..b86fe2b 100644 --- a/Services/ForgejoService.cs +++ b/Services/ForgejoService.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; namespace ForgejoReleaseSync.Services; -public class ForgejoService(HttpClient httpClient, AppConfig config, ILogger logger) +public class ForgejoService(IHttpClientFactory httpClientFactory, ILogger logger) { public async Task CreateReleaseAsync( string owner, string repo, string body, string name, string tagName, CancellationToken token = default) @@ -16,10 +16,13 @@ public class ForgejoService(HttpClient httpClient, AppConfig config, ILogger logger) +public class GithubService(IHttpClientFactory httpClientFactory, ILogger logger) { public async Task> FetchRepoReleasesAsync( string owner, string repo, CancellationToken token = default) { try { + var httpClient = httpClientFactory.CreateClient("github"); + using var response = await httpClient.GetAsync( - new Uri($"https://api.github.com/repos/{owner}/{repo}/releases?per_page=3&page=1"), - token); + $"repos/{owner}/{repo}/releases?per_page=3&page=1", token); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(token); diff --git a/Services/ReleaseAssetDownloadService.cs b/Services/ReleaseAssetDownloadService.cs index 2a5b881..a1b184b 100644 --- a/Services/ReleaseAssetDownloadService.cs +++ b/Services/ReleaseAssetDownloadService.cs @@ -2,12 +2,14 @@ using Microsoft.Extensions.Logging; namespace ForgejoReleaseSync.Services; -public class ReleaseAssetDownloadService(HttpClient httpClient, ILogger logger) +public class ReleaseAssetDownloadService(IHttpClientFactory httpClientFactory, ILogger logger) { public async Task DownloadReleaseAssetAsync(Uri url, CancellationToken token = default) { try { + var httpClient = httpClientFactory.CreateClient("asset-download"); + var fileName = Path.GetFileName(url.AbsoluteUri); var filePath = Path.Combine(Path.GetTempPath(), fileName);