Skip to content

Instantly share code, notes, and snippets.

@grumpydev
Forked from thecodejunkie/async.cs
Last active May 12, 2016 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save grumpydev/048e8ab6fb390dfa53d77d3cc68a4b19 to your computer and use it in GitHub Desktop.
Save grumpydev/048e8ab6fb390dfa53d77d3cc68a4b19 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
var task = Main();
while (true)
{
Console.WriteLine("Main Task Status: {0}", task.Status);
if (task.IsCompleted)
{
break;
}
Thread.Sleep(500);
}
Console.Read();
}
static Task Main()
{
var cts = new CancellationTokenSource();
var module = new MyModule();
var tasks = new List<Task>();
foreach (var route in module.Routes)
{
var routeResult =
route.Invoke(cts.Token);
var coerced =
RouteResultHelper.CoerceResult(routeResult);
Console.WriteLine("Task Status: {0}", coerced.Status);
tasks.Add(coerced.ContinueWith(t =>
{
Console.WriteLine("Result: {0}", t.Result);
return true;
}, cts.Token));
}
return Task.WhenAll(tasks).ContinueWith(t =>
{
Console.WriteLine("All routes completed");
return true;
});
}
}
public class MyModule : NancyModule
{
public MyModule()
{
Get("first", async ct =>
{
await DoWork("first", 500);
return 1;
});
Get("second", async ct =>
{
await DoWork("second", 200);
return 2;
});
Get("third", () =>
{
return 3;
});
Get("fourth", ct => DoStuff());
}
private static Task<string> DoStuff()
{
return Task.Delay(3000).ContinueWith(t => "fourth");
}
private static async Task DoWork(string name, int delay)
{
for (var i = 0; i < 10; i++)
{
await Task.Delay(delay);
}
}
}
public abstract class NancyModule
{
public IList<Route> Routes = new List<Route>();
public void Get<T>(string path, Func<T> action)
{
this.Routes.Add(new Route<T>(path, ct => action()));
}
public void Get<T>(string path, Func<CancellationToken, T> action)
{
this.Routes.Add(new Route<T>(path, action));
}
}
public abstract class Route
{
public Route(string path)
{
this.Path = path;
}
public string Path { get; private set; }
public abstract object Invoke(CancellationToken cancellationToken);
}
public class Route<T> : Route
{
public Route(string path, Func<CancellationToken, T> action)
: base(path)
{
this.Action = action;
}
public Func<CancellationToken, T> Action { get; set; }
public override object Invoke(CancellationToken cancellationToken)
{
return this.Action.Invoke(cancellationToken);
}
}
public static class RouteResultHelper
{
private static readonly MethodInfo ConvertMethod = typeof(RouteResultHelper).GetMethod("Convert", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
private static readonly ConcurrentDictionary<Type, MethodInfo> ConverterCache = new ConcurrentDictionary<Type, MethodInfo>();
/// <summary>
/// Coerces the result.
/// </summary>
/// <param name="routeResult">The result that should be coereced.</param>
/// <returns>A <see cref="Task{TResult}"/> of <see cref="object"/>.</returns>
public static Task<object> CoerceResult(object routeResult)
{
if (routeResult == null)
{
return null;
}
var resultType = routeResult.GetType();
if (!IsTask(resultType))
{
return Task.FromResult(routeResult);
}
Type innerType = resultType.GetGenericArguments()[0];
var converter = ConverterCache.GetOrAdd(innerType, t =>
{
var conervertResult = ConvertMethod.MakeGenericMethod(t);
return conervertResult;
});
var result = (Task<object>)converter.Invoke(null, new[] { routeResult });
return result;
}
private static bool IsTask(Type resultType)
{
var type = resultType;
while (type != null)
{
if (type == typeof (Task))
{
return true;
}
type = type.BaseType;
}
return false;
}
private static Task<object> Convert<T>(object taskAsObject)
{
var task = (Task<T>)taskAsObject;
return CastToObject<T>(task);
}
private static async Task<object> CastToObject<T>(Task<T> task)
{
return (object)await task.ConfigureAwait(false);
}
}
first second third
second second first second second second first second second first second second
first first first first first first
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment