diff --git a/.vscode/settings.json b/.vscode/settings.json index 0a8ba99..f7754b1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { + "cSpell.words": [ + "autofac", + "xunit" + ], "omnisharp.enableEditorConfigSupport": true } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2354883..70e1c3b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,21 +1,9 @@ { "tasks": [ - { - "args": [ - "watch", - "run", - "${workspaceFolder}/test/Autofac.Pooling.Tests/Autofac.Pooling.Tests.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "command": "dotnet", - "label": "watch", - "problemMatcher": "$msCompile", - "type": "process" - }, { "args": [ "build", + "Autofac.Pooling.sln", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 341027f..0000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/build/Source.ruleset b/build/Source.ruleset index 459e4e0..8994858 100644 --- a/build/Source.ruleset +++ b/build/Source.ruleset @@ -1,9 +1,11 @@ - - + + - - + + + + @@ -12,23 +14,45 @@ - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/Test.ruleset b/build/Test.ruleset index 3c26c01..b64a37a 100644 --- a/build/Test.ruleset +++ b/build/Test.ruleset @@ -1,16 +1,14 @@ - - + + - - - - + + - - - + - + + + @@ -20,37 +18,93 @@ - - - + - + - - - + + + + + - + - + - + + + - + - + - + - + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -58,11 +112,11 @@ - + - + - + @@ -82,6 +136,13 @@ + + + + + + + diff --git a/src/Autofac.Pooling/Autofac.Pooling.csproj b/src/Autofac.Pooling/Autofac.Pooling.csproj index 1e71b41..7954479 100644 --- a/src/Autofac.Pooling/Autofac.Pooling.csproj +++ b/src/Autofac.Pooling/Autofac.Pooling.csproj @@ -8,6 +8,8 @@ ../../Autofac.snk true ../../build/Source.ruleset + AllEnabledByDefault + true false false false @@ -32,27 +34,29 @@ true $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - + + + - - - All All + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - True @@ -70,7 +74,6 @@ RegistrationExtensionsResources.resx - ResXFileCodeGenerator @@ -85,5 +88,4 @@ RegistrationExtensionsResources.Designer.cs - diff --git a/src/Autofac.Pooling/AutofacPooledObjectPolicy.cs b/src/Autofac.Pooling/AutofacPooledObjectPolicy.cs index 8665959..8b202c4 100644 --- a/src/Autofac.Pooling/AutofacPooledObjectPolicy.cs +++ b/src/Autofac.Pooling/AutofacPooledObjectPolicy.cs @@ -10,7 +10,7 @@ namespace Autofac.Pooling; /// Provides the needed for creating/returning objects in the pool in an Autofac way. /// /// The type of object being pooled. -internal class AutofacPooledObjectPolicy : IPooledObjectPolicy +internal sealed class AutofacPooledObjectPolicy : IPooledObjectPolicy where TPooledObject : class { private readonly Service _poolInstanceService; diff --git a/src/Autofac.Pooling/PoolService.cs b/src/Autofac.Pooling/PoolService.cs index 358cb76..1faae61 100644 --- a/src/Autofac.Pooling/PoolService.cs +++ b/src/Autofac.Pooling/PoolService.cs @@ -11,7 +11,7 @@ namespace Autofac.Pooling; /// /// Defines a service used to access an , ensuring that each pooled item registration gets a different pool. /// -internal class PoolService : Service, IEquatable +internal sealed class PoolService : Service, IEquatable { private readonly IComponentRegistration _pooledItemRegistration; diff --git a/src/Autofac.Pooling/PooledLifetime.cs b/src/Autofac.Pooling/PooledLifetime.cs index bfed629..4398da7 100644 --- a/src/Autofac.Pooling/PooledLifetime.cs +++ b/src/Autofac.Pooling/PooledLifetime.cs @@ -8,6 +8,7 @@ namespace Autofac.Pooling; /// /// Lifetime wrapper to help us detect if we finished registering in a pooled configuration. /// +[SuppressMessage("S2094", "S2094", Justification = "Lifetimes are classes, not interfaces. Changing this would be a breaking change.")] public class PooledLifetime : CurrentScopeLifetime { } diff --git a/test/Autofac.Pooling.Test/Autofac.Pooling.Test.csproj b/test/Autofac.Pooling.Test/Autofac.Pooling.Test.csproj index f67c43d..83c24e7 100644 --- a/test/Autofac.Pooling.Test/Autofac.Pooling.Test.csproj +++ b/test/Autofac.Pooling.Test/Autofac.Pooling.Test.csproj @@ -2,8 +2,13 @@ net10.0 ../../build/Test.ruleset + AllEnabledByDefault + true false + + + all @@ -15,6 +20,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/test/Autofac.Pooling.Test/Shared/IPooledService.cs b/test/Autofac.Pooling.Test/Common/IPooledService.cs similarity index 80% rename from test/Autofac.Pooling.Test/Shared/IPooledService.cs rename to test/Autofac.Pooling.Test/Common/IPooledService.cs index 144234e..951e569 100644 --- a/test/Autofac.Pooling.Test/Shared/IPooledService.cs +++ b/test/Autofac.Pooling.Test/Common/IPooledService.cs @@ -1,4 +1,4 @@ -namespace Autofac.Pooling.Tests.Shared; +namespace Autofac.Pooling.Tests.Common; public interface IPooledService { diff --git a/test/Autofac.Pooling.Test/Common/OtherPooledComponent.cs b/test/Autofac.Pooling.Test/Common/OtherPooledComponent.cs new file mode 100644 index 0000000..edbf163 --- /dev/null +++ b/test/Autofac.Pooling.Test/Common/OtherPooledComponent.cs @@ -0,0 +1,10 @@ +namespace Autofac.Pooling.Tests.Common; + +public class OtherPooledComponent : IPooledService +{ + public int GetCalled => 0; + + public int ReturnCalled => 0; + + public int DisposeCalled => 0; +} diff --git a/test/Autofac.Pooling.Test/Shared/PoolTrackingPolicy.cs b/test/Autofac.Pooling.Test/Common/PoolTrackingPolicy.cs similarity index 86% rename from test/Autofac.Pooling.Test/Shared/PoolTrackingPolicy.cs rename to test/Autofac.Pooling.Test/Common/PoolTrackingPolicy.cs index 2365abe..7fa7cb3 100644 --- a/test/Autofac.Pooling.Test/Shared/PoolTrackingPolicy.cs +++ b/test/Autofac.Pooling.Test/Common/PoolTrackingPolicy.cs @@ -3,7 +3,7 @@ using System.Threading; using Autofac.Core; -namespace Autofac.Pooling.Tests.Shared; +namespace Autofac.Pooling.Tests.Common; public class PoolTrackingPolicy : DefaultPooledRegistrationPolicy where TLimit : class @@ -14,6 +14,8 @@ public class PoolTrackingPolicy : DefaultPooledRegistrationPolicy parameters, Func getFromPool) { + ArgumentNullException.ThrowIfNull(getFromPool); + Interlocked.Increment(ref _outOfPool); return getFromPool(); diff --git a/test/Autofac.Pooling.Test/Shared/PooledComponent.cs b/test/Autofac.Pooling.Test/Common/PooledComponent.cs similarity index 61% rename from test/Autofac.Pooling.Test/Shared/PooledComponent.cs rename to test/Autofac.Pooling.Test/Common/PooledComponent.cs index 5791620..ffbed02 100644 --- a/test/Autofac.Pooling.Test/Shared/PooledComponent.cs +++ b/test/Autofac.Pooling.Test/Common/PooledComponent.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using Autofac.Core; -namespace Autofac.Pooling.Tests.Shared; +namespace Autofac.Pooling.Tests.Common; +[SuppressMessage("CA1063", "CA1063", Justification = "Dispose remains simple here for testing.")] public class PooledComponent : IPooledService, IPooledComponent, IDisposable { public int GetCalled @@ -21,7 +22,7 @@ public int DisposeCalled get; private set; } - public void OnGetFromPool(IComponentContext ctxt, IEnumerable parameters) + public void OnGetFromPool(IComponentContext context, IEnumerable parameters) { GetCalled++; } @@ -31,6 +32,7 @@ public void OnReturnToPool() ReturnCalled++; } + [SuppressMessage("CA1063", "CA1063", Justification = "Dispose remains simple here for testing.")] public void Dispose() { DisposeCalled++; diff --git a/test/Autofac.Pooling.Test/ConcurrencyTests.cs b/test/Autofac.Pooling.Test/ConcurrencyTests.cs index 29f5bf5..a73c2e7 100644 --- a/test/Autofac.Pooling.Test/ConcurrencyTests.cs +++ b/test/Autofac.Pooling.Test/ConcurrencyTests.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Autofac.Core; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; @@ -22,14 +22,18 @@ public async Task CanUsePoolConcurrently() var container = builder.Build(); - await Task.WhenAll(Enumerable.Range(0, 2000).Select(i => Task.Run(() => + var exception = await Record.ExceptionAsync(async () => { - using var scope = container.BeginLifetimeScope(); + await Task.WhenAll(Enumerable.Range(0, 2000).Select(i => Task.Run(() => + { + using var scope = container.BeginLifetimeScope(); - scope.Resolve(); - }))); + scope.Resolve(); + }))); - container.Dispose(); + container.Dispose(); + }); + Assert.Null(exception); } [Fact] @@ -37,7 +41,7 @@ public async Task CanUsePoolConcurrentlyWithCustomPolicyToBlockOnMaxUsage() { var builder = new ContainerBuilder(); - var blockingPolicy = new BlockingPolicy(4); + using var blockingPolicy = new BlockingPolicy(4); builder.RegisterType().As() .PooledInstancePerLifetimeScope(blockingPolicy); @@ -56,10 +60,11 @@ await Task.WhenAll(Enumerable.Range(0, 10000).Select(i => Task.Run(() => container.Dispose(); } - private class BlockingPolicy : DefaultPooledRegistrationPolicy + private class BlockingPolicy : DefaultPooledRegistrationPolicy, IDisposable where TLimit : class { private readonly SemaphoreSlim _semaphore; + private bool _disposedValue; public BlockingPolicy(int maxConcurrentInstances) : base(maxConcurrentInstances) { @@ -83,5 +88,25 @@ public override bool Return(TLimit pooledObject) return base.Return(pooledObject); } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + _semaphore.Dispose(); + } + + _disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/test/Autofac.Pooling.Test/DisposableTests.cs b/test/Autofac.Pooling.Test/DisposableTests.cs index cf59a18..d903072 100644 --- a/test/Autofac.Pooling.Test/DisposableTests.cs +++ b/test/Autofac.Pooling.Test/DisposableTests.cs @@ -1,5 +1,5 @@ using Autofac.Features.OwnedInstances; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; diff --git a/test/Autofac.Pooling.Test/ImplicitRelationshipTests.cs b/test/Autofac.Pooling.Test/ImplicitRelationshipTests.cs index e0a81c4..29b2f97 100644 --- a/test/Autofac.Pooling.Test/ImplicitRelationshipTests.cs +++ b/test/Autofac.Pooling.Test/ImplicitRelationshipTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Autofac.Features.Metadata; using Autofac.Features.OwnedInstances; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; @@ -237,7 +237,7 @@ public void CanResolveCollectionOfTwoDifferentPoolsOfSameLimitType() using (var scope1 = container.BeginLifetimeScope()) { - var set = scope1.Resolve>(); + scope1.Resolve>(); // The important point is that each pool goes up by one, meaning that we can track different pools // for the same limit type. diff --git a/test/Autofac.Pooling.Test/LifetimeScopeTests.cs b/test/Autofac.Pooling.Test/LifetimeScopeTests.cs index 3116bed..2a2cc28 100644 --- a/test/Autofac.Pooling.Test/LifetimeScopeTests.cs +++ b/test/Autofac.Pooling.Test/LifetimeScopeTests.cs @@ -1,5 +1,5 @@ using Autofac.Core; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; diff --git a/test/Autofac.Pooling.Test/PolicyTests.cs b/test/Autofac.Pooling.Test/PolicyTests.cs index ab302c2..b3af42d 100644 --- a/test/Autofac.Pooling.Test/PolicyTests.cs +++ b/test/Autofac.Pooling.Test/PolicyTests.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Autofac.Core; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; @@ -144,11 +144,9 @@ public void PolicyCanSeeParametersFromThePooledServiceResolve() var container = builder.Build(); - IPooledService pooledInstance; - using (var scope = container.BeginLifetimeScope()) { - pooledInstance = scope.Resolve(new NamedParameter("Val1", 123), new TypedParameter(typeof(int), 456)); + var _ = scope.Resolve(new NamedParameter("Val1", 123), new TypedParameter(typeof(int), 456)); } Assert.Collection(policyReceivedParameters, diff --git a/test/Autofac.Pooling.Test/PooledComponentTests.cs b/test/Autofac.Pooling.Test/PooledComponentTests.cs index d511bd9..08fb98c 100644 --- a/test/Autofac.Pooling.Test/PooledComponentTests.cs +++ b/test/Autofac.Pooling.Test/PooledComponentTests.cs @@ -1,5 +1,5 @@ using Autofac.Features.OwnedInstances; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; diff --git a/test/Autofac.Pooling.Test/PoolingTests.cs b/test/Autofac.Pooling.Test/PoolingTests.cs index 79d7cc6..26a63a5 100644 --- a/test/Autofac.Pooling.Test/PoolingTests.cs +++ b/test/Autofac.Pooling.Test/PoolingTests.cs @@ -1,7 +1,7 @@ -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; -namespace Autofac.Pooling.Tests; +namespace Autofac.Pooling.Test; public class PoolingTest { diff --git a/test/Autofac.Pooling.Test/RegistrationExtensionsTests.cs b/test/Autofac.Pooling.Test/RegistrationExtensionsTests.cs index 6a0505f..b3b7025 100644 --- a/test/Autofac.Pooling.Test/RegistrationExtensionsTests.cs +++ b/test/Autofac.Pooling.Test/RegistrationExtensionsTests.cs @@ -1,6 +1,6 @@ using System; using Autofac.Builder; -using Autofac.Pooling.Tests.Shared; +using Autofac.Pooling.Tests.Common; using Xunit; namespace Autofac.Pooling.Test; @@ -17,6 +17,7 @@ public void RequiresCallbackContainer() } [Fact] + [SuppressMessage("CA2000", "CA2000", Justification = "The container will dispose of the object.")] public void NoProvidedInstances() { var builder = new ContainerBuilder(); diff --git a/test/Autofac.Pooling.Test/Shared/OtherPooledComponent.cs b/test/Autofac.Pooling.Test/Shared/OtherPooledComponent.cs deleted file mode 100644 index f30acbe..0000000 --- a/test/Autofac.Pooling.Test/Shared/OtherPooledComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Autofac.Pooling.Tests.Shared; - -public class OtherPooledComponent : IPooledService -{ - public int GetCalled => throw new System.NotImplementedException(); - - public int ReturnCalled => throw new System.NotImplementedException(); - - public int DisposeCalled => throw new System.NotImplementedException(); -}