From 01e3ef2b02243c89fa93eeae80ad83b69db322cd Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Mon, 29 Jun 2020 11:56:17 -0700 Subject: [PATCH 1/8] Fixed memory leak issue where tracers are held after operation completes. --- .../Diagnostics/DefaultDiagnosticTracer.cs | 52 ++++++++++++++----- .../DefaultDiagnosticTracerTests.cs | 19 +++++++ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/Autofac/Core/Diagnostics/DefaultDiagnosticTracer.cs b/src/Autofac/Core/Diagnostics/DefaultDiagnosticTracer.cs index 55a87d3e8..0312db835 100644 --- a/src/Autofac/Core/Diagnostics/DefaultDiagnosticTracer.cs +++ b/src/Autofac/Core/Diagnostics/DefaultDiagnosticTracer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Globalization; using System.Text; using Autofac.Core.Resolving; @@ -24,6 +25,15 @@ public class DefaultDiagnosticTracer : IResolvePipelineTracer /// public event EventHandler? OperationCompleted; + /// + /// Gets the number of operations in progress being traced. + /// + /// + /// An with the number of trace IDs associated + /// with in-progress operations being traced by this tracer. + /// + public int OperationsInProgress => this._operationBuilders.Count; + /// void IResolvePipelineTracer.OperationStart(ResolveOperationBase operation, ResolveRequest initiatingRequest) { @@ -125,14 +135,21 @@ void IResolvePipelineTracer.OperationFailure(ResolveOperationBase operation, Exc { if (_operationBuilders.TryGetValue(operation.TracingId, out var builder)) { - builder.Outdent(); - builder.AppendLine(TracerMessages.ExitBrace); - builder.AppendException(TracerMessages.OperationFailed, operationException); - - // If we're completing the root operation, raise the event. - if (operation.IsTopLevelOperation) + try { - OperationCompleted?.Invoke(this, new OperationTraceCompletedArgs(operation, builder.ToString())); + builder.Outdent(); + builder.AppendLine(TracerMessages.ExitBrace); + builder.AppendException(TracerMessages.OperationFailed, operationException); + + // If we're completing the root operation, raise the event. + if (operation.IsTopLevelOperation) + { + OperationCompleted?.Invoke(this, new OperationTraceCompletedArgs(operation, builder.ToString())); + } + } + finally + { + _operationBuilders.TryRemove(operation.TracingId, out var _); } } } @@ -142,14 +159,21 @@ void IResolvePipelineTracer.OperationSuccess(ResolveOperationBase operation, obj { if (_operationBuilders.TryGetValue(operation.TracingId, out var builder)) { - builder.Outdent(); - builder.AppendLine(TracerMessages.ExitBrace); - builder.AppendFormattedLine(TracerMessages.OperationSucceeded, resolvedInstance); - - // If we're completing the root operation, raise the event. - if (operation.IsTopLevelOperation) + try + { + builder.Outdent(); + builder.AppendLine(TracerMessages.ExitBrace); + builder.AppendFormattedLine(TracerMessages.OperationSucceeded, resolvedInstance); + + // If we're completing the root operation, raise the event. + if (operation.IsTopLevelOperation) + { + OperationCompleted?.Invoke(this, new OperationTraceCompletedArgs(operation, builder.ToString())); + } + } + finally { - OperationCompleted?.Invoke(this, new OperationTraceCompletedArgs(operation, builder.ToString())); + _operationBuilders.TryRemove(operation.TracingId, out var _); } } } diff --git a/test/Autofac.Specification.Test/Diagnostics/DefaultDiagnosticTracerTests.cs b/test/Autofac.Specification.Test/Diagnostics/DefaultDiagnosticTracerTests.cs index f2c5e947a..b11d137f8 100644 --- a/test/Autofac.Specification.Test/Diagnostics/DefaultDiagnosticTracerTests.cs +++ b/test/Autofac.Specification.Test/Diagnostics/DefaultDiagnosticTracerTests.cs @@ -92,6 +92,25 @@ public void DiagnosticTracerDoesNotRaiseAnEventOnNestedOperations() Assert.Contains("Decorator", lastOpResult); } + [Fact] + public void DiagnosticTracerDoesNotLeakMemory() + { + var tracer = new DefaultDiagnosticTracer(); + + var containerBuilder = new ContainerBuilder(); + containerBuilder.RegisterType().As(); + containerBuilder.RegisterDecorator(); + + var container = containerBuilder.Build(); + + container.AttachTrace(tracer); + container.Resolve(); + + // The dictionary of tracked trace IDs and + // string builders should be empty. + Assert.Equal(0, tracer.OperationsInProgress); + } + private interface IService { } From 3298ec7013da097cf31aed421b4a3247f2a925f5 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 07:40:11 -0700 Subject: [PATCH 2/8] Basic build support for VS Code and Mac. --- .gitignore | 1 - .vscode/tasks.json | 23 +++++++++++++++++++ src/Autofac/Autofac.csproj | 1 + .../Autofac.Specification.Test.csproj | 5 ++-- test/Autofac.Test/Autofac.Test.csproj | 3 ++- 5 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore index d1073e74e..b7c291781 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ x64/ # Visual Studio 2015 cache/options directory .dotnet/ .vs/ -.vscode/ .cr/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..d52dc9b5b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + "tasks": [ + { + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "command": "dotnet", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile", + "type": "shell" + } + ], + "version": "2.0.0" +} diff --git a/src/Autofac/Autofac.csproj b/src/Autofac/Autofac.csproj index 94741d977..0279d702b 100644 --- a/src/Autofac/Autofac.csproj +++ b/src/Autofac/Autofac.csproj @@ -64,6 +64,7 @@ + diff --git a/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj b/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj index d74f2b167..3a2762508 100644 --- a/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj +++ b/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj @@ -15,15 +15,16 @@ + - + - + diff --git a/test/Autofac.Test/Autofac.Test.csproj b/test/Autofac.Test/Autofac.Test.csproj index f5751753a..7847c15d7 100644 --- a/test/Autofac.Test/Autofac.Test.csproj +++ b/test/Autofac.Test/Autofac.Test.csproj @@ -39,8 +39,9 @@ $(DefineConstants);PARTIAL_TRUST - + + From 77a1e7f5928e5cc66135d71c271d96cfcd73e239 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 07:49:03 -0700 Subject: [PATCH 3/8] Recommended VS Code extensions. --- .vscode/extensions.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..767b23afb --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "formulahendry.dotnet-test-explorer", + "ms-dotnettools.csharp", + "editorconfig.editorconfig", + "davidanson.vscode-markdownlint" + ] +} From 49246226a89120c9e768377749d2c3d6babbfe04 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 08:08:52 -0700 Subject: [PATCH 4/8] Ensure formatting and analyzers are on. --- .vscode/settings.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..47b35b3f2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableRoslynAnalyzers": true +} From 65c9748498ffb882e1b6a0608a2450fa008db9d5 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 08:17:48 -0700 Subject: [PATCH 5/8] Note on dev environment with VS Code. --- CONTRIBUTING.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 70c5f5d7c..b52c8be23 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,9 +40,18 @@ We use [semantic versioning](https://semver.org/) for our package versions. ### Developer Environment -- Visual Studio 2019 +**Windows**: + +- Visual Studio 2019 or VS Code +- .NET Core SDK (each repo has a `global.json` with the version required) +- PowerShell 5+ / PowerShell Core + +**Mac**: + +- VS Code - .NET Core SDK (each repo has a `global.json` with the version required) -- PowerShell 5+ +- PowerShell 5+ / PowerShell Core +- Mono - install the latest "Visual Studio channel" version; the standalone version or the one from Homebrew won't work. ### Build / Test @@ -50,7 +59,7 @@ Project codelines with scripted builds generally have a `build.ps1` script. This Some project codelines rely on convention-based builds so do not have a specific script. In these cases you will not see a `.ps1` or `.proj` file to execute. In these cases... -- The build is executed by running it in Visual Studio or by executing `msbuild Solution.sln` on the solution in the codeline root. +- The build is executed by running it in Visual Studio or by executing `dotnet msbuild Solution.sln` on the solution in the codeline root. - Unit tests can be run from the Visual Studio test explorer or by manually executing the command-line unit test runner from the `packages` folder against the built unit test assembly. Unit tests are written in XUnit and Moq. **Code contributions should include tests that exercise/demonstrate the contribution.** From c8f9a1600d4350c26ea805a8bfae2baec2a82a83 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 09:14:14 -0700 Subject: [PATCH 6/8] Corrected build command. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b52c8be23..931cfb2f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,7 +59,7 @@ Project codelines with scripted builds generally have a `build.ps1` script. This Some project codelines rely on convention-based builds so do not have a specific script. In these cases you will not see a `.ps1` or `.proj` file to execute. In these cases... -- The build is executed by running it in Visual Studio or by executing `dotnet msbuild Solution.sln` on the solution in the codeline root. +- The build is executed by running it in Visual Studio or by executing `dotnet build Autofac.sln` on the solution in the codeline root. - Unit tests can be run from the Visual Studio test explorer or by manually executing the command-line unit test runner from the `packages` folder against the built unit test assembly. Unit tests are written in XUnit and Moq. **Code contributions should include tests that exercise/demonstrate the contribution.** From f214f3de15db1fa95d142808bea9e784f6de9aa2 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 09:26:34 -0700 Subject: [PATCH 7/8] Partial trust isn't a thing in the new code access security mechanism. --- test/Autofac.Test/Autofac.Test.csproj | 4 - .../PartialTrust/PartialTrustTestExecutor.cs | 100 ------------------ .../PartialTrust/PartialTrustTests.cs | 82 -------------- 3 files changed, 186 deletions(-) delete mode 100644 test/Autofac.Test/PartialTrust/PartialTrustTestExecutor.cs delete mode 100644 test/Autofac.Test/PartialTrust/PartialTrustTests.cs diff --git a/test/Autofac.Test/Autofac.Test.csproj b/test/Autofac.Test/Autofac.Test.csproj index 7847c15d7..a80360ce1 100644 --- a/test/Autofac.Test/Autofac.Test.csproj +++ b/test/Autofac.Test/Autofac.Test.csproj @@ -36,10 +36,6 @@ - - $(DefineConstants);PARTIAL_TRUST - - diff --git a/test/Autofac.Test/PartialTrust/PartialTrustTestExecutor.cs b/test/Autofac.Test/PartialTrust/PartialTrustTestExecutor.cs deleted file mode 100644 index 31d27e448..000000000 --- a/test/Autofac.Test/PartialTrust/PartialTrustTestExecutor.cs +++ /dev/null @@ -1,100 +0,0 @@ -#if PARTIAL_TRUST -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Net; -using System.Net.Mail; -using System.Reflection; -using System.Security; -using System.Security.Permissions; -using System.Web; -using Xunit; - -namespace Autofac.Test.PartialTrust -{ - public class PartialTrustTestExecutor : IDisposable - { - // Put the actual tests in the PartialTrustTests class as public void methods - // with no parameters. This fixture will automatically enumerate them and execute them - // in a partial trust domain. - private AppDomain _remoteDomain; - - public PartialTrustTestExecutor() - { - _remoteDomain = CreateSandboxDomain(); - } - - public void Dispose() - { - AppDomain.Unload(_remoteDomain); - } - - [Theory] - [MemberData(nameof(ExecutePartialTrustTestsSource))] - public void ExecutePartialTrustTests(MethodInfo testMethod) - { - var fixture = CreateRemoteFixture(); - try - { - testMethod.Invoke(fixture, null); - } - catch (TargetInvocationException ex) - { - if (ex.InnerException != null) - { - throw ex.InnerException; - } - - throw; - } - } - - public static IEnumerable ExecutePartialTrustTestsSource - { - get - { - return typeof(PartialTrustTests) - .GetMethods(BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public) - .Where(m => m.ReturnType == typeof(void) && m.ContainsGenericParameters == false && m.GetParameters().Length == 0) - .Select(m => new object[] { m }); - } - } - - private PartialTrustTests CreateRemoteFixture() - { - var assemblyName = typeof(PartialTrustTests).Assembly.FullName; - var typeName = typeof(PartialTrustTests).FullName; - var executor = (PartialTrustTests)_remoteDomain.CreateInstanceAndUnwrap(assemblyName, typeName); - return executor; - } - - private static AppDomain CreateSandboxDomain() - { - // Normally from a security perspective we'd put the sandboxed app in its own - // base directory, but to make things easier (so we don't have to copy the NUnit - // assembly, etc.) we'll just mirror the current test domain settings. - var info = new AppDomainSetup - { - ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, - PrivateBinPath = AppDomain.CurrentDomain.RelativeSearchPath, - }; - - // Grant set is the same set of permissions as ASP.NET medium trust EXCEPT - // it excludes the FileIOPermission, IsolatedStorageFilePermission, and PrintingPermission. - var grantSet = new PermissionSet(null); - grantSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium)); - grantSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); - grantSet.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read, "TEMP;TMP;USERNAME;OS;COMPUTERNAME")); - grantSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution | SecurityPermissionFlag.ControlThread | SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.RemotingConfiguration)); - grantSet.AddPermission(new SmtpPermission(SmtpAccess.Connect)); - grantSet.AddPermission(new SqlClientPermission(PermissionState.Unrestricted)); - grantSet.AddPermission(new TypeDescriptorPermission(PermissionState.Unrestricted)); - grantSet.AddPermission(new WebPermission(PermissionState.Unrestricted)); - grantSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)); - - return AppDomain.CreateDomain("Sandbox", null, info, grantSet); - } - } -} -#endif diff --git a/test/Autofac.Test/PartialTrust/PartialTrustTests.cs b/test/Autofac.Test/PartialTrust/PartialTrustTests.cs deleted file mode 100644 index a11e4cc02..000000000 --- a/test/Autofac.Test/PartialTrust/PartialTrustTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -#if PARTIAL_TRUST -using System; -using System.Linq; -using System.Security; -using System.Security.Permissions; -using Autofac.Test.Scenarios.Graph1; -using Xunit; - -namespace Autofac.Test.PartialTrust -{ - /// - /// Fixture containing the set of tests that will execute in partial trust. - /// - /// - /// - /// These tests are not marked with any NUnit attributes because they actually get executed - /// through XUnit via the . - /// Any public void method with no parameters found here will execute as a unit test. - /// - /// - public class PartialTrustTests : MarshalByRefObject - { - public void AppDomainSetupCorrect() - { - // The sandbox should have the expected name and we shouldn't be able to demand unrestricted permissions. - Assert.Equal("Sandbox", AppDomain.CurrentDomain.FriendlyName); - Assert.Throws(() => new SecurityPermission(PermissionState.Unrestricted).Demand()); - } - - public void Integration_CanCorrectlyBuildGraph1() - { - var builder = new ContainerBuilder(); - - builder.RegisterType().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().SingleInstance(); - builder.Register(ctr => new B1(ctr.Resolve())); - - var target = builder.Build(); - - var e = target.Resolve(); - var a = target.Resolve(); - var b = target.Resolve(); - var c = target.Resolve(); - var d = target.Resolve(); - - Assert.IsType(c); - var cd = (CD1)c; - - Assert.Same(a, b.A); - Assert.Same(a, cd.A); - Assert.NotSame(b, cd.B); - Assert.Same(c, e.C); - Assert.NotSame(b, e.B); - Assert.NotSame(e.B, cd.B); - } - - public interface I1 - { - } - - public interface I2 - { - } - - public class C : I1, I2 - { - } - - public void Integration_MultipleServicesOnAnOpenGenericType_ShareTheSameRegistration() - { - var builder = new ContainerBuilder(); - builder.RegisterGeneric(typeof(C<>)).As(typeof(I1<>), typeof(I2<>)); - var container = builder.Build(); - container.Resolve>(); - var count = container.ComponentRegistry.Registrations.Count(); - container.Resolve>(); - Assert.Equal(count, container.ComponentRegistry.Registrations.Count()); - } - } -} -#endif From 84c1505d9a8497f3f1d596dc22a2f74d9c56ce81 Mon Sep 17 00:00:00 2001 From: Travis Illig Date: Thu, 2 Jul 2020 14:17:24 -0700 Subject: [PATCH 8/8] Removed support for .NET 4.6.1. netstandard 2.0 is now the minimum - .NET 4.7.2 on desktop supports this. --- src/Autofac/Autofac.csproj | 13 ++++--------- src/Autofac/Util/NullableAttributes.cs | 2 +- .../Autofac.Specification.Test.csproj | 7 +------ .../Autofac.Test.Scenarios.ScannedAssembly.csproj | 2 +- test/Autofac.Test/Autofac.Test.csproj | 7 +------ 5 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/Autofac/Autofac.csproj b/src/Autofac/Autofac.csproj index 0279d702b..ec63ae13b 100644 --- a/src/Autofac/Autofac.csproj +++ b/src/Autofac/Autofac.csproj @@ -4,7 +4,7 @@ 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. 0.0.1 - netstandard2.1;netstandard2.0;net461 + netstandard2.1;netstandard2.0 latest enable $(NoWarn);CS1591;IDE0008 @@ -35,8 +35,8 @@ Autofac - - + + $(NoWarn);8600;8601;8602;8603;8604 @@ -59,15 +59,10 @@ - + - - - - - True diff --git a/src/Autofac/Util/NullableAttributes.cs b/src/Autofac/Util/NullableAttributes.cs index 512f7c13d..3d2f89f94 100644 --- a/src/Autofac/Util/NullableAttributes.cs +++ b/src/Autofac/Util/NullableAttributes.cs @@ -1,7 +1,7 @@ #pragma warning disable MA0048 // File name must match type name #pragma warning disable SA1402 // File may only contain a single type #pragma warning disable SA1649 // File name should match first type name -#if NETSTANDARD2_0 || NET461 +#if NETSTANDARD2_0 namespace System.Diagnostics.CodeAnalysis { diff --git a/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj b/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj index 3a2762508..aff092a33 100644 --- a/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj +++ b/test/Autofac.Specification.Test/Autofac.Specification.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net461 + netcoreapp3.0 $(NoWarn);CS1591;SA1602;SA1611 true ../../build/Analyzers.ruleset @@ -14,11 +14,6 @@ - - - - - diff --git a/test/Autofac.Test.Scenarios.ScannedAssembly/Autofac.Test.Scenarios.ScannedAssembly.csproj b/test/Autofac.Test.Scenarios.ScannedAssembly/Autofac.Test.Scenarios.ScannedAssembly.csproj index 0cabf040c..69edeafae 100644 --- a/test/Autofac.Test.Scenarios.ScannedAssembly/Autofac.Test.Scenarios.ScannedAssembly.csproj +++ b/test/Autofac.Test.Scenarios.ScannedAssembly/Autofac.Test.Scenarios.ScannedAssembly.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.1 $(NoWarn);CS1591 true Autofac.Test.Scenarios.ScannedAssembly diff --git a/test/Autofac.Test/Autofac.Test.csproj b/test/Autofac.Test/Autofac.Test.csproj index a80360ce1..d87264041 100644 --- a/test/Autofac.Test/Autofac.Test.csproj +++ b/test/Autofac.Test/Autofac.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net461 + netcoreapp3.0 $(NoWarn);CS1591;SA1602;SA1611 true ../../Autofac.snk @@ -36,11 +36,6 @@ - - - - -