Browse Source

Upgrade Autofac.Extensions.DependencyInjection to 11.0.0

- 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 support
pull/25190/head
maliming 2 months ago
parent
commit
1d28bab085
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 6
      Directory.Packages.props
  2. 16
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs
  3. 157
      framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutofacRegistration_Tests.cs

6
Directory.Packages.props

@ -7,8 +7,8 @@
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.0.0" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.3" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageVersion Include="Autofac" Version="8.4.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Autofac" Version="9.1.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="11.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageVersion Include="AutoMapper" Version="14.0.0" />
<PackageVersion Include="Asp.Versioning.Mvc" Version="8.1.0" />
@ -76,7 +76,7 @@
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="10.0.2" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="10.0.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.2" />

16
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs

@ -119,7 +119,6 @@ public static class AutofacRegistration
.SingleInstance();
// Shims for keyed service compatibility.
builder.RegisterSource<AnyKeyRegistrationSource>();
builder.ComponentRegistryBuilder.Registered += AddFromKeyedServiceParameterMiddleware;
Register(builder, services, lifetimeScopeTagForSingletons);
@ -212,11 +211,15 @@ public static class AutofacRegistration
this IRegistrationBuilder<object, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceDescriptor descriptor)
{
// If it's keyed, the service key won't be null. A null key results in it _not_ being a keyed service.
if (descriptor.IsKeyedService)
{
var key = descriptor.ServiceKey!;
if (key.Equals(Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey))
{
key = Autofac.Core.KeyedService.AnyKey;
}
// If it's keyed, the service key won't be null. A null key results in it _not_ being a keyed service.
registrationBuilder.Keyed(key, descriptor.ServiceType);
}
else
@ -335,8 +338,7 @@ public static class AutofacRegistration
var serviceProvider = context.Resolve<IServiceProvider>();
var keyedService = (Autofac.Core.KeyedService)requestContext.Service;
var key = keyedService.ServiceKey;
var key = requestContext.Parameters.KeyedServiceKey<object>();
return descriptor.KeyedImplementationFactory(serviceProvider, key);
})
@ -349,8 +351,7 @@ public static class AutofacRegistration
continue;
}
if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null)
else if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null)
{
var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) =>
{
@ -371,7 +372,8 @@ public static class AutofacRegistration
builder
.RegisterInstance(descriptor.NormalizedImplementationInstance()!)
.ConfigureServiceType(descriptor)
.ConfigureLifecycle(descriptor.Lifetime, null);
.ConfigureLifecycle(descriptor.Lifetime, null)
.ExternallyOwned();
}
}
}

157
framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutofacRegistration_Tests.cs

@ -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…
Cancel
Save