Skip to content

Commit 1d28bab

Browse files
committed
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
1 parent d74759c commit 1d28bab

3 files changed

Lines changed: 169 additions & 10 deletions

File tree

Directory.Packages.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.0.0" />
88
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.3" />
99
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
10-
<PackageVersion Include="Autofac" Version="8.4.0" />
11-
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
10+
<PackageVersion Include="Autofac" Version="9.1.0" />
11+
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="11.0.0" />
1212
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
1313
<PackageVersion Include="AutoMapper" Version="14.0.0" />
1414
<PackageVersion Include="Asp.Versioning.Mvc" Version="8.1.0" />
@@ -76,7 +76,7 @@
7676
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
7777
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="10.0.2" />
7878
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="10.0.2" />
79-
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.2" />
79+
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.4" />
8080
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
8181
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
8282
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.2" />

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ public static void Populate(
119119
.SingleInstance();
120120

121121
// Shims for keyed service compatibility.
122-
builder.RegisterSource<AnyKeyRegistrationSource>();
123122
builder.ComponentRegistryBuilder.Registered += AddFromKeyedServiceParameterMiddleware;
124123

125124
Register(builder, services, lifetimeScopeTagForSingletons);
@@ -212,11 +211,15 @@ private static IRegistrationBuilder<object, TActivatorData, TRegistrationStyle>
212211
this IRegistrationBuilder<object, TActivatorData, TRegistrationStyle> registrationBuilder,
213212
ServiceDescriptor descriptor)
214213
{
214+
// If it's keyed, the service key won't be null. A null key results in it _not_ being a keyed service.
215215
if (descriptor.IsKeyedService)
216216
{
217217
var key = descriptor.ServiceKey!;
218+
if (key.Equals(Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey))
219+
{
220+
key = Autofac.Core.KeyedService.AnyKey;
221+
}
218222

219-
// If it's keyed, the service key won't be null. A null key results in it _not_ being a keyed service.
220223
registrationBuilder.Keyed(key, descriptor.ServiceType);
221224
}
222225
else
@@ -335,8 +338,7 @@ private static void Register(
335338
var serviceProvider = context.Resolve<IServiceProvider>();
336339

337340
var keyedService = (Autofac.Core.KeyedService)requestContext.Service;
338-
339-
var key = keyedService.ServiceKey;
341+
var key = requestContext.Parameters.KeyedServiceKey<object>();
340342

341343
return descriptor.KeyedImplementationFactory(serviceProvider, key);
342344
})
@@ -349,8 +351,7 @@ private static void Register(
349351

350352
continue;
351353
}
352-
353-
if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null)
354+
else if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null)
354355
{
355356
var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) =>
356357
{
@@ -371,7 +372,8 @@ private static void Register(
371372
builder
372373
.RegisterInstance(descriptor.NormalizedImplementationInstance()!)
373374
.ConfigureServiceType(descriptor)
374-
.ConfigureLifecycle(descriptor.Lifetime, null);
375+
.ConfigureLifecycle(descriptor.Lifetime, null)
376+
.ExternallyOwned();
375377
}
376378
}
377379
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Shouldly;
5+
using Volo.Abp.Modularity;
6+
using Volo.Abp.Testing;
7+
using Xunit;
8+
9+
namespace Volo.Abp.Autofac;
10+
11+
public class AutofacRegistration_Tests : AbpIntegratedTest<AutofacRegistration_Tests.TestModule>
12+
{
13+
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
14+
{
15+
options.UseAutofac();
16+
}
17+
18+
[Fact]
19+
public void Should_Resolve_AnyKey_Keyed_Service_With_Any_Key()
20+
{
21+
// AnyKey registration should be resolvable with any key value.
22+
var serviceWithKeyA = GetRequiredKeyedService<IAnyKeyService>("keyA");
23+
var serviceWithKeyB = GetRequiredKeyedService<IAnyKeyService>("keyB");
24+
var serviceWithKeyC = GetRequiredKeyedService<IAnyKeyService>(42);
25+
26+
serviceWithKeyA.ShouldNotBeNull();
27+
serviceWithKeyB.ShouldNotBeNull();
28+
serviceWithKeyC.ShouldNotBeNull();
29+
30+
serviceWithKeyA.ShouldBeOfType<AnyKeyServiceImpl>();
31+
serviceWithKeyB.ShouldBeOfType<AnyKeyServiceImpl>();
32+
serviceWithKeyC.ShouldBeOfType<AnyKeyServiceImpl>();
33+
}
34+
35+
[Fact]
36+
public void Should_Pass_Correct_Key_To_Keyed_Factory()
37+
{
38+
var serviceA = GetRequiredKeyedService<IKeyedFactoryService>("alpha");
39+
var serviceB = GetRequiredKeyedService<IKeyedFactoryService>("beta");
40+
41+
serviceA.Key.ShouldBe("alpha");
42+
serviceB.Key.ShouldBe("beta");
43+
}
44+
45+
[Fact]
46+
public void Should_Not_Dispose_Instance_Registration_When_Scope_Disposed()
47+
{
48+
// Resolve the pre-registered singleton instance.
49+
var instance = GetRequiredKeyedService<IDisposableInstance>("instance");
50+
instance.ShouldNotBeNull();
51+
instance.IsDisposed.ShouldBeFalse();
52+
53+
// The same instance should be returned from a child scope.
54+
using (var scope = ServiceProvider.CreateScope())
55+
{
56+
var scopedInstance = scope.ServiceProvider.GetRequiredKeyedService<IDisposableInstance>("instance");
57+
scopedInstance.ShouldBeSameAs(instance);
58+
}
59+
60+
// After the scope is disposed, the singleton instance should still be alive.
61+
instance.IsDisposed.ShouldBeFalse();
62+
63+
// It should also be the same static instance registered in the module.
64+
instance.ShouldBeSameAs(TestModule.DisposableInstanceForTest);
65+
}
66+
67+
[Fact]
68+
public void Should_Resolve_Standard_Keyed_Services()
69+
{
70+
var big = GetRequiredKeyedService<ITypedCache>("big");
71+
var small = GetRequiredKeyedService<ITypedCache>("small");
72+
73+
big.ShouldBeOfType<BigTypedCache>();
74+
small.ShouldBeOfType<SmallTypedCache>();
75+
76+
big.Get("test").ShouldBe("big:test");
77+
small.Get("test").ShouldBe("small:test");
78+
}
79+
80+
[DependsOn(typeof(AbpAutofacModule))]
81+
public class TestModule : AbpModule
82+
{
83+
public static DisposableInstance DisposableInstanceForTest { get; } = new();
84+
85+
public override void ConfigureServices(ServiceConfigurationContext context)
86+
{
87+
// AnyKey registration: this service can be resolved with any key.
88+
context.Services.AddKeyedTransient<IAnyKeyService, AnyKeyServiceImpl>(
89+
Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey);
90+
91+
// Keyed factory registration: the factory receives the actual key used for resolution.
92+
context.Services.Add(ServiceDescriptor.KeyedTransient<IKeyedFactoryService>(
93+
Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey,
94+
(sp, key) => new KeyedFactoryServiceImpl(key)));
95+
96+
// Instance registration with keyed service (ExternallyOwned should prevent Autofac from disposing it).
97+
context.Services.AddKeyedSingleton<IDisposableInstance>("instance", DisposableInstanceForTest);
98+
99+
// Standard keyed type registrations.
100+
context.Services.AddKeyedTransient<ITypedCache, BigTypedCache>("big");
101+
context.Services.AddKeyedTransient<ITypedCache, SmallTypedCache>("small");
102+
}
103+
}
104+
105+
public interface IAnyKeyService
106+
{
107+
}
108+
109+
public class AnyKeyServiceImpl : IAnyKeyService
110+
{
111+
}
112+
113+
public interface IKeyedFactoryService
114+
{
115+
object Key { get; }
116+
}
117+
118+
public class KeyedFactoryServiceImpl : IKeyedFactoryService
119+
{
120+
public object Key { get; }
121+
122+
public KeyedFactoryServiceImpl(object key)
123+
{
124+
Key = key;
125+
}
126+
}
127+
128+
public interface IDisposableInstance
129+
{
130+
bool IsDisposed { get; }
131+
}
132+
133+
public class DisposableInstance : IDisposableInstance, IDisposable
134+
{
135+
public bool IsDisposed { get; private set; }
136+
137+
public void Dispose()
138+
{
139+
IsDisposed = true;
140+
}
141+
}
142+
143+
public interface ITypedCache
144+
{
145+
string Get(string key);
146+
}
147+
148+
public class BigTypedCache : ITypedCache
149+
{
150+
public string Get(string key) => $"big:{key}";
151+
}
152+
153+
public class SmallTypedCache : ITypedCache
154+
{
155+
public string Get(string key) => $"small:{key}";
156+
}
157+
}

0 commit comments

Comments
 (0)