namespace Prefab.Handler; /// /// Provides access to the current handler context for the executing operation. /// /// Implementations of this interface allow components to retrieve or temporarily override the current /// HandlerContext within a given scope. This is typically used to flow contextual information, such as user or request /// data, through asynchronous or nested operations. public interface IHandlerContextAccessor { /// /// Gets the current handler context for the ongoing operation, if one is available. /// HandlerContext? Current { get; } /// /// Sets the specified handler context as the current context for the duration of the returned disposable object's /// lifetime. /// /// Use the returned IDisposable in a using statement to ensure the previous context is restored /// even if an exception occurs. /// The handler context to set as current. Cannot be null. /// An IDisposable that, when disposed, restores the previous handler context. IDisposable Set(HandlerContext handlerContext); } /// public sealed class HandlerContextAccessor : IHandlerContextAccessor { private static readonly AsyncLocal CurrentContext = new(); /// public HandlerContext? Current => CurrentContext.Value; /// public IDisposable Set(HandlerContext handlerContext) { var previous = CurrentContext.Value; CurrentContext.Value = handlerContext; return new Scope(() => CurrentContext.Value = previous); } /// /// Provides a mechanism for executing a specified delegate when the scope is disposed, typically used to restore /// state or perform cleanup actions. /// /// This type is intended for use with the 'using' statement to ensure that the specified /// delegate is executed exactly once when the scope ends. The delegate is not invoked if Dispose is called more /// than once. /// The delegate to invoke when the scope is disposed. Cannot be null. private sealed class Scope(Action restore) : IDisposable { private bool _done; public void Dispose() { if(_done) return; _done = true; restore(); } } }