From 31315580173cda232300b8bf82946317115dec2a Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Tue, 4 Jun 2024 12:37:09 +0200 Subject: [PATCH] Change HttpClientBuilder to work on IServiceCollection --- .../Http/HttpClientBuilderTests.cs | 118 +----------------- .../Extensions/ServiceManagerExtensions.cs | 11 +- .../Http/HttpClientBuilder.cs | 17 +-- ...ons.NetStandard.DependencyInjection.csproj | 2 +- 4 files changed, 22 insertions(+), 126 deletions(-) diff --git a/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs index 7ff7344..2656a26 100644 --- a/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs +++ b/SystemExtensions.DependencyInjection.Tests/Http/HttpClientBuilderTests.cs @@ -1,8 +1,8 @@ using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; using NSubstitute; using NSubstitute.ExceptionExtensions; -using Slim; using System; using System.Linq; using System.Net.Http; @@ -18,7 +18,7 @@ public sealed class HttpClientBuilderTests private const string SomeValue = "SomeValue"; private readonly HttpClientBuilder httpClientBuilder; - private readonly IServiceProducer serviceProducerMock = Substitute.For(); + private readonly IServiceCollection serviceProducerMock = Substitute.For(); private readonly Uri baseAddress = new("http://contoso.co"); public HttpClientBuilderTests() @@ -63,120 +63,13 @@ public sealed class HttpClientBuilderTests { var producer = this.httpClientBuilder.Build(); - producer.Should().Be(this.serviceProducerMock); - } - - [TestMethod] - public void Build_RegistersWithServiceProducer() - { - this.httpClientBuilder.Build(); - - this.serviceProducerMock.Received().RegisterScoped(Arg.Any>>(), false); - } - - [TestMethod] - public void Build_CreatesExpectedClient() - { - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - client.BaseAddress.Should().BeNull(); - client.DefaultRequestHeaders.Should().BeEmpty(); - client.MaxResponseContentBufferSize.Should().Be(2147483647L); - client.Timeout.Should().Be(TimeSpan.FromSeconds(100)); - }); - - this.httpClientBuilder.Build(); - - } - - [TestMethod] - public void Build_WithBaseAddress_ReturnsClientWithBaseAddress() - { - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - client.BaseAddress.Should().Be(this.baseAddress); - }); - - this.httpClientBuilder.WithBaseAddress(this.baseAddress) - .Build(); - } - - [TestMethod] - public void Build_WithDefaultRequestHeaders_CallsFactory() - { - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - client.DefaultRequestHeaders.TryGetValues(SomeHeader, out var values); - values.Should().HaveCount(1); - values.FirstOrDefault().Should().Be(SomeValue); - }); - - this.httpClientBuilder.WithDefaultRequestHeadersSetup((headers) => - { - headers.TryAddWithoutValidation(SomeHeader, SomeValue); - }).Build(); - } - - [TestMethod] - public void Build_WithMaxResponseBufferSize_ReturnsClientWithMaxResponseBufferSize() - { - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - client.MaxResponseContentBufferSize.Should().Be(100); - }); - - this.httpClientBuilder.WithMaxResponseBufferSize(100) - .Build(); - } - - [TestMethod] - public void Build_WithTimeout_ReturnsClientWithTimeout() - { - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - client.Timeout.Should().Be(TimeSpan.FromSeconds(5)); - }); - - this.httpClientBuilder.WithTimeout(TimeSpan.FromSeconds(5)) - .Build(); - } - - [TestMethod] - public void Build_WithMessageHandler_CallsMessageHandler() - { - var handlerMock = new HttpMessageHandlerMock(); - this.serviceProducerMock.When(u => u.RegisterScoped(Arg.Any>>(), false)) - .Do(async callInfo => - { - var factory = callInfo.ArgAt>>(0); - var client = factory(Substitute.For()); - await client.GetAsync(this.baseAddress); - handlerMock.Called.Should().BeTrue(); - }); - - this.httpClientBuilder.WithMessageHandler(sp => handlerMock) - .Build(); + producer.Should().BeEquivalentTo(this.serviceProducerMock); } [TestMethod] public async Task HttpClientBuilder_RegistersClientCorrectly_IServiceProviderReturnsExpected() { - var container = new ServiceManager(); + var container = new ServiceCollection(); var messageHandler = new HttpMessageHandlerMock(); new HttpClientBuilder(container) .WithBaseAddress(this.baseAddress) @@ -186,7 +79,8 @@ public sealed class HttpClientBuilderTests .WithTimeout(TimeSpan.FromSeconds(5)) .Build(); - var client = container.GetService>(); + var di = container.BuildServiceProvider(); + var client = di.GetService>(); await client.GetAsync(""); client.Should().NotBeNull(); diff --git a/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs b/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs index a50189f..513851a 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Extensions/ServiceManagerExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Slim; using System.Configuration; @@ -157,13 +158,13 @@ public static class ServiceManagerExtensions /// Register a scoped to be used by the DI engine. /// /// Type of the scoped . - /// . + /// . /// to build the http client. - public static HttpClientBuilder RegisterHttpClient(this IServiceProducer serviceProducer) + public static HttpClientBuilder RegisterHttpClient(this IServiceCollection services) { - serviceProducer.ThrowIfNull(nameof(serviceProducer)); + services.ThrowIfNull(nameof(services)); - return new HttpClientBuilder(serviceProducer); + return new HttpClientBuilder(services); } [Obsolete($"{nameof(RegisterHttpFactory)} is obsolete. Please use {nameof(RegisterHttpClient)} for each service that requires an instance of {nameof(IHttpClient)}.")] diff --git a/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs index 072f9d8..0e7fac2 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs +++ b/SystemExtensions.NetStandard.DependencyInjection/Http/HttpClientBuilder.cs @@ -1,4 +1,5 @@ -using Slim; +using Microsoft.Extensions.DependencyInjection; +using Slim; using System.Extensions; using System.Net.Http.Headers; @@ -6,7 +7,7 @@ namespace System.Net.Http; public sealed class HttpClientBuilder { - private readonly IServiceProducer serviceProducer; + private readonly IServiceCollection services; private Uri baseAddress; private Func httpMessageHandlerFactory; @@ -15,11 +16,11 @@ public sealed class HttpClientBuilder private long maxResponseBufferSize = 2147483647L; //2GB default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.maxresponsecontentbuffersize?view=net-6.0] private TimeSpan timeout = TimeSpan.FromSeconds(100); //100 seconds default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-6.0] - internal HttpClientBuilder(IServiceProducer serviceProducer) + internal HttpClientBuilder(IServiceCollection services) { - serviceProducer.ThrowIfNull(nameof(serviceProducer)); + services.ThrowIfNull(nameof(services)); - this.serviceProducer = serviceProducer; + this.services = services; } public HttpClientBuilder WithMessageHandler(Func httpMessageHandlerFactory) @@ -64,9 +65,9 @@ public sealed class HttpClientBuilder return this; } - public IServiceProducer Build() + public IServiceCollection Build() { - this.serviceProducer.RegisterScoped>(sp => + this.services.AddScoped>(sp => { var client = this.httpMessageHandlerFactory is not null ? new HttpClient(this.httpMessageHandlerFactory(sp), this.disposeMessageHandler) : @@ -79,6 +80,6 @@ public sealed class HttpClientBuilder return client; }); - return this.serviceProducer; + return this.services; } } diff --git a/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj b/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj index 21a19a8..4c9eef2 100644 --- a/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj +++ b/SystemExtensions.NetStandard.DependencyInjection/SystemExtensions.NetStandard.DependencyInjection.csproj @@ -6,7 +6,7 @@ LICENSE true latest - 1.3.1 + 1.4.0 Alexandru Macocian https://github.com/AlexMacocian/SystemExtensions Extensions for the Slim Dependency Injection engine