From 34ee2bb7c40ef81b3d5684ed336971a69d4af84e Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Sun, 8 Sep 2024 14:13:50 +0200 Subject: [PATCH 1/2] :bug: potential fix of highlighted issue https://github.com/gimlichael/Cuemon/pull/73#issuecomment-2335199229 --- src/Cuemon.Core/Threading/Lock.cs | 153 +++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/src/Cuemon.Core/Threading/Lock.cs b/src/Cuemon.Core/Threading/Lock.cs index 823925571..dfccedb6f 100644 --- a/src/Cuemon.Core/Threading/Lock.cs +++ b/src/Cuemon.Core/Threading/Lock.cs @@ -2,10 +2,11 @@ // Taken from: https://github.com/MarkCiliaVincenti/Backport.System.Threading.Lock // NuGet package: https://www.nuget.org/packages/Backport.System.Threading.Lock -using System.Runtime.CompilerServices; #if NET9_0_OR_GREATER +using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(System.Threading.Lock))] -#else +#elif NET5_0_OR_GREATER && !NET9_0_OR_GREATER +using System.Runtime.CompilerServices; namespace System.Threading { /// @@ -136,4 +137,152 @@ public ref struct Scope(Lock @lock) } } } +#else +using System.Runtime.CompilerServices; +namespace System.Threading +{ + /// + /// A backport of .NET 9.0+'s System.Threading.Lock. Provides a way to get mutual exclusion in regions of code between different threads. + /// A lock may be held by one thread at a time. + /// + /// + /// Threads that cannot immediately enter the lock may wait for the lock to be exited or until a specified timeout. A thread + /// that holds a lock may enter the lock repeatedly without exiting it, such as recursively, in which case the thread should + /// eventually exit the lock the same number of times to fully exit the lock and allow other threads to enter the lock. + /// + public sealed class Lock + { + /// + /// + /// + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void Enter() => Monitor.Enter(this); + + /// + /// + /// + /// + /// + /// + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryEnter() => Monitor.TryEnter(this); + + /// + /// + /// + /// + /// + /// + /// + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryEnter(TimeSpan timeout) => Monitor.TryEnter(this, timeout); + + /// + /// + /// + /// + /// + /// + /// + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool TryEnter(int millisecondsTimeout) => Monitor.TryEnter(this, millisecondsTimeout); + + /// + /// + /// + /// + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void Exit() => Monitor.Exit(this); + + /// + /// Determines whether the current thread holds this lock. + /// + /// + /// true if the current thread holds this lock; otherwise, false. + /// + /// +#if !PRE_NETSTANDARD + public bool IsHeldByCurrentThread => Monitor.IsEntered(this); +#else + public bool IsHeldByCurrentThread => throw new NotSupportedException("IsHeldByCurrentThread is only supported on .NET Framework 4.5 or greater."); +#endif + + /// + /// Enters the lock and returns a that may be disposed to exit the lock. Once the method returns, + /// the calling thread would be the only thread that holds the lock. This method is intended to be used along with a + /// language construct that would automatically dispose the , such as with the C# using statement. + /// + /// + /// A that may be disposed to exit the lock. + /// + /// + /// If the lock cannot be entered immediately, the calling thread waits for the lock to be exited. If the lock is + /// already held by the calling thread, the lock is entered again. The calling thread should exit the lock, such as by + /// disposing the returned , as many times as it had entered the lock to fully exit the lock and + /// allow other threads to enter the lock. + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif +#if (NET40_OR_GREATER || NETSTANDARD2_0_OR_GREATER) && !NET5_0_OR_GREATER + [Obsolete("This method is a best-effort at hardening against thread aborts, but can theoretically retain lock on pre-.NET 5.0. Use with caution.")] + public Scope EnterScope() + { + bool lockTaken = false; + try + { + Monitor.Enter(this, ref lockTaken); + return new Scope(this); + } + catch (ThreadAbortException) + { + if (lockTaken) Monitor.Exit(this); + throw; + } + } +#else + public Scope EnterScope() + { + Monitor.Enter(this); + return new Scope(this); + } +#endif + + /// + /// A disposable structure that is returned by , which when disposed, exits the lock. + /// + public ref struct Scope(Lock @lock) + { + /// + /// Exits the lock. + /// + /// + /// If the calling thread holds the lock multiple times, such as recursively, the lock is exited only once. The + /// calling thread should ensure that each enter is matched with an exit. + /// + /// + /// The calling thread does not hold the lock. + /// +#if !PRE_NETSTANDARD + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public readonly void Dispose() => @lock.Exit(); + } + } +} #endif From e54b3b271b0949b1cf6aaa061308307de91f8504 Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Mon, 9 Sep 2024 22:19:13 +0200 Subject: [PATCH 2/2] :recycle: refactored Lock to Cuemon.Extensions.Threading and added reference to Backport.System.Threading.Lock --- .../PackageReleaseNotes.txt | 11 +- CHANGELOG.md | 1 + src/Cuemon.Core/Cuemon.Core.csproj | 4 - src/Cuemon.Core/Runtime/Dependency.cs | 3 +- src/Cuemon.Core/Runtime/FileWatcher.cs | 3 +- src/Cuemon.Core/Runtime/Watcher.cs | 2 +- src/Cuemon.Core/Threading/Lock.cs | 288 ------------------ src/Cuemon.Data/BulkCopyDataReader.cs | 3 +- src/Cuemon.Data/DatabaseWatcher.cs | 3 +- .../Bootstrapper.cs | 3 +- .../Bootstrapper.cs | 3 +- .../Bootstrapper.cs | 3 +- .../Http/SlimHttpClientFactory.cs | 2 +- .../NewtonsoftJsonFormatterOptions.cs | 3 +- .../CacheEnumerableExtensions.cs | 3 +- .../Formatters/JsonFormatterOptions.cs | 3 +- .../Cuemon.Extensions.Threading.csproj | 9 +- .../Formatters/YamlFormatterOptions.cs | 3 +- .../Formatters/XmlFormatterOptions.cs | 3 +- 19 files changed, 33 insertions(+), 320 deletions(-) delete mode 100644 src/Cuemon.Core/Threading/Lock.cs diff --git a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt index 459ea8776..63d0f81e9 100644 --- a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt @@ -1,4 +1,13 @@ -Version 8.3.2 +Version 9.0.0 +Availability: .NET 9, .NET 8, .NET 6 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +  +# New Features +- ADDED support for System.Threading.Lock object that targets .NET TFM prior to .NET 9 (credits to Mark Cilia Vincenti, https://github.com/MarkCiliaVincenti/Backport.System.Threading.Lock) +  +Version 8.3.2 Availability: .NET 8, .NET 6 and .NET Standard 2.0   # ALM diff --git a/CHANGELOG.md b/CHANGELOG.md index a9fbb4934..c0b0f6f57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ New features: - FailureConverter class in the Cuemon.Extensions.Newtonsoft.Json.Converters namespace to convert FailureConverter to JSON - FailureConverter class in the Cuemon.Extensions.Text.Json.Converters namespace to convert FailureConverter to JSON - FailureConverter class in the Cuemon.Xml.Serialization.Converters namespace to convert FailureConverter to XML +- Support for System.Threading.Lock object that targets TFMs prior to .NET 9 (credits to Mark Cilia Vincenti, https://github.com/MarkCiliaVincenti/Backport.System.Threading.Lock) ### Changed diff --git a/src/Cuemon.Core/Cuemon.Core.csproj b/src/Cuemon.Core/Cuemon.Core.csproj index 6807e66c6..0a1710f99 100644 --- a/src/Cuemon.Core/Cuemon.Core.csproj +++ b/src/Cuemon.Core/Cuemon.Core.csproj @@ -13,8 +13,4 @@ action-factory bit-unit byte-unit binary-prefix decimal-prefix prefix-multiple multiple-table calculator configure configure-revert configure-exchange configurable condition options-pattern data-reader decorator delimited-string disposable finalize-disposable safe-invoke safe-invoke-async func-factory patterns reference-project clean-architecture clean-code task-action-factory task-func-factory template template-factory time-range time-unit validator guard text-encoding parser-factory security aes-cryptor cyclic-redundancy-check fowler-noll-vo-hash hash-factory hash-result hmac-message-digest hmac-secure-hash-algorithm keyed-crypto-hash keyed-crypto-algorithm message-digest non-crypto-algorithm secure-hash-algorithm unkeyed-crypto-hash - - - - diff --git a/src/Cuemon.Core/Runtime/Dependency.cs b/src/Cuemon.Core/Runtime/Dependency.cs index f37c74f6b..5b4bdb63d 100644 --- a/src/Cuemon.Core/Runtime/Dependency.cs +++ b/src/Cuemon.Core/Runtime/Dependency.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; namespace Cuemon.Runtime @@ -13,7 +12,7 @@ public abstract class Dependency : IDependency { private IEnumerable _watchers; private readonly Func, IEnumerable> _watchersHandler; - private readonly Lock _locker = new(); + private readonly object _locker = new(); /// /// Initializes a new instance of the class. diff --git a/src/Cuemon.Core/Runtime/FileWatcher.cs b/src/Cuemon.Core/Runtime/FileWatcher.cs index 851420ba9..b40c2e7ab 100644 --- a/src/Cuemon.Core/Runtime/FileWatcher.cs +++ b/src/Cuemon.Core/Runtime/FileWatcher.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Threading; using System.Threading.Tasks; using Cuemon.Security; @@ -12,7 +11,7 @@ namespace Cuemon.Runtime /// public class FileWatcher : Watcher { - private readonly Lock _locker = new(); + private readonly object _locker = new(); /// /// Initializes a new instance of the class. diff --git a/src/Cuemon.Core/Runtime/Watcher.cs b/src/Cuemon.Core/Runtime/Watcher.cs index a0bbee15f..6f3f5f6d5 100644 --- a/src/Cuemon.Core/Runtime/Watcher.cs +++ b/src/Cuemon.Core/Runtime/Watcher.cs @@ -10,7 +10,7 @@ namespace Cuemon.Runtime /// public abstract class Watcher : Disposable, IWatcher { - private readonly Lock _locker = new(); + private readonly object _locker = new(); private Timer _watcherTimer; private Timer _watcherPostponingTimer; diff --git a/src/Cuemon.Core/Threading/Lock.cs b/src/Cuemon.Core/Threading/Lock.cs deleted file mode 100644 index dfccedb6f..000000000 --- a/src/Cuemon.Core/Threading/Lock.cs +++ /dev/null @@ -1,288 +0,0 @@ -// Credit: Mark Cilia Vincenti, 2024 -// Taken from: https://github.com/MarkCiliaVincenti/Backport.System.Threading.Lock -// NuGet package: https://www.nuget.org/packages/Backport.System.Threading.Lock - -#if NET9_0_OR_GREATER -using System.Runtime.CompilerServices; -[assembly: TypeForwardedTo(typeof(System.Threading.Lock))] -#elif NET5_0_OR_GREATER && !NET9_0_OR_GREATER -using System.Runtime.CompilerServices; -namespace System.Threading -{ - /// - /// A backport of .NET 9.0+'s System.Threading.Lock. Provides a way to get mutual exclusion in regions of code between different threads. - /// A lock may be held by one thread at a time. - /// - /// - /// Threads that cannot immediately enter the lock may wait for the lock to be exited or until a specified timeout. A thread - /// that holds a lock may enter the lock repeatedly without exiting it, such as recursively, in which case the thread should - /// eventually exit the lock the same number of times to fully exit the lock and allow other threads to enter the lock. - /// - public sealed class Lock - { -#pragma warning disable CS9216 // A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement. - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Enter() => Monitor.Enter(this); - - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter() => Monitor.TryEnter(this); - - /// - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter(TimeSpan timeout) => Monitor.TryEnter(this, timeout); - - /// - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter(int millisecondsTimeout) => Monitor.TryEnter(this, millisecondsTimeout); - - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Exit() => Monitor.Exit(this); - - /// - /// Determines whether the current thread holds this lock. - /// - /// - /// true if the current thread holds this lock; otherwise, false. - /// - /// -#if !PRE_NETSTANDARD - public bool IsHeldByCurrentThread => Monitor.IsEntered(this); -#else - public bool IsHeldByCurrentThread => throw new NotSupportedException("IsHeldByCurrentThread is only supported on .NET Framework 4.5 or greater."); -#endif -#pragma warning restore CS9216 // A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement. - - /// - /// Enters the lock and returns a that may be disposed to exit the lock. Once the method returns, - /// the calling thread would be the only thread that holds the lock. This method is intended to be used along with a - /// language construct that would automatically dispose the , such as with the C# using statement. - /// - /// - /// A that may be disposed to exit the lock. - /// - /// - /// If the lock cannot be entered immediately, the calling thread waits for the lock to be exited. If the lock is - /// already held by the calling thread, the lock is entered again. The calling thread should exit the lock, such as by - /// disposing the returned , as many times as it had entered the lock to fully exit the lock and - /// allow other threads to enter the lock. - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public Scope EnterScope() - { - Enter(); - return new Scope(this); - } - - /// - /// A disposable structure that is returned by , which when disposed, exits the lock. - /// - public ref struct Scope(Lock @lock) - { - /// - /// Exits the lock. - /// - /// - /// If the calling thread holds the lock multiple times, such as recursively, the lock is exited only once. The - /// calling thread should ensure that each enter is matched with an exit. - /// - /// - /// The calling thread does not hold the lock. - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public readonly void Dispose() => @lock.Exit(); - } - } -} -#else -using System.Runtime.CompilerServices; -namespace System.Threading -{ - /// - /// A backport of .NET 9.0+'s System.Threading.Lock. Provides a way to get mutual exclusion in regions of code between different threads. - /// A lock may be held by one thread at a time. - /// - /// - /// Threads that cannot immediately enter the lock may wait for the lock to be exited or until a specified timeout. A thread - /// that holds a lock may enter the lock repeatedly without exiting it, such as recursively, in which case the thread should - /// eventually exit the lock the same number of times to fully exit the lock and allow other threads to enter the lock. - /// - public sealed class Lock - { - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Enter() => Monitor.Enter(this); - - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter() => Monitor.TryEnter(this); - - /// - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter(TimeSpan timeout) => Monitor.TryEnter(this, timeout); - - /// - /// - /// - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public bool TryEnter(int millisecondsTimeout) => Monitor.TryEnter(this, millisecondsTimeout); - - /// - /// - /// - /// - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public void Exit() => Monitor.Exit(this); - - /// - /// Determines whether the current thread holds this lock. - /// - /// - /// true if the current thread holds this lock; otherwise, false. - /// - /// -#if !PRE_NETSTANDARD - public bool IsHeldByCurrentThread => Monitor.IsEntered(this); -#else - public bool IsHeldByCurrentThread => throw new NotSupportedException("IsHeldByCurrentThread is only supported on .NET Framework 4.5 or greater."); -#endif - - /// - /// Enters the lock and returns a that may be disposed to exit the lock. Once the method returns, - /// the calling thread would be the only thread that holds the lock. This method is intended to be used along with a - /// language construct that would automatically dispose the , such as with the C# using statement. - /// - /// - /// A that may be disposed to exit the lock. - /// - /// - /// If the lock cannot be entered immediately, the calling thread waits for the lock to be exited. If the lock is - /// already held by the calling thread, the lock is entered again. The calling thread should exit the lock, such as by - /// disposing the returned , as many times as it had entered the lock to fully exit the lock and - /// allow other threads to enter the lock. - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif -#if (NET40_OR_GREATER || NETSTANDARD2_0_OR_GREATER) && !NET5_0_OR_GREATER - [Obsolete("This method is a best-effort at hardening against thread aborts, but can theoretically retain lock on pre-.NET 5.0. Use with caution.")] - public Scope EnterScope() - { - bool lockTaken = false; - try - { - Monitor.Enter(this, ref lockTaken); - return new Scope(this); - } - catch (ThreadAbortException) - { - if (lockTaken) Monitor.Exit(this); - throw; - } - } -#else - public Scope EnterScope() - { - Monitor.Enter(this); - return new Scope(this); - } -#endif - - /// - /// A disposable structure that is returned by , which when disposed, exits the lock. - /// - public ref struct Scope(Lock @lock) - { - /// - /// Exits the lock. - /// - /// - /// If the calling thread holds the lock multiple times, such as recursively, the lock is exited only once. The - /// calling thread should ensure that each enter is matched with an exit. - /// - /// - /// The calling thread does not hold the lock. - /// -#if !PRE_NETSTANDARD - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public readonly void Dispose() => @lock.Exit(); - } - } -} -#endif diff --git a/src/Cuemon.Data/BulkCopyDataReader.cs b/src/Cuemon.Data/BulkCopyDataReader.cs index a071ad876..c3fb3225b 100644 --- a/src/Cuemon.Data/BulkCopyDataReader.cs +++ b/src/Cuemon.Data/BulkCopyDataReader.cs @@ -6,7 +6,6 @@ using System.Globalization; using System.Linq; using System.Text; -using System.Threading; namespace Cuemon.Data { @@ -15,7 +14,7 @@ namespace Cuemon.Data /// public sealed class BulkCopyDataReader : DbDataReader { - private static readonly Lock PadLock = new(); + private static readonly object PadLock = new(); private IOrderedDictionary _defaultFields; /// diff --git a/src/Cuemon.Data/DatabaseWatcher.cs b/src/Cuemon.Data/DatabaseWatcher.cs index bcab2bbf4..9aeb3d248 100644 --- a/src/Cuemon.Data/DatabaseWatcher.cs +++ b/src/Cuemon.Data/DatabaseWatcher.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Cuemon.Runtime; using Cuemon.Security; @@ -15,7 +14,7 @@ namespace Cuemon.Data /// public class DatabaseWatcher : Watcher { - private readonly Lock _locker = new(); + private readonly object _locker = new(); /// /// Initializes a new instance of the class. diff --git a/src/Cuemon.Extensions.AspNetCore.Newtonsoft.Json/Bootstrapper.cs b/src/Cuemon.Extensions.AspNetCore.Newtonsoft.Json/Bootstrapper.cs index 9f9ed8813..60cda82c9 100644 --- a/src/Cuemon.Extensions.AspNetCore.Newtonsoft.Json/Bootstrapper.cs +++ b/src/Cuemon.Extensions.AspNetCore.Newtonsoft.Json/Bootstrapper.cs @@ -1,12 +1,11 @@ using Cuemon.Extensions.AspNetCore.Newtonsoft.Json.Converters; using Cuemon.Extensions.Newtonsoft.Json.Formatters; -using System.Threading; namespace Cuemon.Extensions.AspNetCore.Newtonsoft.Json { internal static class Bootstrapper { - private static readonly Lock PadLock = new(); + private static readonly object PadLock = new(); private static bool _initialized; internal static void Initialize() diff --git a/src/Cuemon.Extensions.AspNetCore.Text.Json/Bootstrapper.cs b/src/Cuemon.Extensions.AspNetCore.Text.Json/Bootstrapper.cs index 8da6adf94..50f33939b 100644 --- a/src/Cuemon.Extensions.AspNetCore.Text.Json/Bootstrapper.cs +++ b/src/Cuemon.Extensions.AspNetCore.Text.Json/Bootstrapper.cs @@ -1,12 +1,11 @@ using Cuemon.Extensions.AspNetCore.Text.Json.Converters; using Cuemon.Extensions.Text.Json.Formatters; -using System.Threading; namespace Cuemon.Extensions.AspNetCore.Text.Json { internal static class Bootstrapper { - private static readonly Lock PadLock = new(); + private static readonly object PadLock = new(); private static bool _initialized; internal static void Initialize() diff --git a/src/Cuemon.Extensions.AspNetCore.Xml/Bootstrapper.cs b/src/Cuemon.Extensions.AspNetCore.Xml/Bootstrapper.cs index c21d48bbd..4da21b799 100644 --- a/src/Cuemon.Extensions.AspNetCore.Xml/Bootstrapper.cs +++ b/src/Cuemon.Extensions.AspNetCore.Xml/Bootstrapper.cs @@ -1,12 +1,11 @@ using Cuemon.Extensions.AspNetCore.Xml.Converters; using Cuemon.Xml.Serialization.Formatters; -using System.Threading; namespace Cuemon.Extensions.AspNetCore.Xml { internal static class Bootstrapper { - private static readonly Lock PadLock = new(); + private static readonly object PadLock = new(); private static bool _initialized; internal static void Initialize() diff --git a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs index 3a5fe7bb5..66f6b44cb 100644 --- a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs +++ b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs @@ -29,7 +29,7 @@ public class SlimHttpClientFactory : IHttpClientFactory private readonly ConcurrentDictionary> _activeHandlers = new(); private readonly ConcurrentQueue _expiredHandlers = new(); private readonly Func _handlerFactory; - private readonly Lock _locker = new(); + private readonly object _locker = new(); private readonly SlimHttpClientFactoryOptions _options; internal static readonly TimeSpan ExpirationTimerDueTime = TimeSpan.FromSeconds(15); private Timer _expirationTimer; diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/NewtonsoftJsonFormatterOptions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/NewtonsoftJsonFormatterOptions.cs index 61ae8895e..2c6fe74f8 100644 --- a/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/NewtonsoftJsonFormatterOptions.cs +++ b/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/NewtonsoftJsonFormatterOptions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Net.Http.Headers; using System.Reflection; -using System.Threading; using Cuemon.Configuration; using Cuemon.Diagnostics; using Cuemon.Extensions.Newtonsoft.Json.Converters; @@ -17,7 +16,7 @@ namespace Cuemon.Extensions.Newtonsoft.Json.Formatters /// public class NewtonsoftJsonFormatterOptions : IExceptionDescriptorOptions, IContentNegotiation, IValidatableParameterObject { - private readonly Lock _locker = new(); + private readonly object _locker = new(); private bool _refreshed; /// diff --git a/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs index 26f2e7cd0..7244291e1 100644 --- a/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs +++ b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.Linq; using System.Reflection; -using System.Threading; using Cuemon.Collections.Generic; using Cuemon.Reflection; using Cuemon.Runtime; @@ -707,7 +706,7 @@ public static Func Memoize(ICacheEnumerable cache, string key, CacheInvalidation invalidation, FuncFactory valueFactory) where TTuple : Template { diff --git a/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs b/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs index fc6fb782c..775435f73 100644 --- a/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs +++ b/src/Cuemon.Extensions.Text.Json/Formatters/JsonFormatterOptions.cs @@ -4,7 +4,6 @@ using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; -using System.Threading; using Cuemon.Configuration; using Cuemon.Diagnostics; using Cuemon.Extensions.Text.Json.Converters; @@ -17,7 +16,7 @@ namespace Cuemon.Extensions.Text.Json.Formatters /// public class JsonFormatterOptions : IContentNegotiation, IExceptionDescriptorOptions, IValidatableParameterObject { - private readonly Lock _locker = new(); + private readonly object _locker = new(); private bool _refreshed; /// diff --git a/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj b/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj index 82273dce8..c68df8d90 100644 --- a/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj +++ b/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj @@ -13,4 +13,11 @@ - \ No newline at end of file + + + + + + + + diff --git a/src/Cuemon.Extensions.YamlDotNet/Formatters/YamlFormatterOptions.cs b/src/Cuemon.Extensions.YamlDotNet/Formatters/YamlFormatterOptions.cs index 866f45476..baeb215f3 100644 --- a/src/Cuemon.Extensions.YamlDotNet/Formatters/YamlFormatterOptions.cs +++ b/src/Cuemon.Extensions.YamlDotNet/Formatters/YamlFormatterOptions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http.Headers; -using System.Threading; using Cuemon.Configuration; using Cuemon.Diagnostics; using Cuemon.Extensions.YamlDotNet.Converters; @@ -16,7 +15,7 @@ namespace Cuemon.Extensions.YamlDotNet.Formatters /// public class YamlFormatterOptions : EncodingOptions, IExceptionDescriptorOptions, IContentNegotiation, IValidatableParameterObject { - private readonly Lock _locker = new(); + private readonly object _locker = new(); private bool _refreshed; /// diff --git a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs index f354cade7..b44734460 100644 --- a/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs +++ b/src/Cuemon.Xml/Serialization/Formatters/XmlFormatterOptions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Net.Http.Headers; -using System.Threading; using Cuemon.Configuration; using Cuemon.Diagnostics; using Cuemon.Net.Http; @@ -14,7 +13,7 @@ namespace Cuemon.Xml.Serialization.Formatters /// public class XmlFormatterOptions : IExceptionDescriptorOptions, IContentNegotiation, IValidatableParameterObject { - private readonly Lock _locker = new(); + private readonly object _locker = new(); private bool _refreshed; ///