Skip to content

Instantly share code, notes, and snippets.

@thecodejunkie
Last active May 12, 2016 08:10
Show Gist options
  • Save thecodejunkie/ce52631ec5d550243a1a669b9201091a to your computer and use it in GitHub Desktop.
Save thecodejunkie/ce52631ec5d550243a1a669b9201091a 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)
{
Main().Wait();
Console.Read();
}
static async Task Main()
{
var cts = new CancellationTokenSource();
var module = new MyModule();
foreach (var route in module.Routes)
{
var routeResult =
route.Invoke(cts.Token);
var coerced =
RouteResultHelper.CoerceResult(routeResult);
await coerced;
}
}
}
public class MyModule : NancyModule
{
public MyModule()
{
Get("first", async ct =>
{
await DoWork("first", 500);
return 200;
});
Get("second", async ct =>
{
await DoWork("second", 200);
return 200;
});
Get("third", () =>
{
Console.WriteLine("third ");
return 200;
});
}
private static async Task DoWork(string name, int delay)
{
for (var i = 0; i < 10; i++)
{
Console.Write($"{ name } ");
await Task.Delay(delay);
}
Console.WriteLine();
}
}
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; }
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 async Task<object> CoerceResult(object routeResult)
{
if (routeResult == null)
{
return null;
}
var resultType = routeResult.GetType();
if (resultType != typeof(Task))
{
return routeResult;
}
Type innerType = resultType.GetGenericArguments()[0];
var converter = ConverterCache.GetOrAdd(innerType, t =>
{
return ConvertMethod.MakeGenericMethod(t);
});
return await (Task<object>)converter.Invoke(null, new[] { routeResult });
}
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