From 42cb9acb4846b35747be25ace7f36d74fb5b9c94 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Mon, 21 Aug 2023 17:39:35 +0100 Subject: [PATCH] fix: fix AddHostedSingleton not accepting interface as service type --- CHANGELOG.md | 9 +++- .../ServiceCollectionExtensions.cs | 7 +-- .../src/Hosting/ServiceCollectionTests.cs | 53 ++++++++++++++++++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a86ae26..034117e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.3.1] - 2023-08-21 + +### Fixed + +- X10D.Hosting: Fixed `AddHostedSingleton` not accepting an interface as the service type. + ## [3.3.0] - 2023-08-21 ### Added @@ -583,7 +589,8 @@ please [open an issue](https://github.com/oliverbooth/X10D/issues)! Earlier versions of this package are undocumented and unlisted from package results. -[unreleased]: https://github.com/oliverbooth/X10D/compare/v3.3.0...main +[unreleased]: https://github.com/oliverbooth/X10D/compare/v3.3.1...main +[3.3.1]: https://github.com/oliverbooth/X10D/releases/tag/v3.3.1 [3.3.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.3.0 [3.2.2]: https://github.com/oliverbooth/X10D/releases/tag/v3.2.2 [3.2.0]: https://github.com/oliverbooth/X10D/releases/tag/v3.2.0 diff --git a/X10D.Hosting/src/DependencyInjection/ServiceCollectionExtensions.cs b/X10D.Hosting/src/DependencyInjection/ServiceCollectionExtensions.cs index 8df216c..ea0d3a4 100644 --- a/X10D.Hosting/src/DependencyInjection/ServiceCollectionExtensions.cs +++ b/X10D.Hosting/src/DependencyInjection/ServiceCollectionExtensions.cs @@ -29,11 +29,12 @@ public static class ServiceCollectionExtensions /// The type of the implementation to use. /// A reference to this instance after the operation has completed. public static IServiceCollection AddHostedSingleton(this IServiceCollection services) - where TService : class, IHostedService - where TImplementation : class, TService + where TService : class + where TImplementation : class, TService, IHostedService { services.AddSingleton(); - return services.AddSingleton(provider => provider.GetRequiredService()); + return services.AddSingleton(provider => + (TImplementation)provider.GetRequiredService()); } /// diff --git a/X10D.Tests/src/Hosting/ServiceCollectionTests.cs b/X10D.Tests/src/Hosting/ServiceCollectionTests.cs index 0ce3fd2..63a3db6 100644 --- a/X10D.Tests/src/Hosting/ServiceCollectionTests.cs +++ b/X10D.Tests/src/Hosting/ServiceCollectionTests.cs @@ -29,6 +29,27 @@ public class ServiceCollectionTests }); } + [Test] + public void AddHostedSingleton_ShouldRegisterServiceAsSingletonAndAsHostedService_GivenServiceAndImplTypes() + { + var services = new ServiceCollection(); + + services.AddHostedSingleton(); + + var serviceProvider = services.BuildServiceProvider(); + var service = serviceProvider.GetService(); + var hostedService = serviceProvider.GetService(); + + Assert.Multiple(() => + { + Assert.That(service, Is.Not.Null); + Assert.That(hostedService, Is.Not.Null); + Assert.IsAssignableFrom(service); + Assert.IsAssignableFrom(hostedService); + Assert.That(hostedService, Is.SameAs(service)); + }); + } + [Test] public void AddHostedSingleton_ShouldRegisterServiceTypeAsSingletonAndAsHostedService() { @@ -50,8 +71,38 @@ public class ServiceCollectionTests }); } - private sealed class TestService : IHostedService + [Test] + public void AddHostedSingleton_ShouldRegisterServiceTypeAsSingletonAndAsHostedService_GivenServiceAndImplTypes() { + var services = new ServiceCollection(); + + services.AddHostedSingleton(typeof(ITestService), typeof(TestService)); + + var serviceProvider = services.BuildServiceProvider(); + var service = serviceProvider.GetService(); + var hostedService = serviceProvider.GetService(); + + Assert.Multiple(() => + { + Assert.That(service, Is.Not.Null); + Assert.That(hostedService, Is.Not.Null); + Assert.IsAssignableFrom(service); + Assert.IsAssignableFrom(hostedService); + Assert.That(hostedService, Is.SameAs(service)); + }); + } + + private interface ITestService + { + void Foo(); + } + + private sealed class TestService : ITestService, IHostedService + { + public void Foo() + { + } + public Task StartAsync(CancellationToken cancellationToken) { return Task.CompletedTask;