Action selection based on action descriptors
This commit is contained in:
parent
1d40372cc3
commit
941a12daea
|
|
@ -0,0 +1,12 @@
|
|||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace MvcSample
|
||||
{
|
||||
public class SimpleRest : Controller
|
||||
{
|
||||
public string Get()
|
||||
{
|
||||
return "Get method";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,10 @@ namespace MvcSample
|
|||
endpoint,
|
||||
"{controller}/{action}",
|
||||
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } }));
|
||||
router.Add(new TemplateRoute(
|
||||
endpoint,
|
||||
"{controller}",
|
||||
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" } }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
public class RazorViewEngine : IViewEngine
|
||||
{
|
||||
private static readonly string[] _viewLocationFormats = new[]
|
||||
private static readonly string[] _viewLocationFormats =
|
||||
{
|
||||
"/Views/{1}/{0}.cshtml",
|
||||
"/Views/Shared/{0}.cshtml",
|
||||
|
|
@ -28,11 +28,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
get { return _viewLocationFormats; }
|
||||
}
|
||||
|
||||
public async Task<ViewEngineResult> FindView(RequestContext requestContext, string viewName)
|
||||
public async Task<ViewEngineResult> FindView(object context, string viewName)
|
||||
{
|
||||
var actionContext = (ActionContext)context;
|
||||
|
||||
// TODO: We plan to change this on the next CR, so we don't have a strong depenedency directly on the specific
|
||||
// type of the action descriptor
|
||||
var actionDescriptor = _actionDescriptorProvider.CreateDescriptor(requestContext) as TypeMethodBasedActionDescriptor;
|
||||
ActionDescriptor actionDescriptor = actionContext.ActionDescriptor;
|
||||
|
||||
if (actionDescriptor == null)
|
||||
{
|
||||
|
|
@ -41,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
if (String.IsNullOrEmpty(viewName))
|
||||
{
|
||||
viewName = actionDescriptor.ActionName;
|
||||
viewName = actionDescriptor.Name;
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(viewName))
|
||||
|
|
@ -59,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
else
|
||||
{
|
||||
string controllerName = actionDescriptor.ControllerName;
|
||||
string controllerName = actionDescriptor.Path;
|
||||
var searchedLocations = new List<string>(_viewLocationFormats.Length);
|
||||
for (int i = 0; i < _viewLocationFormats.Length; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IViewEngine
|
||||
{
|
||||
Task<ViewEngineResult> FindView(RequestContext requestContext, string viewName);
|
||||
// TODO: Relayer to allow this to be ActionContext. We probably need the common MVC assembly
|
||||
Task<ViewEngineResult> FindView(object actionContext, string viewName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using Microsoft.AspNet.DependencyInjection;
|
||||
using Microsoft.AspNet.FileSystems;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Startup
|
||||
{
|
||||
|
|
@ -15,18 +13,16 @@ namespace Microsoft.AspNet.Mvc.Startup
|
|||
Services = new ServiceProvider();
|
||||
|
||||
Add<IControllerFactory, DefaultControllerFactory>();
|
||||
Add<IControllerDescriptorFactory, DefaultControllerDescriptorFactory>();
|
||||
Add<IActionSelector, DefaultActionSelector>();
|
||||
Add<IActionInvokerFactory, ActionInvokerFactory>();
|
||||
Add<IActionResultHelper, ActionResultHelper>();
|
||||
Add<IActionResultFactory, ActionResultFactory>();
|
||||
Add<IActionDescriptorProvider, TypeMethodBasedActionDescriptorProvider>();
|
||||
Add<IActionInvokerProvider, ActionInvokerProvider>();
|
||||
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
||||
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
||||
|
||||
// need singleton support here.
|
||||
// need a design for immutable caches at startup
|
||||
var provider = new DefaultControllerDescriptorProvider(new AppDomainControllerAssemblyProvider());
|
||||
provider.FinalizeSetup();
|
||||
|
||||
AddInstance<IControllerDescriptorProvider>(provider);
|
||||
AddInstance<IFileSystem>(new PhysicalFileSystem(appRoot));
|
||||
AddInstance<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionContext
|
||||
{
|
||||
public ActionContext(HttpContext httpContext, IDictionary<string, object> routeValues, ActionDescriptor actionDescriptor)
|
||||
{
|
||||
HttpContext = httpContext;
|
||||
RouteValues = routeValues;
|
||||
ActionDescriptor = actionDescriptor;
|
||||
}
|
||||
|
||||
public HttpContext HttpContext { get; private set; }
|
||||
|
||||
public IDictionary<string, object> RouteValues { get; private set; }
|
||||
|
||||
public ActionDescriptor ActionDescriptor { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionInfo
|
||||
{
|
||||
public string ActionName { get; set; }
|
||||
public string[] HttpMethods { get; set; }
|
||||
public bool RequireActionNameMatch { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
[DebuggerDisplay("{Path}:{Name}")]
|
||||
public class ActionDescriptor
|
||||
{
|
||||
public virtual string Path { get; set; }
|
||||
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
public List<RouteDataActionConstraint> RouteConstraints { get; set; }
|
||||
|
||||
public List<HttpMethodConstraint> MethodConstraints { get; set; }
|
||||
|
||||
public IEnumerable<IActionConstraint> DynamicConstraints { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionInvokerFactory : IActionInvokerFactory
|
||||
{
|
||||
|
|
@ -18,15 +15,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
_actionInvokerProvider = actionInvokerProvider;
|
||||
}
|
||||
|
||||
public IActionInvoker CreateInvoker(RequestContext requestContext)
|
||||
public IActionInvoker CreateInvoker(ActionContext actionContext)
|
||||
{
|
||||
ActionDescriptor routeContext = _routeContextProvider.CreateDescriptor(requestContext);
|
||||
if (routeContext == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _actionInvokerProvider.GetInvoker(requestContext, routeContext);
|
||||
return _actionInvokerProvider.GetInvoker(actionContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -18,14 +17,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public IActionInvoker GetInvoker(RequestContext requestContext, ActionDescriptor actionDescriptor)
|
||||
public IActionInvoker GetInvoker(ActionContext actionContext)
|
||||
{
|
||||
var ad = actionDescriptor as TypeMethodBasedActionDescriptor;
|
||||
var ad = actionContext.ActionDescriptor as TypeMethodBasedActionDescriptor;
|
||||
|
||||
if (ad != null)
|
||||
{
|
||||
return new TypeMethodBasedActionInvoker(
|
||||
requestContext,
|
||||
actionContext,
|
||||
ad,
|
||||
_actionResultFactory,
|
||||
_controllerFactory,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
_result = result;
|
||||
}
|
||||
|
||||
public IActionResult CreateActionResult(Type declaredReturnType, object actionReturnValue, RequestContext requestContext)
|
||||
public IActionResult CreateActionResult(Type declaredReturnType, object actionReturnValue, ActionContext actionContext)
|
||||
{
|
||||
// optimize common path
|
||||
IActionResult actionResult = actionReturnValue as IActionResult;
|
||||
var actionResult = actionReturnValue as IActionResult;
|
||||
|
||||
if (actionResult != null)
|
||||
{
|
||||
|
|
@ -38,17 +38,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new InvalidOperationException("HttpActionDescriptor_NoConverterForGenericParamterTypeExists");
|
||||
}
|
||||
|
||||
if (declaredReturnType.IsAssignableFrom(typeof(void)))
|
||||
if (declaredReturnType.IsAssignableFrom(typeof(void)) || actionReturnValue == null)
|
||||
{
|
||||
return new NoContentResult();
|
||||
}
|
||||
|
||||
if (actionReturnValue is string)
|
||||
var actionReturnString = actionReturnValue as string;
|
||||
|
||||
if (actionReturnString != null)
|
||||
{
|
||||
return new ContentResult
|
||||
{
|
||||
ContentType = "text/plain",
|
||||
Content = (string)actionReturnValue,
|
||||
Content = actionReturnString,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
|
@ -26,12 +26,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
response.ContentType = ContentType;
|
||||
}
|
||||
|
||||
//if (ContentEncoding != null)
|
||||
//{
|
||||
// response.ContentEncoding = ContentEncoding;
|
||||
//}
|
||||
|
||||
|
||||
if (Content != null)
|
||||
{
|
||||
await response.WriteAsync(Content);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
get { return _singleton; }
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
_statusCode = statusCode;
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = _statusCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
HttpResponse response = context.HttpContext.Response;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class NoContentResult : IActionResult
|
||||
{
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
|
@ -24,8 +23,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
#endif
|
||||
|
||||
await Task.FromResult(false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public ViewData ViewData { get; set; }
|
||||
|
||||
public async Task ExecuteResultAsync(RequestContext context)
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
|
@ -44,9 +44,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<IView> FindView(RequestContext requestContext, string viewName)
|
||||
private async Task<IView> FindView(ActionContext actionContext, string viewName)
|
||||
{
|
||||
ViewEngineResult result = await _viewEngine.FindView(requestContext, viewName);
|
||||
ViewEngineResult result = await _viewEngine.FindView(actionContext, viewName);
|
||||
if (!result.Success)
|
||||
{
|
||||
string locationsText = String.Join(Environment.NewLine, result.SearchedLocations);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
// consider mechanisms to filter assemblies upfront, so scanning cost is minimized and startup improved.
|
||||
// 1 - Does assembly reference the WebFx assembly (directly or indirectly). - Down side, object only controller not supported.
|
||||
// 2 - Remove well known assemblies (maintenance and composability cost)
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,31 +5,22 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class ControllerDescriptor
|
||||
{
|
||||
public ControllerDescriptor(Type controllerType, Assembly assembly)
|
||||
public ControllerDescriptor(TypeInfo controllerTypeInfo)
|
||||
{
|
||||
if (controllerType == null)
|
||||
if (controllerTypeInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("controllerType");
|
||||
throw new ArgumentNullException("controllerTypeInfo");
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
{
|
||||
throw new ArgumentNullException("assembly");
|
||||
}
|
||||
ControllerTypeInfo = controllerTypeInfo;
|
||||
|
||||
ControllerType = controllerType;
|
||||
Assembly = assembly;
|
||||
|
||||
ControllerName = controllerType.Name;
|
||||
AssemblyName = assembly.GetName().Name;
|
||||
Name = controllerTypeInfo.Name.EndsWith("Controller", StringComparison.Ordinal)
|
||||
? controllerTypeInfo.Name.Substring(0, controllerTypeInfo.Name.Length - "Controller".Length)
|
||||
: controllerTypeInfo.Name;
|
||||
}
|
||||
|
||||
public string ControllerName { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public string AssemblyName { get; private set; }
|
||||
|
||||
public Type ControllerType { get; private set; }
|
||||
|
||||
public Assembly Assembly { get; private set; }
|
||||
public TypeInfo ControllerTypeInfo { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultActionDiscoveryConventions : IActionDiscoveryConventions
|
||||
{
|
||||
private static readonly string[] _supportedHttpMethodsByConvention =
|
||||
{
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"HEAD",
|
||||
"OPTIONS",
|
||||
"PATCH",
|
||||
};
|
||||
|
||||
public virtual bool IsController(TypeInfo typeInfo)
|
||||
{
|
||||
if (typeInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("typeInfo");
|
||||
}
|
||||
|
||||
if (!typeInfo.IsClass ||
|
||||
typeInfo.IsAbstract ||
|
||||
typeInfo.ContainsGenericParameters)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeInfo.Name.Equals("Controller", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ||
|
||||
typeof(Controller).GetTypeInfo().IsAssignableFrom(typeInfo);
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<ActionInfo> GetActions(MethodInfo methodInfo)
|
||||
{
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("methodInfo");
|
||||
}
|
||||
|
||||
if (!IsValidMethod(methodInfo))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < _supportedHttpMethodsByConvention.Length; i++)
|
||||
{
|
||||
if (methodInfo.Name.StartsWith(_supportedHttpMethodsByConvention[i], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new [] {
|
||||
new ActionInfo()
|
||||
{
|
||||
HttpMethods = new[] { _supportedHttpMethodsByConvention[i] },
|
||||
ActionName = methodInfo.Name,
|
||||
RequireActionNameMatch = false,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Consider mapping Index here to both Get and also to Index
|
||||
|
||||
return new[]
|
||||
{
|
||||
new ActionInfo()
|
||||
{
|
||||
ActionName = methodInfo.Name,
|
||||
RequireActionNameMatch = true,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public virtual bool IsValidMethod(MethodInfo method)
|
||||
{
|
||||
return
|
||||
method.IsPublic &&
|
||||
!method.IsAbstract &&
|
||||
!method.IsConstructor &&
|
||||
!method.IsGenericMethod &&
|
||||
!method.IsSpecialName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultActionSelector : IActionSelector
|
||||
{
|
||||
private readonly IEnumerable<IActionDescriptorProvider> _actionDescriptorProviders;
|
||||
|
||||
public DefaultActionSelector(IEnumerable<IActionDescriptorProvider> actionDescriptorProviders)
|
||||
{
|
||||
_actionDescriptorProviders = actionDescriptorProviders;
|
||||
}
|
||||
|
||||
public ActionDescriptor Select(RequestContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
var allDescriptors = _actionDescriptorProviders.SelectMany(d => d.GetDescriptors());
|
||||
|
||||
return allDescriptors.SingleOrDefault(d => Match(d, context));
|
||||
}
|
||||
|
||||
public bool Match(ActionDescriptor descriptor, RequestContext context)
|
||||
{
|
||||
if (descriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException("descriptor");
|
||||
}
|
||||
|
||||
return (descriptor.RouteConstraints == null || descriptor.RouteConstraints.All(c => c.Accept(context))) &&
|
||||
(descriptor.MethodConstraints == null || descriptor.MethodConstraints.All(c => c.Accept(context))) &&
|
||||
(descriptor.DynamicConstraints == null || descriptor.DynamicConstraints.All(c => c.Accept(context)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultControllerDescriptorFactory : IControllerDescriptorFactory
|
||||
{
|
||||
public ControllerDescriptor CreateControllerDescriptor(TypeInfo typeInfo)
|
||||
{
|
||||
return new ControllerDescriptor(typeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultControllerDescriptorProvider : IControllerDescriptorProvider
|
||||
{
|
||||
private readonly IControllerAssemblyProvider _controllerAssemblyProvider;
|
||||
|
||||
public IReadOnlyDictionary<string, IEnumerable<ControllerDescriptor>> Controllers { get; protected set; }
|
||||
|
||||
public void FinalizeSetup()
|
||||
{
|
||||
Controllers = ScanAppDomain();
|
||||
}
|
||||
|
||||
public DefaultControllerDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider)
|
||||
{
|
||||
if (controllerAssemblyProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("controllerAssemblyProvider");
|
||||
}
|
||||
|
||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||
}
|
||||
|
||||
public IEnumerable<ControllerDescriptor> GetControllers(string controllerName)
|
||||
{
|
||||
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
controllerName += "Controller";
|
||||
}
|
||||
|
||||
if (Controllers == null)
|
||||
{
|
||||
throw new InvalidOperationException("Finalizing the setup must happen prior to accessing controllers");
|
||||
}
|
||||
|
||||
IEnumerable<ControllerDescriptor> descriptors = null;
|
||||
|
||||
if (Controllers.TryGetValue(controllerName, out descriptors))
|
||||
{
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<ControllerDescriptor>();
|
||||
}
|
||||
|
||||
public Dictionary<string, IEnumerable<ControllerDescriptor>> ScanAppDomain()
|
||||
{
|
||||
var dictionary = new Dictionary<string, IEnumerable<ControllerDescriptor>>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var assembly in _controllerAssemblyProvider.Assemblies)
|
||||
{
|
||||
foreach (var type in assembly.DefinedTypes.Where(IsController).Select(info => info.AsType()))
|
||||
{
|
||||
var descriptor = new ControllerDescriptor(type, assembly);
|
||||
|
||||
IEnumerable<ControllerDescriptor> controllerDescriptors;
|
||||
if (!dictionary.TryGetValue(type.Name, out controllerDescriptors))
|
||||
{
|
||||
controllerDescriptors = new List<ControllerDescriptor>();
|
||||
dictionary.Add(descriptor.ControllerName, controllerDescriptors);
|
||||
}
|
||||
|
||||
((List<ControllerDescriptor>)controllerDescriptors).Add(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public virtual bool IsController(TypeInfo typeInfo)
|
||||
{
|
||||
if (typeInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("typeInfo");
|
||||
}
|
||||
|
||||
bool validController = typeInfo.IsClass &&
|
||||
!typeInfo.IsAbstract &&
|
||||
!typeInfo.ContainsGenericParameters;
|
||||
|
||||
validController = validController && typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return validController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
|
|
@ -9,49 +8,37 @@ namespace Microsoft.AspNet.Mvc
|
|||
public class DefaultControllerFactory : IControllerFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IControllerDescriptorProvider _controllerDescriptorProvider;
|
||||
|
||||
public DefaultControllerFactory(IServiceProvider serviceProvider, IControllerDescriptorProvider controllerDescriptorProvider)
|
||||
public DefaultControllerFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_controllerDescriptorProvider = controllerDescriptorProvider;
|
||||
}
|
||||
|
||||
public object CreateController(HttpContext context, string controllerName)
|
||||
{
|
||||
var controllers = _controllerDescriptorProvider.GetControllers(controllerName);
|
||||
public object CreateController(HttpContext context, ActionDescriptor actionDescriptor)
|
||||
{
|
||||
var typedAd = actionDescriptor as TypeMethodBasedActionDescriptor;
|
||||
|
||||
if (controllers != null)
|
||||
if (typedAd == null)
|
||||
{
|
||||
try
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var controller = ActivatorUtilities.CreateInstance(_serviceProvider, typedAd.ControllerDescriptor.ControllerTypeInfo.AsType());
|
||||
|
||||
// TODO: How do we feed the controller with context (need DI improvements)
|
||||
var contextProperty = controller.GetType().GetRuntimeProperty("Context");
|
||||
|
||||
if (contextProperty != null)
|
||||
{
|
||||
var descriptor = controllers.SingleOrDefault();
|
||||
|
||||
if (descriptor != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var controller = ActivatorUtilities.CreateInstance(_serviceProvider, descriptor.ControllerType);
|
||||
|
||||
// TODO: How do we feed the controller with context (need DI improvements)
|
||||
var contextProperty = descriptor.ControllerType.GetRuntimeProperty("Context");
|
||||
|
||||
if (contextProperty != null)
|
||||
{
|
||||
contextProperty.SetMethod.Invoke(controller, new object[] { context });
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
catch (ReflectionTypeLoadException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw new InvalidOperationException("Ambiguity: Duplicate controllers match the controller name");
|
||||
contextProperty.SetMethod.Invoke(controller, new object[] { context });
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
catch (ReflectionTypeLoadException)
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class HttpMethodConstraint : IActionConstraint
|
||||
{
|
||||
private readonly IReadOnlyList<string> _methods;
|
||||
|
||||
// Empty collection means any method will be accepted.
|
||||
public HttpMethodConstraint(IEnumerable<string> httpMethods)
|
||||
{
|
||||
if (httpMethods == null)
|
||||
{
|
||||
throw new ArgumentNullException("httpMethods");
|
||||
}
|
||||
|
||||
var methods = new List<string>();
|
||||
|
||||
foreach (var method in httpMethods)
|
||||
{
|
||||
if (string.IsNullOrEmpty(method))
|
||||
{
|
||||
throw new ArgumentException("httpMethod cannot be null or empty");
|
||||
}
|
||||
|
||||
methods.Add(method);
|
||||
}
|
||||
|
||||
_methods = new ReadOnlyCollection<string>(methods);
|
||||
}
|
||||
|
||||
public IEnumerable<string> HttpMethods
|
||||
{
|
||||
get
|
||||
{
|
||||
return _methods;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Accept(RequestContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
if (_methods.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var request = context.HttpContext.Request;
|
||||
|
||||
return (HttpMethods.Any(m => m.Equals(request.Method, StringComparison.Ordinal)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionConstraint
|
||||
{
|
||||
bool Accept(RequestContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionDescriptorProvider
|
||||
{
|
||||
ActionDescriptor CreateDescriptor(RequestContext requestContext);
|
||||
IEnumerable<ActionDescriptor> GetDescriptors();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionDiscoveryConventions
|
||||
{
|
||||
bool IsController(TypeInfo typeInfo);
|
||||
|
||||
IEnumerable<ActionInfo> GetActions(MethodInfo methodInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionInvokerFactory
|
||||
{
|
||||
IActionInvoker CreateInvoker(RequestContext requestContext);
|
||||
IActionInvoker CreateInvoker(ActionContext actionContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionInvokerProvider
|
||||
{
|
||||
IActionInvoker GetInvoker(RequestContext requestContext, ActionDescriptor routeContext);
|
||||
IActionInvoker GetInvoker(ActionContext actionContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IActionResult
|
||||
{
|
||||
Task ExecuteResultAsync(RequestContext context);
|
||||
Task ExecuteResultAsync(ActionContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IActionResultFactory
|
||||
{
|
||||
IActionResult CreateActionResult(Type declaredReturnType, object actionReturnValue, RequestContext requestContext);
|
||||
IActionResult CreateActionResult(Type declaredReturnType, object actionReturnValue, ActionContext actionContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionSelector
|
||||
{
|
||||
ActionDescriptor Select(RequestContext context);
|
||||
|
||||
bool Match(ActionDescriptor descriptor, RequestContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IControllerDescriptorFactory
|
||||
{
|
||||
ControllerDescriptor CreateControllerDescriptor(TypeInfo type);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IControllerDescriptorProvider
|
||||
{
|
||||
IEnumerable<ControllerDescriptor> GetControllers(string controllerName);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public interface IControllerFactory
|
||||
{
|
||||
object CreateController(HttpContext context, string controllerName);
|
||||
object CreateController(HttpContext context, ActionDescriptor actionDescriptor);
|
||||
|
||||
void ReleaseController(object controller);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ActionDescriptor
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class RouteDataActionConstraint : IActionConstraint
|
||||
{
|
||||
private IEqualityComparer _comparer;
|
||||
|
||||
private RouteDataActionConstraint(string routeKey)
|
||||
{
|
||||
if (routeKey == null)
|
||||
{
|
||||
throw new ArgumentNullException("routeKey");
|
||||
}
|
||||
|
||||
RouteKey = routeKey;
|
||||
Comparer = StringComparer.OrdinalIgnoreCase; // Is this the right comparer for route values?
|
||||
}
|
||||
|
||||
public RouteDataActionConstraint(string routeKey, string routeValue)
|
||||
: this(routeKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(routeValue))
|
||||
{
|
||||
throw new ArgumentNullException("routeValue");
|
||||
}
|
||||
|
||||
RouteValue = routeValue;
|
||||
KeyHandling = RouteKeyHandling.RequireKey;
|
||||
}
|
||||
|
||||
public RouteDataActionConstraint(string routeKey, RouteKeyHandling keyHandling)
|
||||
: this(routeKey)
|
||||
{
|
||||
switch (keyHandling)
|
||||
{
|
||||
case RouteKeyHandling.AcceptAlways:
|
||||
case RouteKeyHandling.CatchAll:
|
||||
case RouteKeyHandling.DenyKey:
|
||||
case RouteKeyHandling.RequireKey:
|
||||
KeyHandling = keyHandling;
|
||||
break;
|
||||
default:
|
||||
#if NET45
|
||||
throw new InvalidEnumArgumentException("keyHandling", (int)keyHandling, typeof (RouteKeyHandling));
|
||||
#else
|
||||
throw new ArgumentOutOfRangeException("keyHandling");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public string RouteKey { get; private set; }
|
||||
public string RouteValue { get; private set; }
|
||||
public RouteKeyHandling KeyHandling { get; private set; }
|
||||
|
||||
public IEqualityComparer Comparer
|
||||
{
|
||||
get { return _comparer; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
_comparer = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Accept(RequestContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
var routeValues = context.RouteValues;
|
||||
|
||||
if (routeValues == null)
|
||||
{
|
||||
throw new ArgumentException("Need route values", "context");
|
||||
}
|
||||
|
||||
switch (KeyHandling)
|
||||
{
|
||||
case RouteKeyHandling.AcceptAlways:
|
||||
return true;
|
||||
case RouteKeyHandling.DenyKey:
|
||||
return !routeValues.ContainsKey(RouteKey);
|
||||
case RouteKeyHandling.CatchAll:
|
||||
return routeValues.ContainsKey(RouteKey);
|
||||
}
|
||||
|
||||
Debug.Assert(KeyHandling == RouteKeyHandling.RequireKey, "Unexpected routeValue");
|
||||
|
||||
object value;
|
||||
if (routeValues.TryGetValue(RouteKey, out value))
|
||||
{
|
||||
return Comparer.Equals(value, RouteValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
// This needs more thought, the intent is that we would be able to cache over this constraint without running the accept method.
|
||||
public enum RouteKeyHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires that the key will be in the route values, and that the content matches.
|
||||
/// </summary>
|
||||
RequireKey,
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the key will not be in the route values.
|
||||
/// </summary>
|
||||
DenyKey,
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the key will be in the route values, but ignore the content.
|
||||
/// </summary>
|
||||
CatchAll,
|
||||
|
||||
/// <summary>
|
||||
/// Always accept.
|
||||
/// </summary>
|
||||
AcceptAlways,
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private IActionInvokerFactory _actionInvokerFactory;
|
||||
private IActionSelector _actionSelector;
|
||||
|
||||
// Using service provider here to prevent ordering issues with configuration...
|
||||
// IE: creating routes before configuring services, vice-versa.
|
||||
|
|
@ -32,21 +33,46 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
}
|
||||
}
|
||||
|
||||
private IActionSelector ActionSelector
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_actionSelector == null)
|
||||
{
|
||||
_actionSelector = _services.GetService<IActionSelector>();
|
||||
}
|
||||
|
||||
return _actionSelector;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> Send(HttpContext context)
|
||||
{
|
||||
var routeValues = context.GetFeature<IRouteValues>();
|
||||
var requestContext = new RequestContext(context, routeValues.Values);
|
||||
|
||||
var invoker = ActionInvokerFactory.CreateInvoker(requestContext);
|
||||
if (invoker == null)
|
||||
var actionDescriptor = ActionSelector.Select(requestContext);
|
||||
|
||||
if (actionDescriptor == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
var invoker = ActionInvokerFactory.CreateInvoker(new ActionContext(context, routeValues.Values, actionDescriptor));
|
||||
|
||||
if (invoker == null)
|
||||
{
|
||||
await invoker.InvokeActionAsync();
|
||||
return true;
|
||||
var ex = new InvalidOperationException("Could not instantiate invoker for the actionDescriptor");
|
||||
|
||||
// Add tracing/logging (what do we think of this pattern of tacking on extra data on the exception?)
|
||||
ex.Data.Add("AD", actionDescriptor);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
||||
await invoker.InvokeActionAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,34 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
[DebuggerDisplay("CA {Path}:{Name}(RC-{RouteConstraints.Count})")]
|
||||
public class TypeMethodBasedActionDescriptor : ActionDescriptor
|
||||
{
|
||||
// TODO:
|
||||
// In the next PR the content of the descriptor is changing, and the string below will
|
||||
// be represented as route constraints, so for now leaving as is.
|
||||
public string ControllerName { get; set; }
|
||||
public override string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControllerDescriptor.Name;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new InvalidOperationException("Cannot override path");
|
||||
}
|
||||
}
|
||||
|
||||
public string ActionName { get; set; }
|
||||
public string ControllerName
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControllerDescriptor.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public MethodInfo MethodInfo { get; set; }
|
||||
|
||||
public ControllerDescriptor ControllerDescriptor { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,104 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class TypeMethodBasedActionDescriptorProvider : IActionDescriptorProvider
|
||||
{
|
||||
public ActionDescriptor CreateDescriptor(RequestContext requestContext)
|
||||
{
|
||||
var controllerName = (string)requestContext.RouteValues["controller"];
|
||||
var actionName = (string)requestContext.RouteValues["action"];
|
||||
private readonly IControllerAssemblyProvider _controllerAssemblyProvider;
|
||||
private readonly IActionDiscoveryConventions _conventions;
|
||||
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||
|
||||
return new TypeMethodBasedActionDescriptor()
|
||||
public TypeMethodBasedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||
IActionDiscoveryConventions conventions,
|
||||
IControllerDescriptorFactory controllerDescriptorFactory)
|
||||
{
|
||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||
_conventions = conventions;
|
||||
_controllerDescriptorFactory = controllerDescriptorFactory;
|
||||
}
|
||||
|
||||
public IEnumerable<ActionDescriptor> GetDescriptors()
|
||||
{
|
||||
var assemblies = _controllerAssemblyProvider.Assemblies;
|
||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||
var controllers = types.Where(_conventions.IsController);
|
||||
var controllerDescriptors = controllers.Select(t => _controllerDescriptorFactory.CreateControllerDescriptor(t)).ToArray();
|
||||
|
||||
foreach (var cd in controllerDescriptors)
|
||||
{
|
||||
ControllerName = controllerName,
|
||||
ActionName = actionName
|
||||
foreach (var methodInfo in cd.ControllerTypeInfo.DeclaredMethods)
|
||||
{
|
||||
var actionInfos = _conventions.GetActions(methodInfo);
|
||||
|
||||
if (actionInfos == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var actionInfo in actionInfos)
|
||||
{
|
||||
yield return BuildDescriptor(cd, methodInfo, actionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeMethodBasedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor, MethodInfo methodInfo, ActionInfo actionInfo)
|
||||
{
|
||||
var ad = new TypeMethodBasedActionDescriptor
|
||||
{
|
||||
RouteConstraints = new List<RouteDataActionConstraint>
|
||||
{
|
||||
new RouteDataActionConstraint("controller", controllerDescriptor.Name)
|
||||
},
|
||||
|
||||
Name = actionInfo.ActionName,
|
||||
ControllerDescriptor = controllerDescriptor,
|
||||
MethodInfo = methodInfo,
|
||||
};
|
||||
|
||||
var httpMethods = actionInfo.HttpMethods;
|
||||
if (httpMethods != null && httpMethods.Length > 0)
|
||||
{
|
||||
ad.MethodConstraints = new List<HttpMethodConstraint>
|
||||
{
|
||||
new HttpMethodConstraint(httpMethods)
|
||||
};
|
||||
}
|
||||
|
||||
if (actionInfo.RequireActionNameMatch)
|
||||
{
|
||||
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", actionInfo.ActionName));
|
||||
}
|
||||
else
|
||||
{
|
||||
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", RouteKeyHandling.DenyKey));
|
||||
}
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
private static void ApplyRest(TypeMethodBasedActionDescriptor descriptor, IEnumerable<string> httpMethods)
|
||||
{
|
||||
|
||||
descriptor.RouteConstraints.Add(new RouteDataActionConstraint("action", RouteKeyHandling.DenyKey));
|
||||
}
|
||||
|
||||
private static void ApplyRpc(TypeMethodBasedActionDescriptor descriptor, ActionInfo convention)
|
||||
{
|
||||
|
||||
var methods = convention.HttpMethods;
|
||||
|
||||
// rest action require specific methods, but RPC actions do not.
|
||||
if (methods != null)
|
||||
{
|
||||
descriptor.MethodConstraints = new List<HttpMethodConstraint>
|
||||
{
|
||||
new HttpMethodConstraint(methods)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,19 +8,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class TypeMethodBasedActionInvoker : IActionInvoker
|
||||
{
|
||||
private readonly RequestContext _requestContext;
|
||||
private readonly ActionContext _actionContext;
|
||||
private readonly TypeMethodBasedActionDescriptor _descriptor;
|
||||
private readonly IActionResultFactory _actionResultFactory;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IControllerFactory _controllerFactory;
|
||||
|
||||
public TypeMethodBasedActionInvoker(RequestContext requestContext,
|
||||
TypeMethodBasedActionDescriptor descriptor,
|
||||
IActionResultFactory actionResultFactory,
|
||||
IControllerFactory controllerFactory,
|
||||
IServiceProvider serviceProvider)
|
||||
public TypeMethodBasedActionInvoker(ActionContext actionContext,
|
||||
TypeMethodBasedActionDescriptor descriptor,
|
||||
IActionResultFactory actionResultFactory,
|
||||
IControllerFactory controllerFactory,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_requestContext = requestContext;
|
||||
_actionContext = actionContext;
|
||||
_descriptor = descriptor;
|
||||
_actionResultFactory = actionResultFactory;
|
||||
_controllerFactory = controllerFactory;
|
||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
IActionResult actionResult = null;
|
||||
|
||||
object controller = _controllerFactory.CreateController(_requestContext.HttpContext, _descriptor.ControllerName);
|
||||
object controller = _controllerFactory.CreateController(_actionContext.HttpContext, _descriptor);
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
Initialize(controller);
|
||||
|
||||
var method = controller.GetType().GetRuntimeMethods().FirstOrDefault(m => m.Name.Equals(_descriptor.ActionName, StringComparison.OrdinalIgnoreCase));
|
||||
var method = _descriptor.MethodInfo;
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
|
|
@ -51,12 +51,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
object actionReturnValue = method.Invoke(controller, null);
|
||||
|
||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _requestContext);
|
||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This will probably move out once we got filters
|
||||
return actionResult.ExecuteResultAsync(_requestContext);
|
||||
return actionResult.ExecuteResultAsync(_actionContext);
|
||||
}
|
||||
|
||||
private void Initialize(object controller)
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
if (prop.PropertyType == typeof(HttpContext))
|
||||
{
|
||||
prop.SetValue(controller, _requestContext.HttpContext);
|
||||
prop.SetValue(controller, _actionContext.HttpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue