<file_sep>﻿using System.Net.Http;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class SecondController
    {
        public Task<string> Get()
        {
            var client = new HttpClient();
            return client.GetStringAsync("http://www.google.com")
                .ContinueWith(t => t.Result.Substring(0, 10));
        }
        
    }
}<file_sep>﻿using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class FirstController
    {
        public Task<string> Get()
        {
            var client = new HttpClient();
            return client.GetStringAsync("http://www.google.com");
        }
    }
}<file_sep>﻿using System;
using System.Linq;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class ThirdController
    {
        public Task<string> Get()
        {
            return Db.QueryAsync("SELECT twitterId FROM ids where id = 42")
                .ContinueWith(t => Client.GetTweets(t.Result))
                .Unwrap()
                .ContinueWith(t => t.Result.First())
                .ContinueWith(e =>
                {
                    Console.WriteLine($"Error {e}");
                    return "";
                }, TaskContinuationOptions.OnlyOnFaulted);

        }


        internal class Db
        {
            public static Task<int> QueryAsync(string sql)
            {
                // return Task.Delay(0).ContinueWith(_ => 42);
                throw new Exception("foo");
            }
        }
        
        internal class Client
        {
            public static Task<string[]> GetTweets(int id)
            {
                return Task.Delay(0).ContinueWith(_ => new [] { "one", "two", "three"});
            }
        }
    }
}<file_sep>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;

namespace TpgAsyncExercises
{
    // do not edit this file
    public class TimedInt
    {
        public DateTime RetrieveDate { get; }
        public int Value { get; }

        public TimedInt(DateTime retrieveDate, int value)
        {
            RetrieveDate = retrieveDate;
            Value = value;
        }
    }

    public class Randomizer
    {
        public static readonly Random Random = new Random();

        private bool _finished = false;

        public Task<TimedInt> Get(int input)
        {
            if (_finished)
                Debug.Assert(false, $"It took too much time to start the Get call for {input}");
            var delay = Random.Next(500, 3000);
            return Task.Delay(delay).ContinueWith(_ =>
            {
                _finished = true;
                return new TimedInt(DateTime.Now, input);
            });
        }

        public Task<int> GetAndAdd(int root, int addendum)
        {
            var delay = Random.Next(500, 3000);
            return Task.Delay(delay).ContinueWith(_ => root + addendum);
        }

        public WaitableItem GetWaitable(string input)
        {
            var item = new WaitableItem(input) ;
            var delay = Random.Next(2, 800);
            Task.Delay(delay).ContinueWith(_ => { item.Completed = true; });
            return item;
        }
    }

    public class TimedQueue
    {
        private readonly List<TimedInt> _list = new List<TimedInt>();
        public void Enqueue(TimedInt input)
        {
            var retrieveDate = input.RetrieveDate;
            if (_list.Any())
            {
                if (!IsValidSpan(retrieveDate) && !IsValidSpan(_list.Last().RetrieveDate))
                {
                    throw new ArgumentException($"You took too long to queue '{input.Value}'");
                }

                if (_list.Last().Value > input.Value)
                {
                    throw new ArgumentException($"'{input.Value}' is enqueued out of order");
                    
                }
            }
            _list.Add(input);
        }

        public int Count => _list.Count();

        private static bool IsValidSpan(DateTime retrieveDate)
        {
            return retrieveDate.AddMilliseconds(100) > DateTime.Now;
        }
    }
}<file_sep>﻿#pragma warning disable 219
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class SecondControllerAwaitMachine
    {
        public Task<string> Get()
        {
            var stateMachine = new InternalMachine();
            stateMachine._controller = this;
            stateMachine._builder = AsyncTaskMethodBuilder<string>.Create();
            stateMachine._state = -1;
            stateMachine._builder.Start<SecondControllerAwaitMachine.InternalMachine>(ref stateMachine);
            return stateMachine._builder.Task;
        }

        public SecondControllerAwaitMachine()
        {
            // base.\u002Ector();
        }

        [CompilerGenerated]
        private sealed class InternalMachine : IAsyncStateMachine
        {
            public int _state;
            public AsyncTaskMethodBuilder<string> _builder;
            public SecondControllerAwaitMachine _controller;
            private HttpClient _client;
            private string _html;
            private string _htmlResult;
            private TaskAwaiter<string> _awaiter;

            public InternalMachine()
            {
                // base.\u002Ector();
            }

            void IAsyncStateMachine.MoveNext()
            {
                int num1 = this._state;
                string result;
                try
                {
                    TaskAwaiter<string> awaiter;
                    int num2;
                    if (num1 != 0)
                    {
                        this._client = new HttpClient();
                        awaiter = this._client.GetStringAsync("http://www.google.com").GetAwaiter();
                        if (!awaiter.IsCompleted)
                        {
                            this._state = num2 = 0;
                            this._awaiter = awaiter;
                            SecondControllerAwaitMachine.InternalMachine stateMachine = this;
                            this._builder
                                .AwaitUnsafeOnCompleted<TaskAwaiter<string>,
                                    SecondControllerAwaitMachine.InternalMachine>(
                                    ref awaiter, ref stateMachine);
                            return;
                        }
                    }
                    else
                    {
                        awaiter = this._awaiter;
                        this._awaiter = new TaskAwaiter<string>();
                        this._state = num2 = -1;
                    }

                    this._htmlResult = awaiter.GetResult();
                    this._html = this._htmlResult;
                    this._htmlResult = (string) null;
                    result = this._html.Substring(0, 10);
                }
                catch (Exception ex)
                {
                    this._state = -2;
                    this._builder.SetException(ex);
                    return;
                }

                this._state = -2;
                this._builder.SetResult(result);
            }

            void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
            {
            }
        }
    }
}<file_sep>﻿using System;

namespace SimpleWebServer.cli
{
    class Program
    {
        static void Main(string[] args)
        {
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            while (Console.ReadKey() != null)
            {
                var controller = new StringController();
                var task = controller.Get();
                task.ContinueWith(t => Console.WriteLine(t.Result));
                Console.WriteLine("after continue");
            }
        }
    }
}
<file_sep>﻿using System.Net.Http;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class SecondControllerAwait
    {
        public async Task<string> Get()
        {
            var client = new HttpClient();
            var s = await client.GetStringAsync("http://www.google.com");
            return s.Substring(0, 10);
        }
    }
}<file_sep>﻿using System;
using System.Net.Http;

namespace SimpleWebServer.cli
{
    public class SynchronousWithResult
    {
        public string Get()
        {
            // BAD BAD BAD 
            var client = new HttpClient();
            var html = client.GetStringAsync("http://www.google.com").Result;
            Console.WriteLine("This will run *after* the google call");
            return html;
        }
    }
}<file_sep>﻿namespace TpgAsyncExercises
{
    // you can edit this file
    public class WaitableItem 
    {
        public bool Completed { get; set; }

        public WaitableItem(string value)
        {
            
        }
    }
}<file_sep>﻿using System.Linq;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class FourthController
    {
        public async Task<string> Get()
        {
            var twitterId = await Db.QueryAsync("SELECT twitterId FROM ids where id = 42");
            var tweets = await Client.GetTweets(twitterId);
            return tweets.First();
        }
        

        internal class Db
        {
            public static Task<int> QueryAsync(string sql)
            {
                return Task.Delay(0).ContinueWith(_ => 42);
            }
        }
        
        internal class Client
        {
            public static Task<string[]> GetTweets(int id)
            {
                return Task.Delay(0).ContinueWith(_ => new [] { "one", "two", "three"});
            }
        }
    }
}<file_sep>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace TpgAsyncExercises
{
    internal class Program
    {
        public static async Task Main(string[] args)
        {
            // await Exercise1A();
            // Exercise2();
            // Exercise3("hello");
            Console.ReadKey();
        }


// rewrite this method to correctly use async/await
        public static Task<int> Exercise1(int input)
        {
            var r = new Randomizer();
            return r.GetAndAdd(input, 5)
                .ContinueWith(t => t.Result + 1)
                .ContinueWith(t => r.GetAndAdd(t.Result, 2)).Unwrap();
        }

        public static async Task Exercise1A()
        {
            var result = await Exercise1(3);
            Debug.Assert(result == 11, $"result should be 11");
            Console.WriteLine("Success");
        }


        // Call r.Get for each item in the input array.
        // Each call will take a random amount of time (imagine it's a web service call)
        // All r.Get calls must be started as quickly as possible
        //   DO NOT wait until one call returns before starting the next
        // The results from r.Get should be enqueued as quickly as 
        // possible but *must* be enqueued in input order 
        // IN other words, when "2" arrives, if "1" has not yet 
        // arrived then wait for it, otherwise enqueue "2" immediately.
        
        #if FALSE
        public static async Task Exercise2()
        {
            var input = new[] {1, 2, 3, 4};
            var r = new Randomizer();
            var queue = new TimedQueue();
            
            // call r.Get on all input items
            // enqueue them as quickly as possible, but in order

            Debug.Assert(queue.Count == 4, "not all values are enqueued");
            Console.WriteLine("success!");
        }
    
        #endif


        #if FALSE
        // Edit *only* the WaitableItem file to make this code compile 
        // and run correctly.  You should not need to edit
        // Exercise3 itself nor should you need to edit the Randomizer
        public static async Task Exercise3(string input)
        {
            var r = new Randomizer();
            var result = await r.GetWaitable(input);
            
            Debug.Assert(result == "hello", $"{result} is not 'Hello'");
            Console.WriteLine("Success");
        }
        #endif
    }
}<file_sep>﻿using System;
using System.Net.Http;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class StringController
    {
        public Task<string> Get()
        {
            // return await "http://www.google.com";
            return null;
        }

        
    }
}<file_sep>﻿using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class SimpleAsyncController
    {
        public Task<string> Get()
        {
            return Task.FromResult("hello");
        }
        
    }
}<file_sep>﻿using System.Threading.Tasks;

namespace SimpleWebServer.cli
{
    public class SimpleSimpleAsyncController
    {
        public async Task<string> Get()
        {
            return "hello";
        }
    }
}