diff --git a/Aspects/Diagnostics/ExternalMetadata/WebExceptionDumpMetadata.cs b/Aspects/Diagnostics/ExternalMetadata/WebExceptionDumpMetadata.cs index 5755e88..b8aa04a 100644 --- a/Aspects/Diagnostics/ExternalMetadata/WebExceptionDumpMetadata.cs +++ b/Aspects/Diagnostics/ExternalMetadata/WebExceptionDumpMetadata.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; using System.IO; using System.Net; @@ -9,16 +11,19 @@ public abstract class WebExceptionDumpMetadata { /// [Dump(0)] - public object Status; + public object Status { get; set; } /// [Dump(1, DumpClass = typeof(WebExceptionDumpMetadata), DumpMethod = nameof(DumpResponse))] - public object Response; + public object Response { get; set; } /// + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] public static string DumpResponse( WebResponse response) { + Contract.Ensures(Contract.Result() != null); + var stream = response?.GetResponseStream(); if (stream == null) diff --git a/Aspects/Diagnostics/NuGet/PublishObjectDumper.cmd b/Aspects/Diagnostics/NuGet/PublishObjectDumper.cmd index c526344..bdb823e 100644 --- a/Aspects/Diagnostics/NuGet/PublishObjectDumper.cmd +++ b/Aspects/Diagnostics/NuGet/PublishObjectDumper.cmd @@ -12,7 +12,7 @@ if not exist c:\NuGet md c:\NuGet copy /y *.nupkg c:\NuGet @echo Press any key to push to NuGet.org... > con: @pause > nul: -NuGet Push AspectObjectDumper.1.5.5.nupkg -source https://www.nuget.org/api/v2/ +NuGet Push AspectObjectDumper.1.5.5.nupkg -source https://www.nuget.org :exit popd pause \ No newline at end of file diff --git a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec index b4b3c17..6eda703 100644 --- a/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec +++ b/Aspects/Linq/Expressions/Serialization/NuGet/ExpressionSerialization.nuspec @@ -2,7 +2,7 @@ AspectExpressionSerialization - 1.0.50 + 1.0.51 Val Melamed Val Melamed diff --git a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs index 033f0cf..135e2c3 100644 --- a/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs +++ b/Aspects/Linq/Expressions/Serialization/Properties/AssemblyInfo.cs @@ -4,9 +4,9 @@ [assembly: AssemblyTitle("vm.Aspects.Linq.Expressions.Serialization")] [assembly: AssemblyDescription("Serializes and deserializes LINQ expression trees to and from XML documents.")] -[assembly: AssemblyVersion("1.0.50")] -[assembly: AssemblyFileVersion("1.0.50")] -[assembly: AssemblyInformationalVersion("1.0.50")] +[assembly: AssemblyVersion("1.0.51")] +[assembly: AssemblyFileVersion("1.0.51")] +[assembly: AssemblyInformationalVersion("1.0.51")] [assembly: InternalsVisibleTo( "vm.Aspects.Linq.Expressions.Serialization.Test, " + diff --git a/Aspects/Model/EFRepository/EFRepositoryBase.cs b/Aspects/Model/EFRepository/EFRepositoryBase.cs index baf96bc..cf4fbbd 100644 --- a/Aspects/Model/EFRepository/EFRepositoryBase.cs +++ b/Aspects/Model/EFRepository/EFRepositoryBase.cs @@ -320,6 +320,7 @@ IList ToValidationErrors( /// is by this context or ownership was passed to this context when this context was created. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. + [SuppressMessage("Microsoft.Usage", "CA2215:Dispose methods should call base class dispose")] protected override void Dispose( bool disposing) { diff --git a/Aspects/Model/PerCallContextRepositoryCallHandler.cs b/Aspects/Model/PerCallContextRepositoryCallHandler.cs index 86c523a..9bdc08c 100644 --- a/Aspects/Model/PerCallContextRepositoryCallHandler.cs +++ b/Aspects/Model/PerCallContextRepositoryCallHandler.cs @@ -72,6 +72,7 @@ public IMethodReturn Invoke( #endregion + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The scope will be disposed in PostInvoke.")] void PreInvoke(IMethodInvocation input) { if (!CreateTransactionScopeForTasks) @@ -92,7 +93,7 @@ void PreInvoke(IMethodInvocation input) input.InvocationContext["transactionScope"] = scope; } - IMethodReturn DoInvoke( + static IMethodReturn DoInvoke( IMethodInvocation input, GetNextHandlerDelegate getNext) => getNext().Invoke(input, getNext); diff --git a/Aspects/Model/Properties/AssemblyInfo.cs b/Aspects/Model/Properties/AssemblyInfo.cs index a3334e7..d6abf84 100644 --- a/Aspects/Model/Properties/AssemblyInfo.cs +++ b/Aspects/Model/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("vm.Aspect.Model")] [assembly: AssemblyDescription("Defines the IRepository and related base classes and utilities - a framework of building domain object model.")] -[assembly: AssemblyVersion("1.0.50")] -[assembly: AssemblyFileVersion("1.0.50")] -[assembly: AssemblyInformationalVersion("1.0.50")] +[assembly: AssemblyVersion("1.0.51")] +[assembly: AssemblyFileVersion("1.0.51")] +[assembly: AssemblyInformationalVersion("1.0.51")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Model.Tests, " + diff --git a/Aspects/NuGet/PublishAspects.cmd b/Aspects/NuGet/PublishAspects.cmd index e7d7455..d290d32 100644 --- a/Aspects/NuGet/PublishAspects.cmd +++ b/Aspects/NuGet/PublishAspects.cmd @@ -19,7 +19,7 @@ if not exist c:\NuGet md c:\NuGet copy /y *.nupkg c:\NuGet @echo Press any key to push to NuGet.org... > con: @pause > nul: -NuGet Push vm.Aspects.1.0.50-beta.nupkg +NuGet Push vm.Aspects.1.0.51-beta.nupkg -source https://www.nuget.org :exit popd pause \ No newline at end of file diff --git a/Aspects/NuGet/vm.Aspects.nuspec b/Aspects/NuGet/vm.Aspects.nuspec index 7fc25a5..49b5cb9 100644 --- a/Aspects/NuGet/vm.Aspects.nuspec +++ b/Aspects/NuGet/vm.Aspects.nuspec @@ -2,7 +2,7 @@ vm.Aspects - 1.0.50-beta + 1.0.51-beta Val Melamed Val Melamed diff --git a/Aspects/Parsers/Properties/AssemblyInfo.cs b/Aspects/Parsers/Properties/AssemblyInfo.cs index 9db5a77..013ddeb 100644 --- a/Aspects/Parsers/Properties/AssemblyInfo.cs +++ b/Aspects/Parsers/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ [assembly: AssemblyTitle("vm.Aspects.Parser")] [assembly: AssemblyDescription("Text parsing readers, e.g. CSV/TSV reader.")] -[assembly: AssemblyVersion("1.0.50")] -[assembly: AssemblyFileVersion("1.0.50")] -[assembly: AssemblyInformationalVersion("1.0.50")] +[assembly: AssemblyVersion("1.0.51")] +[assembly: AssemblyFileVersion("1.0.51")] +[assembly: AssemblyInformationalVersion("1.0.51")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Parsers.Tests, " + diff --git a/Aspects/Properties/AssemblyInfo.cs b/Aspects/Properties/AssemblyInfo.cs index 8a1fa91..651c220 100644 --- a/Aspects/Properties/AssemblyInfo.cs +++ b/Aspects/Properties/AssemblyInfo.cs @@ -2,9 +2,9 @@ [assembly: AssemblyTitle("vm.Aspects")] [assembly: AssemblyDescription("A set of classes addressing various common cross-cutting concerns.")] -[assembly: AssemblyVersion("1.0.50")] -[assembly: AssemblyFileVersion("1.0.50")] -[assembly: AssemblyInformationalVersion("1.0.50")] +[assembly: AssemblyVersion("1.0.51")] +[assembly: AssemblyFileVersion("1.0.51")] +[assembly: AssemblyInformationalVersion("1.0.51")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Test, " + diff --git a/Aspects/Security/Cryptography/Ciphers/NuGet/PublishCiphers.cmd b/Aspects/Security/Cryptography/Ciphers/NuGet/PublishCiphers.cmd index a81b136..4604823 100644 --- a/Aspects/Security/Cryptography/Ciphers/NuGet/PublishCiphers.cmd +++ b/Aspects/Security/Cryptography/Ciphers/NuGet/PublishCiphers.cmd @@ -18,7 +18,7 @@ if not exist c:\NuGet md c:\NuGet copy /y *.nupkg c:\NuGet @echo Press any key to push to NuGet.org... > con: @pause > nul: -NuGet Push Ciphers.1.11.9.nupkg -source https://www.nuget.org/api/v2/ +NuGet Push Ciphers.1.11.9.nupkg -source https://www.nuget.org :exit popd pause diff --git a/Aspects/Wcf/AsyncCallContext.cs b/Aspects/Wcf/AsyncCallContext.cs index 016f086..13baf93 100644 --- a/Aspects/Wcf/AsyncCallContext.cs +++ b/Aspects/Wcf/AsyncCallContext.cs @@ -12,11 +12,16 @@ namespace vm.Aspects.Wcf /// Maintains a simple synchronized key-value collection to replace /// the one from the which is failing in asynchronous situations. /// - public class AsyncCallContext + public class AsyncCallContext : IDisposable, IIsDisposed { readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); IDictionary _contextSlots = new Dictionary(); + /// + /// Gets the current asynchronous call context. + /// + public static AsyncCallContext Current => CallContext.LogicalGetData(nameof(AsyncCallContext)) as AsyncCallContext; + /// /// Gets the entry at the data slot with name . /// @@ -94,5 +99,68 @@ void ObjectInvariant() { Contract.Invariant(_contextSlots != null); } + + #region IDisposable pattern implementation + /// + /// The flag will be set just before the object is disposed. + /// + /// 0 - if the object is not disposed yet, any other value - the object is already disposed. + /// + /// Do not test or manipulate this flag outside of the property or the method . + /// The type of this field is Int32 so that it can be easily passed to the members of the class . + /// + int _disposed; + + /// + /// Returns if the object has already been disposed, otherwise . + /// + public bool IsDisposed => Interlocked.CompareExchange(ref _disposed, 1, 1) == 1; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// Invokes the protected virtual . + [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "It is correct.")] + public void Dispose() + { + // if it is disposed or in a process of disposing - return. + if (Interlocked.Exchange(ref _disposed, 1) != 0) + return; + + // these will be called only if the instance is not disposed and is not in a process of disposing. + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Allows the object to attempt to free resources and perform other cleanup operations before it is reclaimed by garbage collection. + /// + /// Invokes the protected virtual with parameter . + ~AsyncCallContext() + { + Dispose(false); + } + + /// + /// Performs the actual job of disposing the object. + /// + /// + /// Passes the information whether this method is called by (explicitly or + /// implicitly at the end of a using statement), or by the finalizer. + /// + /// + /// If the method is called with ==, i.e. from , + /// it will try to release all managed resources (usually aggregated objects which implement as well) + /// and then it will release all unmanaged resources if any. If the parameter is then + /// the method will only try to release the unmanaged resources. + /// + protected virtual void Dispose(bool disposing) + { + if (!disposing) + return; + + _lock.Dispose(); + } + #endregion } } diff --git a/Aspects/Wcf/Behaviors/AsyncCallContextMessageInspector.cs b/Aspects/Wcf/Behaviors/AsyncCallContextMessageInspector.cs index 1044f6a..60a713a 100644 --- a/Aspects/Wcf/Behaviors/AsyncCallContextMessageInspector.cs +++ b/Aspects/Wcf/Behaviors/AsyncCallContextMessageInspector.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; -using System.Globalization; -using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Messaging; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; @@ -29,9 +27,6 @@ public object AfterReceiveRequest( CallContext.LogicalSetData(CallContextSlotName, context); - Trace.WriteLine( - string.Format(CultureInfo.InvariantCulture, "### Installed async context: {0}", context.GetHashCode().ToString())); - return null; } @@ -44,12 +39,10 @@ public void BeforeSendReply( ref Message reply, object correlationState) { - if (!ClearCallContext()) - Trace.WriteLine( - string.Format(CultureInfo.InvariantCulture, "*** ASYNC CONTEXT WAS NOT FOUND!")); + ClearCallContext(); } - bool ClearCallContext() + static bool ClearCallContext() { var context = CallContext.LogicalGetData(CallContextSlotName) as AsyncCallContext; @@ -58,8 +51,6 @@ bool ClearCallContext() context.Clear(); CallContext.FreeNamedDataSlot(CallContextSlotName); - Trace.WriteLine( - string.Format(CultureInfo.InvariantCulture, "### Cleared async context: {0}", context.GetHashCode().ToString())); return true; } } diff --git a/Aspects/Wcf/PerAsyncCallContextLifetimeManager.cs b/Aspects/Wcf/PerAsyncCallContextLifetimeManager.cs index a88b8e5..d4a4b0b 100644 --- a/Aspects/Wcf/PerAsyncCallContextLifetimeManager.cs +++ b/Aspects/Wcf/PerAsyncCallContextLifetimeManager.cs @@ -40,7 +40,7 @@ public override void RemoveValue() AsyncCallContext.FreeDataSlot(Key); } - AsyncCallContext AsyncCallContext + static AsyncCallContext AsyncCallContext { get { diff --git a/Aspects/Wcf/Properties/AssemblyInfo.cs b/Aspects/Wcf/Properties/AssemblyInfo.cs index 390e4e3..fa0a57b 100644 --- a/Aspects/Wcf/Properties/AssemblyInfo.cs +++ b/Aspects/Wcf/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ [assembly: AssemblyTitle("Wcf")] [assembly: AssemblyDescription("A set of classes and generics simplifying the initial configuration work of creating WCF services.")] -[assembly: AssemblyVersion("1.0.50")] -[assembly: AssemblyFileVersion("1.0.50")] -[assembly: AssemblyInformationalVersion("1.0.50")] +[assembly: AssemblyVersion("1.0.51")] +[assembly: AssemblyFileVersion("1.0.51")] +[assembly: AssemblyInformationalVersion("1.0.51")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "vm.Aspects.Wcf.Test, " +