Browse Source

Merge pull request #13844 from mgochmuradov/feature/Add_DisablePropertyInjection_Attribute

pull/13858/head
maliming 3 years ago
committed by GitHub
parent
commit
dffa80b291
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      docs/en/Dependency-Injection.md
  2. 8
      framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs
  3. 21
      framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpPropertySelector.cs
  4. 9
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DisablePropertyInjectionAttribute.cs
  5. 62
      framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs

34
docs/en/Dependency-Injection.md

@ -244,25 +244,35 @@ One restriction of property injection is that you cannot use the dependency in y
Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class.
### Resolve Service from IServiceProvider
#### DisablePropertyInjectionAttribute
You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below:
You can use `[DisablePropertyInjection]` attribute on class or properties to disable property injection for the whole class or some specific properties.
````C#
[DisablePropertyInjection]
public class MyService : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public ITaxCalculator TaxCalculator { get; set; }
}
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public class MyService : ITransientDependency
{
public ILogger<MyService> Logger { get; set; }
public void DoSomething()
{
var taxCalculator = _serviceProvider.GetService<ITaxCalculator>();
//...
}
[DisablePropertyInjection]
public ITaxCalculator TaxCalculator { get; set; }
}
````
### 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 ``GetService`` method as shown below:
````C#
public class MyService : ITransientDependency
{
public ILogger<MyService> Logger { get; set; }
}
````

8
framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autofac.Core;
using Autofac.Extras.DynamicProxy;
using Volo.Abp.Autofac;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
@ -67,10 +68,11 @@ public static class AbpRegistrationBuilderExtensions
Type implementationType)
where TActivatorData : ReflectionActivatorData
{
//Enable Property Injection only for types in an assembly containing an AbpModule
if (moduleContainer.Modules.Any(m => m.Assembly == implementationType.Assembly))
// Enable Property Injection only for types in an assembly containing an AbpModule and without a DisablePropertyInjection attribute on class or properties.
if (moduleContainer.Modules.Any(m => m.Assembly == implementationType.Assembly) &&
implementationType.GetCustomAttributes(typeof(DisablePropertyInjectionAttribute), true).IsNullOrEmpty())
{
registrationBuilder = registrationBuilder.PropertiesAutowired();
registrationBuilder = registrationBuilder.PropertiesAutowired(new AbpPropertySelector(false));
}
return registrationBuilder;

21
framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpPropertySelector.cs

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Reflection;
using Autofac.Core;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Autofac;
public class AbpPropertySelector : DefaultPropertySelector
{
public AbpPropertySelector(bool preserveSetValues)
: base(preserveSetValues)
{
}
public override bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
return propertyInfo.GetCustomAttributes(typeof(DisablePropertyInjectionAttribute), true).IsNullOrEmpty() &&
base.InjectProperty(propertyInfo, instance);
}
}

9
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DisablePropertyInjectionAttribute.cs

@ -0,0 +1,9 @@
using System;
namespace Volo.Abp.DependencyInjection;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class DisablePropertyInjectionAttribute : Attribute
{
}

62
framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs

@ -47,19 +47,36 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest<Dep
[Fact]
public void Should_Inject_Services_As_Properties()
{
GetRequiredService<ServiceWithPropertyInject>().ProperyInjectedService.ShouldNotBeNull();
GetRequiredService<ServiceWithPropertyInject>().PropertyInjectedService.ShouldNotBeNull();
}
[Fact]
public void Should_Inject_Services_As_Properties_For_Generic_Classes()
{
GetRequiredService<GenericServiceWithPropertyInject<int>>().ProperyInjectedService.ShouldNotBeNull();
GetRequiredService<GenericServiceWithPropertyInject<int>>().PropertyInjectedService.ShouldNotBeNull();
}
[Fact]
public void Should_Inject_Services_As_Properties_For_Generic_Concrete_Classes()
{
GetRequiredService<ConcreteGenericServiceWithPropertyInject>().ProperyInjectedService.ShouldNotBeNull();
GetRequiredService<ConcreteGenericServiceWithPropertyInject>().PropertyInjectedService.ShouldNotBeNull();
}
[Fact]
public void Should_Not_Inject_Services_As_Properties_When_Class_With_DisablePropertyInjection()
{
GetRequiredService<DisablePropertyInjectionOnClass>().PropertyInjectedService.ShouldBeNull();
GetRequiredService<GenericServiceWithDisablePropertyInjectionOnClass<string>>().PropertyInjectedService.ShouldBeNull();
}
[Fact]
public void Should_Not_Inject_Services_As_Properties_When_Property_With_DisablePropertyInjection()
{
GetRequiredService<DisablePropertyInjectionOnProperty>().PropertyInjectedService.ShouldNotBeNull();
GetRequiredService<DisablePropertyInjectionOnProperty>().DisablePropertyInjectionService.ShouldBeNull();
GetRequiredService<GenericServiceWithDisablePropertyInjectionOnProperty<string>>().PropertyInjectedService.ShouldNotBeNull();
GetRequiredService<GenericServiceWithDisablePropertyInjectionOnProperty<string>>().DisablePropertyInjectionService.ShouldBeNull();
}
[Fact]
@ -145,18 +162,19 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest<Dep
context.Services.AddType<ServiceWithPropertyInject>();
context.Services.AddType<MySingletonExposingMultipleServices>();
context.Services.AddTransient(typeof(GenericServiceWithPropertyInject<>));
context.Services.AddTransient(typeof(ConcreteGenericServiceWithPropertyInject));
context.Services.AddTransient(typeof(GenericServiceWithDisablePropertyInjectionOnClass<>));
context.Services.AddTransient(typeof(GenericServiceWithDisablePropertyInjectionOnProperty<>));
}
}
public class ServiceWithPropertyInject : ITransientDependency
{
public MyEmptyTransientService ProperyInjectedService { get; set; }
public MyEmptyTransientService PropertyInjectedService { get; set; }
}
public class GenericServiceWithPropertyInject<T> : ITransientDependency
{
public MyEmptyTransientService ProperyInjectedService { get; set; }
public MyEmptyTransientService PropertyInjectedService { get; set; }
public T Value { get; set; }
}
@ -165,4 +183,36 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest<Dep
{
}
[DisablePropertyInjection]
public class DisablePropertyInjectionOnClass : ITransientDependency
{
public MyEmptyTransientService PropertyInjectedService { get; set; }
}
public class DisablePropertyInjectionOnProperty : ITransientDependency
{
public MyEmptyTransientService PropertyInjectedService { get; set; }
[DisablePropertyInjection]
public MyEmptyTransientService DisablePropertyInjectionService { get; set; }
}
[DisablePropertyInjection]
public class GenericServiceWithDisablePropertyInjectionOnClass<T> : ITransientDependency
{
public MyEmptyTransientService PropertyInjectedService { get; set; }
public T Value { get; set; }
}
public class GenericServiceWithDisablePropertyInjectionOnProperty<T> : ITransientDependency
{
public MyEmptyTransientService PropertyInjectedService { get; set; }
[DisablePropertyInjection]
public MyEmptyTransientService DisablePropertyInjectionService { get; set; }
public T Value { get; set; }
}
}

Loading…
Cancel
Save