Reworked it so that it's fully action based.
- The action invoker factory is the entry point to an mvc application. - The default implementation will use an IActionDescriptorProvider with a IActionInvokerProvider to resolve an IActionInvoker to invoke.
This commit is contained in:
parent
b798736385
commit
307d2ea198
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionDescriptor
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionDescriptorProvider : IActionDescriptorProvider
|
||||
{
|
||||
public ActionDescriptor CreateDescriptor(RequestContext requestContext)
|
||||
{
|
||||
string controllerName = requestContext.RouteData.GetRouteValue("controller");
|
||||
string actionName = requestContext.RouteData.GetRouteValue("action");
|
||||
|
||||
return new ControllerBasedActionDescriptor
|
||||
{
|
||||
ControllerName = controllerName,
|
||||
ActionName = actionName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionInvokerFactory : IActionInvokerFactory
|
||||
{
|
||||
private readonly IActionResultFactory _actionResultFactory;
|
||||
private readonly IActionDescriptorProvider _actionDescriptorProvider;
|
||||
private readonly IActionInvokerProvider _actionInvokerProvider;
|
||||
|
||||
public ActionInvokerFactory(IActionResultFactory actionResultFactory,
|
||||
IActionDescriptorProvider actionDescriptorProvider,
|
||||
IActionInvokerProvider actionInvokerProvider)
|
||||
{
|
||||
_actionResultFactory = actionResultFactory;
|
||||
_actionDescriptorProvider = actionDescriptorProvider;
|
||||
_actionInvokerProvider = actionInvokerProvider;
|
||||
}
|
||||
|
||||
public IActionInvoker CreateInvoker(RequestContext requestContext)
|
||||
{
|
||||
ActionDescriptor descriptor = _actionDescriptorProvider.CreateDescriptor(requestContext);
|
||||
|
||||
return _actionInvokerProvider.GetInvoker(requestContext, descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionInvokerProvider : IActionInvokerProvider
|
||||
{
|
||||
private IActionResultFactory _actionResultFactory;
|
||||
private IServiceProvider _serviceProvider;
|
||||
|
||||
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_actionResultFactory = actionResultFactory;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public IActionInvoker GetInvoker(RequestContext requestContext, ActionDescriptor descriptor)
|
||||
{
|
||||
var controllerActionDescriptor = descriptor as ControllerBasedActionDescriptor;
|
||||
|
||||
if (controllerActionDescriptor != null)
|
||||
{
|
||||
return new ControllerActionInvoker(
|
||||
requestContext,
|
||||
controllerActionDescriptor,
|
||||
_actionResultFactory,
|
||||
_serviceProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public async Task ExecuteResultAsync(ControllerContext context)
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,34 +1,87 @@
|
|||
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 ControllerContext _context;
|
||||
private readonly RequestContext _requestContext;
|
||||
private readonly ControllerBasedActionDescriptor _descriptor;
|
||||
private readonly IActionResultFactory _actionResultFactory;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ControllerActionInvoker(ControllerContext context, IActionResultFactory actionResultFactory)
|
||||
public ControllerActionInvoker(RequestContext requestContext,
|
||||
ControllerBasedActionDescriptor descriptor,
|
||||
IActionResultFactory actionResultFactory,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_context = context;
|
||||
_requestContext = requestContext;
|
||||
_descriptor = descriptor;
|
||||
_actionResultFactory = actionResultFactory;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task InvokeActionAsync(string actionName)
|
||||
public Task InvokeActionAsync()
|
||||
{
|
||||
var method = _context.Controller.GetType().GetMethod(actionName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
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, _requestContext);
|
||||
|
||||
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}'", actionName));
|
||||
throw new InvalidOperationException(String.Format("Could not find action method '{0}'", _descriptor.ActionName));
|
||||
}
|
||||
|
||||
object actionReturnValue = method.Invoke(_context.Controller, null);
|
||||
object actionReturnValue = method.Invoke(controller, null);
|
||||
|
||||
IActionResult actionResult = _actionResultFactory.CreateActionResult(actionReturnValue);
|
||||
|
||||
return actionResult.ExecuteResultAsync(_context);
|
||||
return actionResult.ExecuteResultAsync(_requestContext);
|
||||
}
|
||||
|
||||
private void Initialize(object controller, RequestContext requestContext)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ControllerActionInvokerFactory : IActionInvokerFactory
|
||||
{
|
||||
private readonly IActionResultFactory _actionResultFactory;
|
||||
|
||||
public ControllerActionInvokerFactory(IActionResultFactory actionResultFactory)
|
||||
{
|
||||
_actionResultFactory = actionResultFactory;
|
||||
}
|
||||
|
||||
public IActionInvoker CreateInvoker(ControllerContext context)
|
||||
{
|
||||
return new ControllerActionInvoker(context, _actionResultFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ControllerBasedActionDescriptor : ActionDescriptor
|
||||
{
|
||||
public string ControllerName { get; set; }
|
||||
|
||||
public string ActionName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
get { return _singleton; }
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(ControllerContext context)
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
ResponseMessage = responseMessage;
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(ControllerContext context)
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
{
|
||||
var response = context.HttpContext.Response;
|
||||
response.StatusCode = (int)ResponseMessage.StatusCode;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
_statusCode = statusCode;
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(ControllerContext context)
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = _statusCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionDescriptorProvider
|
||||
{
|
||||
ActionDescriptor CreateDescriptor(RequestContext requestContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IActionInvoker
|
||||
{
|
||||
Task InvokeActionAsync(string actionName);
|
||||
Task InvokeActionAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionInvokerFactory
|
||||
{
|
||||
IActionInvoker CreateInvoker(ControllerContext context);
|
||||
IActionInvoker CreateInvoker(RequestContext requestContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionInvokerProvider
|
||||
{
|
||||
IActionInvoker GetInvoker(RequestContext requestContext, ActionDescriptor descriptor);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IActionResult
|
||||
{
|
||||
Task ExecuteResultAsync(ControllerContext context);
|
||||
Task ExecuteResultAsync(RequestContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,16 +48,22 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ActionDescriptor.cs" />
|
||||
<Compile Include="ActionDescriptorProvider.cs" />
|
||||
<Compile Include="ActionInvokerProvider.cs" />
|
||||
<Compile Include="ActionResultFactory.cs" />
|
||||
<Compile Include="ActionResultHelper.cs" />
|
||||
<Compile Include="ContentResult.cs" />
|
||||
<Compile Include="ControllerBasedActionDescriptor.cs" />
|
||||
<Compile Include="RequestContext.cs" />
|
||||
<Compile Include="EmptyResult.cs" />
|
||||
<Compile Include="HttpResponseMessageActionResult.cs" />
|
||||
<Compile Include="IActionDescriptorProvider.cs" />
|
||||
<Compile Include="IActionInvokerProvider.cs" />
|
||||
<Compile Include="IActionResult.cs" />
|
||||
<Compile Include="Controller.cs" />
|
||||
<Compile Include="ControllerActionInvoker.cs" />
|
||||
<Compile Include="ControllerActionInvokerFactory.cs" />
|
||||
<Compile Include="ControllerContext.cs" />
|
||||
<Compile Include="ActionInvokerFactory.cs" />
|
||||
<Compile Include="DefaultControllerFactory.cs" />
|
||||
<Compile Include="HttpStatusCodeResult.cs" />
|
||||
<Compile Include="IActionInvoker.cs" />
|
||||
|
|
@ -68,6 +74,7 @@
|
|||
<Compile Include="MvcHandler.cs" />
|
||||
<Compile Include="MvcServices.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Routing\IRouteData.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.CoreServices;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -23,65 +22,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public Task ExecuteAsync(IOwinContext context)
|
||||
{
|
||||
string[] parts = (context.Request.PathBase + context.Request.Path).Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// {controller}/{action}
|
||||
string controllerName = GetPartOrDefault(parts, 0, "HomeController");
|
||||
string actionName = GetPartOrDefault(parts, 1, "Index");
|
||||
|
||||
var factory = _serviceProvider.GetService<IControllerFactory>();
|
||||
object controller = factory.CreateController(context, controllerName);
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format("Couldn't find controller '{0}'.", controllerName));
|
||||
}
|
||||
|
||||
var controllerContext = new ControllerContext(context, controller);
|
||||
|
||||
Initialize(controller, controllerContext);
|
||||
var routeData = new FakeRouteData(context);
|
||||
|
||||
IActionInvokerFactory invokerFactory = _serviceProvider.GetService<IActionInvokerFactory>();
|
||||
var invoker = invokerFactory.CreateInvoker(controllerContext);
|
||||
var invoker = invokerFactory.CreateInvoker(new RequestContext(context, routeData));
|
||||
|
||||
return invoker.InvokeActionAsync(actionName);
|
||||
}
|
||||
|
||||
private void Initialize(object controller, ControllerContext controllerContext)
|
||||
{
|
||||
var controllerType = controller.GetType();
|
||||
|
||||
foreach (var prop in controllerType.GetProperties())
|
||||
{
|
||||
if (prop.Name == "Context")
|
||||
{
|
||||
if (prop.PropertyType == typeof(IOwinContext))
|
||||
{
|
||||
prop.SetValue(controller, controllerContext.HttpContext);
|
||||
}
|
||||
else if (prop.PropertyType == typeof(IDictionary<string, object>))
|
||||
{
|
||||
prop.SetValue(controller, controllerContext.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);
|
||||
}
|
||||
|
||||
private static string GetPartOrDefault(string[] parts, int index, string defaultValue)
|
||||
{
|
||||
return index < parts.Length ? parts[index] : defaultValue;
|
||||
return invoker.InvokeActionAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
public static void DoCallback(Action<Type, Type> callback)
|
||||
{
|
||||
callback(typeof(IControllerFactory), typeof(DefaultControllerFactory));
|
||||
callback(typeof(IActionInvokerFactory), typeof(ControllerActionInvokerFactory));
|
||||
callback(typeof(IActionInvokerFactory), typeof(ActionInvokerFactory));
|
||||
callback(typeof(IActionResultHelper), typeof(ActionResultHelper));
|
||||
callback(typeof(IActionResultFactory), typeof(ActionResultFactory));
|
||||
|
||||
// TODO: Should be many
|
||||
callback(typeof(IActionDescriptorProvider), typeof(ActionDescriptorProvider));
|
||||
callback(typeof(IActionInvokerProvider), typeof(ActionInvokerProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ControllerContext
|
||||
public class RequestContext
|
||||
{
|
||||
public ControllerContext(IOwinContext context, object controller)
|
||||
public RequestContext(IOwinContext context, IRouteData routeData)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
if (controller == null)
|
||||
if (routeData == null)
|
||||
{
|
||||
throw new ArgumentNullException("controller");
|
||||
throw new ArgumentNullException("routeData");
|
||||
}
|
||||
|
||||
HttpContext = context;
|
||||
Controller = controller;
|
||||
RouteData = routeData;
|
||||
}
|
||||
|
||||
public virtual object Controller { get; set; }
|
||||
public virtual IRouteData RouteData { get; set; }
|
||||
|
||||
public virtual IOwinContext HttpContext { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using Microsoft.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Routing
|
||||
{
|
||||
// Move to routing middleware
|
||||
public interface IRouteData
|
||||
{
|
||||
string GetRouteValue(string name);
|
||||
}
|
||||
|
||||
public class FakeRouteData : IRouteData
|
||||
{
|
||||
private readonly string[] _parts;
|
||||
|
||||
public FakeRouteData(IOwinContext context)
|
||||
{
|
||||
_parts = (context.Request.PathBase + context.Request.Path).Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string GetRouteValue(string name)
|
||||
{
|
||||
if (name.Equals("controller", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetPartOrDefault(0, "HomeController");
|
||||
}
|
||||
else if (name.Equals("action", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetPartOrDefault(1, "Index");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetPartOrDefault(int index, string defaultValue)
|
||||
{
|
||||
return index < _parts.Length ? _parts[index] : defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue