Skip to content

Instantly share code, notes, and snippets.

@Tewr
Created April 1, 2019 10:04
Show Gist options
  • Save Tewr/e6aec3e7b430ee34f28d02d759de39ff to your computer and use it in GitHub Desktop.
Save Tewr/e6aec3e7b430ee34f28d02d759de39ff to your computer and use it in GitHub Desktop.
Reflection-based console app to call and debug simple task-based api's
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Good_Gaz.Services.SirsConsoleClient
{
partial class Program
{
static partial void Wain(IEnumerable<string> args) {
var targetApi = GetTargetApiInstance();
var targetApiType = targetApi.GetType();
var availableMethods = targetApiType.GetMethods();
var argsList = args.ToList();
var method = argsList.FirstOrDefault();
if (string.IsNullOrWhiteSpace(method))
{
OnHelpFlagged(targetApiType);
return;
}
argsList = argsList.Skip(1).ToList();
var methodInfo = availableMethods.FirstOrDefault(x => x.Name.Equals(method, StringComparison.OrdinalIgnoreCase));
if (methodInfo == null)
{
OnHelpFlagged(targetApiType);
return;
}
var ct = CancellationToken.None;
var parameterInfos = methodInfo.GetParameters().Where(x => x.ParameterType != typeof(CancellationToken)).ToList();
var types = parameterInfos.Select(x => x.ParameterType).ToArray();
var typedArgsList = new List<object>();
var ix = 0;
if (argsList.Count != types.Length)
{
throw new ArgumentException($"Method '{methodInfo.Name}' expects the following arguments: {string.Join(", ", parameterInfos.Select(pi => $"{pi.ParameterType} {pi.Name}")) }");
}
var resultProperty = typeof(Task<>).MakeGenericType(methodInfo.ReturnType.GetGenericArguments().FirstOrDefault())
.GetProperty(nameof(Task<object>.Result));
foreach (var strArg in argsList)
{
var targetType = types[ix];
try
{
var typeConverter = TypeDescriptor.GetConverter(targetType);
typedArgsList.Add(typeConverter.ConvertTo(strArg, targetType));
}
catch (Exception)
{
Console.Error.WriteLine($"Unable to cast parameter '{strArg}' to {targetType.Name}");
throw;
}
ix++;
}
typedArgsList.Add(ct);
var result = methodInfo.Invoke(targetApi, typedArgsList.ToArray());
if (methodInfo.ReturnType == typeof(void))
{
return;
}
if (result is Task taskResult)
{
taskResult?.Wait();
if (methodInfo.ReturnType == typeof(Task))
{
return;
}
// unwrap task
result = resultProperty?.GetValue(taskResult);
}
if (result == null)
{
Console.WriteLine("(null)");
}
else
{
Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
}
}
private static object GetTargetApiInstance()
{
var injector = new List<object>();
GetTargetApi(injector);
var targetApi = injector.FirstOrDefault();
return targetApi;
}
static partial void OnHelpFlagged()
{
OnHelpFlagged(GetTargetApiInstance().GetType());
}
static void OnHelpFlagged(Type targetType)
{
Console.Error.WriteLine($"Usage: {System.Reflection.Assembly.GetExecutingAssembly().GetName()} [-h|-v|-d] <{string.Join("|", targetType.GetMethods().Select(x => x.Name))}> [method parameters]");
}
static partial void OnVerboseFlagged()
{
IsVerbose = true;
}
public static bool IsVerbose { get; set; }
/// <summary>
/// Add the target api as the first member of the list.
/// </summary>
/// <param name="injectorList"></param>
static partial void GetTargetApi(List<object> injectorList);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment