//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.Util { using System; using System.Runtime.CompilerServices; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; // An awaitable type that invokes a continuation callback under a call to HttpContext.InvokeCancellableCallback. // This type is for compiler use; the ASP.NET runtime is not expected to call into these APIs directly. internal struct WithinCancellableCallbackTaskAwaitable { internal static readonly WithinCancellableCallbackTaskAwaitable Completed = new WithinCancellableCallbackTaskAwaitable(null, ((Task)Task.FromResult((object)null)).GetAwaiter()); private readonly WithinCancellableCallbackTaskAwaiter _awaiter; public WithinCancellableCallbackTaskAwaitable(HttpContext context, TaskAwaiter innerAwaiter) { _awaiter = new WithinCancellableCallbackTaskAwaiter(context, innerAwaiter); } public WithinCancellableCallbackTaskAwaiter GetAwaiter() { return _awaiter; } // The awaiter type that backs WithinCancellableCallbackTaskAwaitable. internal struct WithinCancellableCallbackTaskAwaiter : ICriticalNotifyCompletion { private static readonly WaitCallback _shunt = state => ((Action)state)(); private readonly HttpContext _context; private readonly TaskAwaiter _innerAwaiter; internal WithinCancellableCallbackTaskAwaiter(HttpContext context, TaskAwaiter innerAwaiter) { _context = context; _innerAwaiter = innerAwaiter; } public bool IsCompleted { get { return _innerAwaiter.IsCompleted; } } public void GetResult() { _innerAwaiter.GetResult(); // If Response.End was called, need to observe it here. HttpContext context = _context; if (context != null) { context.Response.ObserveResponseEndCalled(); } } public void OnCompleted(Action continuation) { Action wrappedContinuation = WrapContinuation(continuation); _innerAwaiter.OnCompleted(wrappedContinuation); } [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)] // equivalent of [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { Action wrappedContinuation = WrapContinuation(continuation); _innerAwaiter.UnsafeOnCompleted(wrappedContinuation); } private Action WrapContinuation(Action continuation) { HttpContext context = _context; return (context != null) ? () => context.InvokeCancellableCallback(_shunt, continuation) : continuation; } } } }