From 7062059d4419d1219b0976323fc20e7bc74826bd Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 26 Nov 2023 21:10:41 +0800 Subject: [PATCH 1/2] Introduce `IInjectPropertiesService`. --- .../Autofac/AutoFacInjectPropertiesService.cs | 44 ++++++++++++ .../IInjectPropertiesService.cs | 16 +++++ .../NullInjectPropertiesService.cs | 17 +++++ ...AutoFacInjectingPropertiesService_Tests.cs | 67 +++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AutoFacInjectPropertiesService.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IInjectPropertiesService.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/NullInjectPropertiesService.cs create mode 100644 framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFacInjectingPropertiesService_Tests.cs diff --git a/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AutoFacInjectPropertiesService.cs b/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AutoFacInjectPropertiesService.cs new file mode 100644 index 0000000000..6209eafc48 --- /dev/null +++ b/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AutoFacInjectPropertiesService.cs @@ -0,0 +1,44 @@ +using System; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Autofac; + +public class AutoFacInjectPropertiesService : IInjectPropertiesService, ITransientDependency +{ + protected IServiceProvider ServiceProvider { get; } + + public AutoFacInjectPropertiesService(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public virtual TService InjectProperties(TService instance) where TService : notnull + { + return InjectProperties(instance, false); + } + + public virtual TService InjectUnsetProperties(TService instance) where TService : notnull + { + return InjectProperties(instance, true); + } + + protected virtual TService InjectProperties(TService instance, bool onlyForUnsetProperties) + where TService : notnull + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } + + if (ServiceProvider is not AutofacServiceProvider) + { + throw new AbpException($"The {nameof(ServiceProvider)} must be an instance of {nameof(AutofacServiceProvider)}!"); + } + + return onlyForUnsetProperties + ? ServiceProvider.As().LifetimeScope.InjectUnsetProperties(instance) + : ServiceProvider.As().LifetimeScope.InjectProperties(instance); + } +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IInjectPropertiesService.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IInjectPropertiesService.cs new file mode 100644 index 0000000000..76313efaaa --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IInjectPropertiesService.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +public interface IInjectPropertiesService +{ + /// + /// Set any properties on that can be resolved by IServiceProvider. + /// + TService InjectProperties(TService instance) where TService : notnull; + + /// + /// Set any null-valued properties on that can be resolved by the IServiceProvider. + /// + TService InjectUnsetProperties(TService instance) where TService : notnull; +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/NullInjectPropertiesService.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/NullInjectPropertiesService.cs new file mode 100644 index 0000000000..5ddfb8d53f --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/NullInjectPropertiesService.cs @@ -0,0 +1,17 @@ +namespace Volo.Abp.DependencyInjection; + +[Dependency(TryRegister = true)] +public class NullInjectPropertiesService : IInjectPropertiesService, ITransientDependency +{ + public TService InjectProperties(TService instance) + where TService : notnull + { + return instance; + } + + public TService InjectUnsetProperties(TService instance) + where TService : notnull + { + return instance; + } +} diff --git a/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFacInjectingPropertiesService_Tests.cs b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFacInjectingPropertiesService_Tests.cs new file mode 100644 index 0000000000..7766450feb --- /dev/null +++ b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFacInjectingPropertiesService_Tests.cs @@ -0,0 +1,67 @@ +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Autofac.Interception; +using Volo.Abp.DependencyInjection; +using Xunit; + +namespace Volo.Abp.Autofac; + +public class AutoFacInjectingPropertiesService_Tests : Autofac_Interception_Test +{ + [Fact] + public void AutoFacInjectingPropertiesService_Should_Replaces_NullInjectingPropertiesService() + { + ServiceProvider.GetRequiredService().GetType().ShouldBe(typeof(AutoFacInjectPropertiesService)); + } + + [Fact] + public void InjectProperties() + { + var injectPropertiesService = ServiceProvider.GetRequiredService(); + var serviceB = new TestServiceB(); + injectPropertiesService.InjectProperties(serviceB); + + serviceB.NullTestServiceA.ShouldNotBeNull(); + serviceB.NullTestServiceA.Name.ShouldBe("Default Name"); + serviceB.NotNullTestServiceA.ShouldNotBeNull(); + serviceB.NotNullTestServiceA.Name.ShouldBe("Default Name"); + } + + [Fact] + public void InjectUnsetProperties() + { + var injectPropertiesService = ServiceProvider.GetRequiredService(); + var serviceB = new TestServiceB(); + injectPropertiesService.InjectUnsetProperties(serviceB); + + serviceB.NullTestServiceA.ShouldNotBeNull(); + serviceB.NullTestServiceA.Name.ShouldBe("Default Name"); + serviceB.NotNullTestServiceA.ShouldNotBeNull(); + serviceB.NotNullTestServiceA.Name.ShouldBe("My Name"); // This is not null property. + } +} + +interface ITestServiceA +{ + public string Name { get; set; } +} + +class TestServiceA : ITestServiceA, ITransientDependency +{ + public string Name { get; set; } = "Default Name"; +} + +interface ITestServiceB +{ + +} + +class TestServiceB : ITestServiceB, ITransientDependency +{ + public ITestServiceA NullTestServiceA { get; set; } + + public ITestServiceA NotNullTestServiceA { get; set; } = new TestServiceA() + { + Name = "My Name" + }; +} From 53163db8b5cf4452642c9bdc7306f8b5d7239e1c Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 27 Nov 2023 10:11:39 +0800 Subject: [PATCH 2/2] Update Dependency-Injection.md --- docs/en/Dependency-Injection.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index d8afe5c21c..51a395e3ea 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -269,6 +269,21 @@ public class MyService : ITransientDependency } ```` +#### IInjectPropertiesService + +You can use the `IInjectPropertiesService` service to inject properties of an object. Generally, it is a service outside of DI, such as manually created services. + +````C# +var injectPropertiesService = serviceProvider.GetRequiredService(); +var instance = new TestService(); + +// Set any properties on instance that can be resolved by IServiceProvider. +injectPropertiesService.InjectProperties(instance); + +// Set any null-valued properties on instance that can be resolved by the IServiceProvider. +injectPropertiesService.InjectUnsetProperties(instance); +```` + ### Resolve Service from IServiceProvider You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject `IServiceProvider` into your class and use the ``GetService`` or the `GetRequiredService` method as shown below: