Skip to content

Commit 703c103

Browse files
authored
Merge pull request #9 from autofac/develop
merge
2 parents 9cf36f6 + 9eee0ea commit 703c103

22 files changed

+712
-49
lines changed

src/Autofac/Autofac.csproj

+17-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<Description>Autofac is an IoC container for Microsoft .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity.</Description>
55
<VersionPrefix>5.0.0</VersionPrefix>
6-
<TargetFrameworks>netstandard2.0;netstandard1.1;net45</TargetFrameworks>
6+
<TargetFrameworks>netstandard2.1;netstandard2.0;net461</TargetFrameworks>
77
<LangVersion>latest</LangVersion>
88
<NoWarn>$(NoWarn);CS1591;IDE0008</NoWarn>
99
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@@ -50,8 +50,12 @@
5050
</PackageReference>
5151
</ItemGroup>
5252

53-
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
54-
<PackageReference Include="System.ComponentModel" Version="4.0.1" />
53+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net461' ">
54+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.1.0-preview1.19504.10" />
55+
</ItemGroup>
56+
57+
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
58+
<Reference Include="System.ComponentModel.Composition" />
5559
</ItemGroup>
5660

5761
<ItemGroup>
@@ -150,10 +154,15 @@
150154
<AutoGen>True</AutoGen>
151155
<DependentUpon>ResolveOperationResources.resx</DependentUpon>
152156
</Compile>
153-
<Compile Update="Core\ServiceResources.Designer.cs">
157+
<Compile Update="Core\DisposerResources.Designer.cs">
158+
<DependentUpon>DisposerResources.resx</DependentUpon>
154159
<DesignTime>True</DesignTime>
155160
<AutoGen>True</AutoGen>
161+
</Compile>
162+
<Compile Update="Core\ServiceResources.Designer.cs">
156163
<DependentUpon>ServiceResources.resx</DependentUpon>
164+
<DesignTime>True</DesignTime>
165+
<AutoGen>True</AutoGen>
157166
</Compile>
158167
<Compile Update="Features\Collections\CollectionRegistrationSourceResources.Designer.cs">
159168
<DesignTime>True</DesignTime>
@@ -334,6 +343,10 @@
334343
<Generator>ResXFileCodeGenerator</Generator>
335344
<LastGenOutput>ResolveOperationResources.Designer.cs</LastGenOutput>
336345
</EmbeddedResource>
346+
<EmbeddedResource Update="Core\DisposerResources.resx">
347+
<LastGenOutput>DisposerResources.Designer.cs</LastGenOutput>
348+
<Generator>ResXFileCodeGenerator</Generator>
349+
</EmbeddedResource>
337350
<EmbeddedResource Update="Core\ServiceResources.resx">
338351
<Generator>ResXFileCodeGenerator</Generator>
339352
<LastGenOutput>ServiceResources.Designer.cs</LastGenOutput>

src/Autofac/Core/Container.cs

+15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using System.Collections.Generic;
2828
using System.Diagnostics;
2929
using System.Diagnostics.CodeAnalysis;
30+
using System.Threading.Tasks;
3031
using Autofac.Core.Activators.Delegate;
3132
using Autofac.Core.Lifetime;
3233
using Autofac.Core.Registration;
@@ -178,6 +179,20 @@ protected override void Dispose(bool disposing)
178179
base.Dispose(disposing);
179180
}
180181

182+
protected override async ValueTask DisposeAsync(bool disposing)
183+
{
184+
if (disposing)
185+
{
186+
await _rootLifetimeScope.DisposeAsync();
187+
188+
// Registries are not likely to have async tasks to dispose of,
189+
// so we will leave it as a straight dispose.
190+
ComponentRegistry.Dispose();
191+
}
192+
193+
// Do not call the base, otherwise the standard Dispose will fire.
194+
}
195+
181196
/// <summary>
182197
/// Gets the service object of the specified type.
183198
/// </summary>

src/Autofac/Core/DependencyResolutionException.cs

-6
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
// OTHER DEALINGS IN THE SOFTWARE.
2525

2626
using System;
27-
#if !NETSTANDARD1_1
2827
using System.Runtime.Serialization;
29-
#endif
3028

3129
namespace Autofac.Core
3230
{
@@ -36,17 +34,13 @@ namespace Autofac.Core
3634
/// been made during the operation. For example, 'on activated' handlers may have already been
3735
/// fired, or 'single instance' components partially constructed.
3836
/// </summary>
39-
#if !NETSTANDARD1_1
4037
[Serializable]
41-
#endif
4238
public class DependencyResolutionException : Exception
4339
{
44-
#if !NETSTANDARD1_1
4540
protected DependencyResolutionException(SerializationInfo info, StreamingContext context)
4641
: base(info, context)
4742
{
4843
}
49-
#endif
5044

5145
/// <summary>
5246
/// Initializes a new instance of the <see cref="DependencyResolutionException" /> class.

src/Autofac/Core/Disposer.cs

+106-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
using System;
2727
using System.Collections.Generic;
28+
using System.Threading;
29+
using System.Threading.Tasks;
2830
using Autofac.Util;
2931

3032
namespace Autofac.Core
@@ -36,11 +38,13 @@ namespace Autofac.Core
3638
internal class Disposer : Disposable, IDisposer
3739
{
3840
/// <summary>
39-
/// Contents all implement IDisposable.
41+
/// Contents all implement IDisposable or IAsyncDisposable.
4042
/// </summary>
41-
private Stack<IDisposable> _items = new Stack<IDisposable>();
43+
private Stack<object> _items = new Stack<object>();
4244

43-
private readonly object _synchRoot = new object();
45+
// Need to use a semaphore instead of a simple object to lock on, because
46+
// we need to synchronise an awaitable block.
47+
private SemaphoreSlim _synchRoot = new SemaphoreSlim(1, 1);
4448

4549
/// <summary>
4650
/// Releases unmanaged and - optionally - managed resources.
@@ -50,32 +54,128 @@ protected override void Dispose(bool disposing)
5054
{
5155
if (disposing)
5256
{
53-
lock (_synchRoot)
57+
_synchRoot.Wait();
58+
try
5459
{
5560
while (_items.Count > 0)
5661
{
5762
var item = _items.Pop();
58-
item.Dispose();
63+
64+
// If we are in synchronous dispose, and an object implements IDisposable,
65+
// then use it.
66+
if (item is IDisposable disposable)
67+
{
68+
disposable.Dispose();
69+
}
70+
else
71+
{
72+
// Type only implements IAsyncDisposable, which is not valid if there
73+
// is a synchronous dispose being done.
74+
throw new InvalidOperationException(string.Format(
75+
DisposerResources.Culture,
76+
DisposerResources.TypeOnlyImplementsIAsyncDisposable,
77+
item.GetType().FullName));
78+
}
5979
}
6080

6181
_items = null;
6282
}
83+
finally
84+
{
85+
_synchRoot.Release();
86+
87+
// We don't need the semaphore any more.
88+
_synchRoot.Dispose();
89+
}
6390
}
6491

6592
base.Dispose(disposing);
6693
}
6794

95+
protected override async ValueTask DisposeAsync(bool disposing)
96+
{
97+
if (disposing)
98+
{
99+
// Acquire our semaphore.
100+
await _synchRoot.WaitAsync().ConfigureAwait(false);
101+
try
102+
{
103+
while (_items.Count > 0)
104+
{
105+
var item = _items.Pop();
106+
107+
// If the item implements IAsyncDisposable we will call its DisposeAsync Method.
108+
if (item is IAsyncDisposable asyncDisposable)
109+
{
110+
var vt = asyncDisposable.DisposeAsync();
111+
112+
// Don't await if it's already completed (this is a slight gain in performance of using ValueTask).
113+
if (!vt.IsCompletedSuccessfully)
114+
{
115+
await vt.ConfigureAwait(false);
116+
}
117+
}
118+
else if (item is IDisposable disposable)
119+
{
120+
// Call the standard Dispose.
121+
disposable.Dispose();
122+
}
123+
}
124+
125+
_items = null;
126+
}
127+
finally
128+
{
129+
_synchRoot.Release();
130+
131+
// We don't need the semaphore any more.
132+
_synchRoot.Dispose();
133+
}
134+
}
135+
}
136+
137+
/// <summary>
138+
/// Adds an object to the disposer, where that object only implements IAsyncDisposable. When the disposer is
139+
/// disposed, so will the object be.
140+
/// This is not typically recommended, and you should implement IDisposable as well.
141+
/// </summary>
142+
/// <param name="instance">The instance.</param>
143+
/// <remarks>
144+
/// If this Disposer is disposed of using a synchronous Dispose call, that call will throw an exception.
145+
/// </remarks>
146+
public void AddInstanceForAsyncDisposal(IAsyncDisposable instance)
147+
{
148+
AddInternal(instance);
149+
}
150+
68151
/// <summary>
69152
/// Adds an object to the disposer. When the disposer is
70153
/// disposed, so will the object be.
71154
/// </summary>
72155
/// <param name="instance">The instance.</param>
73156
public void AddInstanceForDisposal(IDisposable instance)
157+
{
158+
AddInternal(instance);
159+
}
160+
161+
private void AddInternal(object instance)
74162
{
75163
if (instance == null) throw new ArgumentNullException(nameof(instance));
76164

77-
lock (_synchRoot)
165+
if (IsDisposed)
166+
{
167+
throw new ObjectDisposedException(nameof(Disposer), DisposerResources.CannotAddToDisposedDisposer);
168+
}
169+
170+
_synchRoot.Wait();
171+
try
172+
{
78173
_items.Push(instance);
174+
}
175+
finally
176+
{
177+
_synchRoot.Release();
178+
}
79179
}
80180
}
81181
}

src/Autofac/Core/DisposerResources.Designer.cs

+82
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)