Skip to content

Instantly share code, notes, and snippets.

@davidfowl
Created February 9, 2020 02:11
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 davidfowl/7c972ec7b16f5c03d3d2cac2c1bab30b to your computer and use it in GitHub Desktop.
Save davidfowl/7c972ec7b16f5c03d3d2cac2c1bab30b to your computer and use it in GitHub Desktop.
using System;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
{
public static class RequestDelegateExtensions
{
public static RequestDelegate Bind<TArg, TResult>(this Func<TArg, Task<TResult>> handler, From arg = default, JsonSerializerOptions options = null)
{
return async context =>
{
var result = await handler(await Bind<TArg>(context, arg));
context.Response.ContentType = "application/json";
await JsonSerializer.SerializeAsync(context.Response.Body, result, options);
};
}
public static RequestDelegate Bind<T>(this Func<Task<T>> handler, JsonSerializerOptions options = null)
{
return async context =>
{
var result = await handler();
context.Response.ContentType = "application/json";
await JsonSerializer.SerializeAsync(context.Response.Body, result, options);
};
}
public static RequestDelegate Bind<T>(this Func<T, HttpContext, Task> handler, From arg = null)
{
return async context => await handler(await Bind<T>(context, arg), context);
}
public static RequestDelegate Bind<T1, T2>(this Func<T1, T2, HttpContext, Task> handler, From arg1 = null, From arg2 = null)
{
return async context => await handler(await Bind<T1>(context, arg1), await Bind<T2>(context, arg2), context);
}
public static RequestDelegate Bind<T1, T2, T3>(this Func<T1, T2, T3, HttpContext, Task> handler, From arg1 = null, From arg2 = null, From arg3 = null)
{
return async context => await handler(await Bind<T1>(context, arg1), await Bind<T2>(context, arg2), await Bind<T3>(context, arg3), context);
}
public static RequestDelegate Bind<T1, T2, T3, T4>(this Func<T1, T2, T3, T4, HttpContext, Task> handler, From arg1 = null, From arg2 = null, From arg3 = null, From arg4 = null)
{
return async context => await handler(
await Bind<T1>(context, arg1),
await Bind<T2>(context, arg2),
await Bind<T3>(context, arg3),
await Bind<T4>(context, arg4), context);
}
private static async ValueTask<T> Bind<T>(HttpContext context, From a)
{
if (a.Type == ArgumentType.Query)
{
return (T)Convert.ChangeType(context.Request.Query[a.Name], typeof(T));
}
else if (a.Type == ArgumentType.Route)
{
return (T)Convert.ChangeType((string)context.Request.RouteValues[a.Name], typeof(T));
}
else if (a.Type == ArgumentType.Form)
{
var form = await context.Request.ReadFormAsync();
return (T)Convert.ChangeType(form[a.Name], typeof(T));
}
else if (a.Type == ArgumentType.Body)
{
return await JsonSerializer.DeserializeAsync<T>(context.Request.Body, a.Options);
}
return context.RequestServices.GetRequiredService<T>();
}
}
public class From
{
internal string Name { get; set; }
internal ArgumentType Type { get; set; }
internal JsonSerializerOptions Options { get; set; }
public static From Query(string name) => new From { Name = name, Type = ArgumentType.Query };
public static From Route(string name) => new From { Name = name, Type = ArgumentType.Route };
public static From Form(string name) => new From { Name = name, Type = ArgumentType.Form };
public static From Body(JsonSerializerOptions options = null) => new From { Type = ArgumentType.Body, Options = options };
}
public enum ArgumentType
{
Service,
Query,
Route,
Form,
Body
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment