aspnetcore/Microsoft.AspNet.Mvc/ControllerActionInvoker.cs

89 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.CoreServices;
using Microsoft.Owin;
namespace Microsoft.AspNet.Mvc
{
public class ControllerActionInvoker : IActionInvoker
{
private readonly RequestContext _requestContext;
private readonly ControllerBasedActionDescriptor _descriptor;
private readonly IActionResultFactory _actionResultFactory;
private readonly IServiceProvider _serviceProvider;
public ControllerActionInvoker(RequestContext requestContext,
ControllerBasedActionDescriptor descriptor,
IActionResultFactory actionResultFactory,
IServiceProvider serviceProvider)
{
_requestContext = requestContext;
_descriptor = descriptor;
_actionResultFactory = actionResultFactory;
_serviceProvider = serviceProvider;
}
public Task InvokeActionAsync()
{
var factory = _serviceProvider.GetService<IControllerFactory>();
object controller = factory.CreateController(_requestContext.HttpContext, _descriptor.ControllerName);
if (controller == null)
{
throw new InvalidOperationException(String.Format("Couldn't find controller '{0}'.", _descriptor.ControllerName));
}
Initialize(controller);
var method = controller.GetType().GetMethod(_descriptor.ActionName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (method == null)
{
throw new InvalidOperationException(String.Format("Could not find action method '{0}'", _descriptor.ActionName));
}
object actionReturnValue = method.Invoke(controller, null);
// If it's not already an IActionResult then call into the factory
var actionResult = actionReturnValue as IActionResult ?? _actionResultFactory.CreateActionResult(actionReturnValue);
return actionResult.ExecuteResultAsync(_requestContext);
}
private void Initialize(object controller)
{
var controllerType = controller.GetType();
foreach (var prop in controllerType.GetProperties())
{
if (prop.Name == "Context")
{
if (prop.PropertyType == typeof(IOwinContext))
{
prop.SetValue(controller, _requestContext.HttpContext);
}
else if (prop.PropertyType == typeof(IDictionary<string, object>))
{
prop.SetValue(controller, _requestContext.HttpContext.Environment);
}
}
}
var method = controllerType.GetMethod("Initialize");
if (method == null)
{
return;
}
var args = method.GetParameters()
.Select(p => _serviceProvider.GetService(p.ParameterType)).ToArray();
method.Invoke(controller, args);
}
}
}