// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace BasicWebSite.Controllers { public class AsyncActionsController : Controller { const int SimulateDelayMilliseconds = 20; public override void OnActionExecuted(ActionExecutedContext context) { // So that tests can observe we're following the proper flow after an exception, surface a // message saying what the exception was. if (context.Exception != null) { context.Result = Content($"Action exception message: {context.Exception.Message}"); context.ExceptionHandled = true; } } public async void AsyncVoidAction() { await Task.Delay(SimulateDelayMilliseconds); } public Task TaskAction() { return Task.Delay(SimulateDelayMilliseconds); } public async Task TaskExceptionAction() { await Task.Delay(SimulateDelayMilliseconds); throw new CustomException(); } public async Task TaskOfObjectAction(string message) { await Task.Delay(SimulateDelayMilliseconds); return new Message { Text = message }; } public async Task TaskOfObjectExceptionAction(string message) { await Task.Delay(SimulateDelayMilliseconds); throw new CustomException(); } public async Task TaskOfIActionResultAction(string message) { await Task.Delay(SimulateDelayMilliseconds); return Content(message); } public async Task TaskOfIActionResultExceptionAction(string message) { await Task.Delay(SimulateDelayMilliseconds); throw new CustomException(); } public async Task TaskOfContentResultAction(string message) { await Task.Delay(SimulateDelayMilliseconds); return Content(message); } public async Task TaskOfContentResultExceptionAction(string message) { await Task.Delay(SimulateDelayMilliseconds); throw new CustomException(); } public ValueTask PreCompletedValueTaskOfObjectAction(string message) { return new ValueTask(new Message { Text = message }); } public ValueTask PreCompletedValueTaskOfObjectExceptionAction(string message) { throw new CustomException(); } public ValueTask PreCompletedValueTaskOfIActionResultAction(string message) { return new ValueTask(Content(message)); } public ValueTask PreCompletedValueTaskOfIActionResultExceptionAction(string message) { throw new CustomException(); } public ValueTask PreCompletedValueTaskOfContentResultAction(string message) { return new ValueTask(Content(message)); } public ValueTask PreCompletedValueTaskOfContentResultExceptionAction(string message) { throw new CustomException(); } public CustomAwaitable CustomAwaitableVoidAction() { return new CustomAwaitable(SimulateDelayMilliseconds); } public CustomAwaitable CustomAwaitableVoidExceptionAction() { throw new CustomException(); } public CustomAwaitable CustomAwaitableOfObjectAction(string message) { return new CustomAwaitable( SimulateDelayMilliseconds, new Message { Text = message }); } public CustomAwaitable CustomAwaitableOfObjectExceptionAction(string message) { throw new CustomException(); } public CustomAwaitable CustomAwaitableOfIActionResultAction(string message) { return new CustomAwaitable(SimulateDelayMilliseconds, Content(message)); } public CustomAwaitable CustomAwaitableOfIActionResultExceptionAction(string message) { throw new CustomException(); } public CustomAwaitable CustomAwaitableOfContentResultAction(string message) { return new CustomAwaitable(SimulateDelayMilliseconds, Content(message)); } public CustomAwaitable CustomAwaitableOfContentResultExceptionAction(string message) { throw new CustomException(); } public class Message { public string Text { get; set; } } public class CustomAwaitable { protected readonly int _simulateDelayMilliseconds; public CustomAwaitable(int simulateDelayMilliseconds) { _simulateDelayMilliseconds = simulateDelayMilliseconds; } public CustomAwaiter GetAwaiter() { return new CustomAwaiter(_simulateDelayMilliseconds); } } public class CustomAwaitable : CustomAwaitable { private readonly T _result; public CustomAwaitable(int simulateDelayMilliseconds, T result) : base(simulateDelayMilliseconds) { _result = result; } public new CustomAwaiter GetAwaiter() { return new CustomAwaiter(_simulateDelayMilliseconds, _result); } } public class CustomAwaiter : INotifyCompletion { private IList _continuations = new List(); public CustomAwaiter(int simulateDelayMilliseconds) { Task.Factory.StartNew(() => { Thread.Sleep(simulateDelayMilliseconds); lock(_continuations) { IsCompleted = true; foreach (var continuation in _continuations) { continuation(); } _continuations.Clear(); } }); } public bool IsCompleted { get; private set; } public void OnCompleted(Action continuation) { lock (_continuations) { if (IsCompleted) { continuation(); } else { _continuations.Add(continuation); } } } public void GetResult() { } } public class CustomAwaiter : CustomAwaiter { private readonly T _result; public CustomAwaiter(int simulateDelayMilliseconds, T result) : base(simulateDelayMilliseconds) { _result = result; } public new T GetResult() => _result; } public class CustomException : Exception { public CustomException() : base("This is a custom exception.") { } } } }