Skip to content

Instantly share code, notes, and snippets.

@milutinovici
Last active August 29, 2015 14:16
Show Gist options
  • Save milutinovici/9bc3c22fc962175c8084 to your computer and use it in GitHub Desktop.
Save milutinovici/9bc3c22fc962175c8084 to your computer and use it in GitHub Desktop.
asp.net 5 generic controllers
public class GenericActionInvoker : ControllerActionInvoker
{
protected override async Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext)
{
var actionMethodInfo = _descriptor.MethodInfo;
//find action
if(actionExecutingContext.Controller.GetType().IsGenericType)
{
var parameters = actionMethodInfo.GetParameters().Select(x => x.ParameterType).ToArray();
actionMethodInfo = actionExecutingContext.Controller.GetType().GetMethod(actionMethodInfo.Name, parameters);
}
var actionReturnValue = await ControllerActionExecutor.ExecuteAsync(actionMethodInfo, actionExecutingContext.Controller, actionExecutingContext.ActionArguments);
var actionResult = CreateActionResult(
actionMethodInfo.ReturnType,
actionReturnValue);
return actionResult;
}
}
public class GenericActionInvokerProvider : IActionInvokerProvider
{
public void OnProvidersExecuting(ActionInvokerProviderContext context)
{
var actionDescriptor = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
if (actionDescriptor != null)
{
// essentially just calling different constructor
context.Result = new GenericActionInvoker(
context.ActionContext,
_filterProviders,
_controllerFactory,
actionDescriptor,
_inputFormattersProvider,
_argumentBinder,
_modelBinderProvider,
_modelValidationProviderProvider,
_valueProviderFactoryProvider,
_actionBindingContextAccessor);
}
}
}
public class GenericControllerFactory : DefaultControllerFactory
{
//part of route that will represent generic type parameter
private const string TypeKey = "type";
private readonly IControllerActivator _controllerActivator;
public GenericControllerFactory(IControllerActivator controllerActivator) : base(controllerActivator)
{
_controllerActivator = controllerActivator;
}
// should be override
public override object CreateController(ActionContext actionContext)
{
var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
if (actionDescriptor == null)
{
throw new ArgumentException("ReflectedActionDescriptor", "actionContext");
}
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
//helper class where i registered allowed types for generic parameters
if (controllerType.IsGenericType)
{
var genericType = EntityHelper.GetType(GetGenericType(actionContext.RouteData));
controllerType = controllerType.MakeGenericType(genericType);
}
var controller = _controllerActivator.Create(actionContext, controllerType);
base.ActivateProperties(controller, actionContext);
return controller;
}
//get generic type from route
private string GetGenericType(RouteData routeData)
{
if (routeData == null)
{
return null;
}
// Look up type in route data
object typeName = null;
routeData.Values.TryGetValue(TypeKey, out typeName);
return (string)typeName;
}
}
public class GenericControllerModelBuilder : DefaultControllerModelBuilder
{
protected override ControllerModel CreateControllerModel(TypeInfo typeInfo)
{
var attributes = typeInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
var controllerModel = new ControllerModel(typeInfo, attributes);
//remove "`1" from generic type names
var name = typeInfo.Name.EndsWith("`1") ? typeInfo.Name.Substring(0, typeInfo.Name.Length - "`1".Length) : typeInfo.Name;
controllerModel.ControllerName = name.EndsWith(nameof(Controller), StringComparison.OrdinalIgnoreCase) ?
name.Substring(0, name.Length - nameof(Controller).Length) : name;
....
}
}
public class GenericControllerTypeProvider : DefaultControllerTypeProvider
{
private const string ControllerTypeName = nameof(Controller);
private static readonly TypeInfo ControllerTypeInfo = typeof(Controller).GetTypeInfo();
private static readonly TypeInfo ObjectTypeInfo = typeof(object).GetTypeInfo();
//just removed isGeneric check
protected override bool IsController(TypeInfo typeInfo, ISet<Assembly> candidateAssemblies)
{
if (!typeInfo.IsClass)
{
return false;
}
if (typeInfo.IsAbstract)
{
return false;
}
if (!typeInfo.IsPublic)
{
return false;
}
if (!typeInfo.Name.EndsWith(ControllerTypeName, StringComparison.OrdinalIgnoreCase) &&
!DerivesFromController(typeInfo, candidateAssemblies))
{
return false;
}
if (typeInfo.IsDefined(typeof(NonControllerAttribute)))
{
return false;
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment