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();
}
}
}