Merge pull request #18272 from abpframework/auto-merge/rel-8-0/2298

Merge branch dev with rel-8.0
pull/18275/head
maliming 2 years ago committed by GitHub
commit 72681ab626
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -480,6 +480,24 @@ This example simply checks if the service class has `MyLogAttribute` attribute a
> Notice that `OnRegistered` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors.
### IServiceCollection.OnActivated Event
The `OnActivated` event is raised once a service is fully constructed. Here you can perform application-level tasks that depend on the service being fully constructed - these should be rare.
````csharp
var serviceDescriptor = ServiceDescriptor.Transient<MyServer, MyServer>();
services.Add(serviceDescriptor);
if (setIsReadOnly)
{
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().IsReadOnly = true;
});
}
````
> Notice that `OnActivated` event can be registered multiple times for the same `ServiceDescriptor`.
## 3rd-Party Providers
While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work.

@ -310,6 +310,24 @@ public class AppModule : AbpModule
> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistered` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md).
### IServiceCollection.OnActivated 事件
一旦服务完全构建完成`OnActivated`事件就会触发. 你可以执行依赖于服务已完全构建的的一些任务, 虽然这种情况可能很少见.
````csharp
var serviceDescriptor = ServiceDescriptor.Transient<MyServer, MyServer>();
services.Add(serviceDescriptor);
if (setIsReadOnly)
{
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().IsReadOnly = true;
});
}
````
> 注意,`OnActivated`事件可以为一个`ServiceDescriptor`注册多次.
## 第三方提供程序
虽然ABP框架没有对任何第三方DI提供程序的核心依赖, 但它必须使用一个提供程序来支持动态代理(dynamic proxying)和一些高级特性以便ABP特性能正常工作.

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autofac.Core;
using Autofac.Extras.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.DependencyInjection;
@ -14,10 +15,14 @@ public static class AbpRegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> ConfigureAbpConventions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceDescriptor serviceDescriptor,
IModuleContainer moduleContainer,
ServiceRegistrationActionList registrationActionList)
ServiceRegistrationActionList registrationActionList,
ServiceActivatedActionList activatedActionList)
where TActivatorData : ReflectionActivatorData
{
registrationBuilder = registrationBuilder.InvokeActivatedActions(activatedActionList, serviceDescriptor);
var serviceType = registrationBuilder.RegistrationData.Services.OfType<IServiceWithType>().FirstOrDefault()?.ServiceType;
if (serviceType == null)
{
@ -36,6 +41,24 @@ public static class AbpRegistrationBuilderExtensions
return registrationBuilder;
}
private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InvokeActivatedActions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceActivatedActionList activatedActionList,
ServiceDescriptor serviceDescriptor)
where TActivatorData : ReflectionActivatorData
{
registrationBuilder.OnActivated(context =>
{
var serviceActivatedContext = new OnServiceActivatedContext(context.Instance!);
foreach (var action in activatedActionList.GetActions(serviceDescriptor))
{
action.Invoke(serviceActivatedContext);
}
});
return registrationBuilder;
}
private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InvokeRegistrationActions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceRegistrationActionList registrationActionList,

@ -183,6 +183,7 @@ public static class AutofacRegistration
{
var moduleContainer = services.GetSingletonInstance<IModuleContainer>();
var registrationActionList = services.GetRegistrationActionList();
var activatedActionList = services.GetServiceActivatedActionList();
foreach (var descriptor in services)
{
@ -196,7 +197,7 @@ public static class AutofacRegistration
.RegisterGeneric(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.ConfigureAbpConventions(moduleContainer, registrationActionList);
.ConfigureAbpConventions(descriptor, moduleContainer, registrationActionList, activatedActionList);
}
else
{
@ -204,7 +205,7 @@ public static class AutofacRegistration
.RegisterType(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.ConfigureAbpConventions(moduleContainer, registrationActionList);
.ConfigureAbpConventions(descriptor, moduleContainer, registrationActionList, activatedActionList);
}
}
else if (descriptor.ImplementationFactory != null)

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using Volo.Abp.DependencyInjection;
namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionLifetimeEventExtensions
{
// OnActivated
public static void OnActivated(this IServiceCollection services, ServiceDescriptor descriptor, Action<IOnServiceActivatedContext> onActivatedAction)
{
GetOrCreateOnActivatedActionList(services).Add(new KeyValuePair<ServiceDescriptor, Action<IOnServiceActivatedContext>>(descriptor, onActivatedAction));
}
public static ServiceActivatedActionList GetServiceActivatedActionList(this IServiceCollection services)
{
return GetOrCreateOnActivatedActionList(services);
}
private static ServiceActivatedActionList GetOrCreateOnActivatedActionList(IServiceCollection services)
{
var actionList = services.GetSingletonInstanceOrNull<IObjectAccessor<ServiceActivatedActionList>>()?.Value;
if (actionList == null)
{
actionList = new ServiceActivatedActionList();
services.AddObjectAccessor(actionList);
}
return actionList;
}
}

@ -0,0 +1,6 @@
namespace Volo.Abp.DependencyInjection;
public interface IOnServiceActivatedContext
{
public object Instance { get; }
}

@ -0,0 +1,11 @@
namespace Volo.Abp.DependencyInjection;
public class OnServiceActivatedContext : IOnServiceActivatedContext
{
public object Instance { get; set; }
public OnServiceActivatedContext(object instance)
{
Instance = instance;
}
}

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.DependencyInjection;
public class ServiceActivatedActionList : List<KeyValuePair<ServiceDescriptor, Action<IOnServiceActivatedContext>>>
{
public List<Action<IOnServiceActivatedContext>> GetActions(ServiceDescriptor descriptor)
{
return this.Where(x => x.Key == descriptor).Select(x => x.Value).ToList();
}
}

@ -84,22 +84,16 @@ public static class ServiceCollectionRepositoryExtensions
bool replaceExisting,
bool isReadOnlyRepository = false)
{
ServiceDescriptor descriptor;
var descriptor = ServiceDescriptor.Transient(serviceType, implementationType);
if (isReadOnlyRepository)
{
services.TryAddTransient(implementationType);
descriptor = ServiceDescriptor.Transient(serviceType, provider =>
services.OnActivated(descriptor, context =>
{
var repository = provider.GetRequiredService(implementationType);
var repository = context.Instance.As<IRepository>();
ObjectHelper.TrySetProperty(repository.As<IRepository>(), x => x.IsChangeTrackingEnabled, _ => false);
return repository;
});
}
else
{
descriptor = ServiceDescriptor.Transient(serviceType, implementationType);
}
if (replaceExisting)
{

@ -0,0 +1,39 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Autofac.Interception;
using Xunit;
namespace Volo.Abp.Autofac;
public class AutoFac_OnActivated_Tests : Autofac_Interception_Test
{
protected override Task AfterAddApplicationAsync(IServiceCollection services)
{
var serviceDescriptor = ServiceDescriptor.Transient<MyServer, MyServer>();
services.Add(serviceDescriptor);
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().Name += "1";
});
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().Name += "2";
});
return base.AfterAddApplicationAsync(services);
}
[Fact]
public void Should_Call_OnActivated()
{
var server = ServiceProvider.GetRequiredService<MyServer>();
server.Name.ShouldBe("MyServer12");
}
}
class MyServer
{
public string Name { get; set; } = "MyServer";
}

@ -31,15 +31,15 @@ public class RepositoryRegistration_Tests
//Assert
//MyTestAggregateRootWithoutPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
@ -69,24 +69,24 @@ public class RepositoryRegistration_Tests
//Assert
//MyTestAggregateRootWithoutPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
//MyTestEntityWithInt32Pk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IReadOnlyBasicRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
}
@ -114,20 +114,20 @@ public class RepositoryRegistration_Tests
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithoutPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithoutPk>));
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IReadOnlyBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
//MyTestEntityWithInt32Pk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IRepository<MyTestEntityWithInt32Pk>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IReadOnlyBasicRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
services.ShouldContainTransient(typeof(IRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestDefaultRepository<MyTestEntityWithInt32Pk, int>));
}
@ -209,10 +209,10 @@ public class RepositoryRegistration_Tests
services.ShouldNotContainService(typeof(IRepository<MyTestAggregateRootWithoutPk>));
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
}
@ -234,11 +234,11 @@ public class RepositoryRegistration_Tests
new MyTestRepositoryRegistrar(options).AddRepositories();
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransientImplementationFactory(typeof(IReadOnlyBasicRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IReadOnlyBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
}

Loading…
Cancel
Save