mirror of https://github.com/abpframework/abp.git
Browse Source
- Upgrade Autofac from 8.4.0 to 9.1.0 - Upgrade Autofac.Extensions.DependencyInjection from 10.0.0 to 11.0.0 - Upgrade Microsoft.Bcl.AsyncInterfaces from 10.0.2 to 10.0.4 - Remove AnyKeyRegistrationSource (now native in Autofac 9.1.0) - Add MSDI KeyedService.AnyKey to Autofac KeyedService.AnyKey translation - Use Parameters.KeyedServiceKey<object>() for keyed factory key retrieval - Add ExternallyOwned() to instance registrations - Add unit tests for keyed services and AnyKey supportpull/25190/head
3 changed files with 169 additions and 10 deletions
@ -0,0 +1,157 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Testing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Autofac; |
||||
|
|
||||
|
public class AutofacRegistration_Tests : AbpIntegratedTest<AutofacRegistration_Tests.TestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Resolve_AnyKey_Keyed_Service_With_Any_Key() |
||||
|
{ |
||||
|
// AnyKey registration should be resolvable with any key value.
|
||||
|
var serviceWithKeyA = GetRequiredKeyedService<IAnyKeyService>("keyA"); |
||||
|
var serviceWithKeyB = GetRequiredKeyedService<IAnyKeyService>("keyB"); |
||||
|
var serviceWithKeyC = GetRequiredKeyedService<IAnyKeyService>(42); |
||||
|
|
||||
|
serviceWithKeyA.ShouldNotBeNull(); |
||||
|
serviceWithKeyB.ShouldNotBeNull(); |
||||
|
serviceWithKeyC.ShouldNotBeNull(); |
||||
|
|
||||
|
serviceWithKeyA.ShouldBeOfType<AnyKeyServiceImpl>(); |
||||
|
serviceWithKeyB.ShouldBeOfType<AnyKeyServiceImpl>(); |
||||
|
serviceWithKeyC.ShouldBeOfType<AnyKeyServiceImpl>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Pass_Correct_Key_To_Keyed_Factory() |
||||
|
{ |
||||
|
var serviceA = GetRequiredKeyedService<IKeyedFactoryService>("alpha"); |
||||
|
var serviceB = GetRequiredKeyedService<IKeyedFactoryService>("beta"); |
||||
|
|
||||
|
serviceA.Key.ShouldBe("alpha"); |
||||
|
serviceB.Key.ShouldBe("beta"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Not_Dispose_Instance_Registration_When_Scope_Disposed() |
||||
|
{ |
||||
|
// Resolve the pre-registered singleton instance.
|
||||
|
var instance = GetRequiredKeyedService<IDisposableInstance>("instance"); |
||||
|
instance.ShouldNotBeNull(); |
||||
|
instance.IsDisposed.ShouldBeFalse(); |
||||
|
|
||||
|
// The same instance should be returned from a child scope.
|
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var scopedInstance = scope.ServiceProvider.GetRequiredKeyedService<IDisposableInstance>("instance"); |
||||
|
scopedInstance.ShouldBeSameAs(instance); |
||||
|
} |
||||
|
|
||||
|
// After the scope is disposed, the singleton instance should still be alive.
|
||||
|
instance.IsDisposed.ShouldBeFalse(); |
||||
|
|
||||
|
// It should also be the same static instance registered in the module.
|
||||
|
instance.ShouldBeSameAs(TestModule.DisposableInstanceForTest); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Resolve_Standard_Keyed_Services() |
||||
|
{ |
||||
|
var big = GetRequiredKeyedService<ITypedCache>("big"); |
||||
|
var small = GetRequiredKeyedService<ITypedCache>("small"); |
||||
|
|
||||
|
big.ShouldBeOfType<BigTypedCache>(); |
||||
|
small.ShouldBeOfType<SmallTypedCache>(); |
||||
|
|
||||
|
big.Get("test").ShouldBe("big:test"); |
||||
|
small.Get("test").ShouldBe("small:test"); |
||||
|
} |
||||
|
|
||||
|
[DependsOn(typeof(AbpAutofacModule))] |
||||
|
public class TestModule : AbpModule |
||||
|
{ |
||||
|
public static DisposableInstance DisposableInstanceForTest { get; } = new(); |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
// AnyKey registration: this service can be resolved with any key.
|
||||
|
context.Services.AddKeyedTransient<IAnyKeyService, AnyKeyServiceImpl>( |
||||
|
Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey); |
||||
|
|
||||
|
// Keyed factory registration: the factory receives the actual key used for resolution.
|
||||
|
context.Services.Add(ServiceDescriptor.KeyedTransient<IKeyedFactoryService>( |
||||
|
Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey, |
||||
|
(sp, key) => new KeyedFactoryServiceImpl(key))); |
||||
|
|
||||
|
// Instance registration with keyed service (ExternallyOwned should prevent Autofac from disposing it).
|
||||
|
context.Services.AddKeyedSingleton<IDisposableInstance>("instance", DisposableInstanceForTest); |
||||
|
|
||||
|
// Standard keyed type registrations.
|
||||
|
context.Services.AddKeyedTransient<ITypedCache, BigTypedCache>("big"); |
||||
|
context.Services.AddKeyedTransient<ITypedCache, SmallTypedCache>("small"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public interface IAnyKeyService |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class AnyKeyServiceImpl : IAnyKeyService |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public interface IKeyedFactoryService |
||||
|
{ |
||||
|
object Key { get; } |
||||
|
} |
||||
|
|
||||
|
public class KeyedFactoryServiceImpl : IKeyedFactoryService |
||||
|
{ |
||||
|
public object Key { get; } |
||||
|
|
||||
|
public KeyedFactoryServiceImpl(object key) |
||||
|
{ |
||||
|
Key = key; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public interface IDisposableInstance |
||||
|
{ |
||||
|
bool IsDisposed { get; } |
||||
|
} |
||||
|
|
||||
|
public class DisposableInstance : IDisposableInstance, IDisposable |
||||
|
{ |
||||
|
public bool IsDisposed { get; private set; } |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
IsDisposed = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public interface ITypedCache |
||||
|
{ |
||||
|
string Get(string key); |
||||
|
} |
||||
|
|
||||
|
public class BigTypedCache : ITypedCache |
||||
|
{ |
||||
|
public string Get(string key) => $"big:{key}"; |
||||
|
} |
||||
|
|
||||
|
public class SmallTypedCache : ITypedCache |
||||
|
{ |
||||
|
public string Get(string key) => $"small:{key}"; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue