Overload Resolution Skeleton
This commit is contained in:
parent
941a12daea
commit
9d056167e8
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
|
namespace MvcSample
|
||||||
|
{
|
||||||
|
public class OverloadController
|
||||||
|
{
|
||||||
|
private readonly IActionResultHelper _result;
|
||||||
|
|
||||||
|
public OverloadController(IActionResultHelper result)
|
||||||
|
{
|
||||||
|
_result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Get()
|
||||||
|
{
|
||||||
|
return _result.Content("Get()");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Get(int id)
|
||||||
|
{
|
||||||
|
return _result.Content("Get(id)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Get(int id, string name)
|
||||||
|
{
|
||||||
|
return _result.Content("Get(id, name)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public interface IValueProvider
|
||||||
|
{
|
||||||
|
bool ContainsPrefix(string key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.FileSystems;
|
using Microsoft.AspNet.FileSystems;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Razor;
|
using Microsoft.AspNet.Mvc.Razor;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Startup
|
namespace Microsoft.AspNet.Mvc.Startup
|
||||||
|
|
@ -19,6 +20,9 @@ namespace Microsoft.AspNet.Mvc.Startup
|
||||||
Add<IActionResultHelper, ActionResultHelper>();
|
Add<IActionResultHelper, ActionResultHelper>();
|
||||||
Add<IActionResultFactory, ActionResultFactory>();
|
Add<IActionResultFactory, ActionResultFactory>();
|
||||||
Add<IActionDescriptorProvider, TypeMethodBasedActionDescriptorProvider>();
|
Add<IActionDescriptorProvider, TypeMethodBasedActionDescriptorProvider>();
|
||||||
|
Add<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
||||||
|
Add<IValueProviderFactory, RouteValueValueProviderFactory>();
|
||||||
|
Add<IValueProviderFactory, QueryStringValueProviderFactory>();
|
||||||
Add<IActionInvokerProvider, ActionInvokerProvider>();
|
Add<IActionInvokerProvider, ActionInvokerProvider>();
|
||||||
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
||||||
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public List<HttpMethodConstraint> MethodConstraints { get; set; }
|
public List<HttpMethodConstraint> MethodConstraints { get; set; }
|
||||||
|
|
||||||
public IEnumerable<IActionConstraint> DynamicConstraints { get; set; }
|
public List<IActionConstraint> DynamicConstraints { get; set; }
|
||||||
|
|
||||||
|
public List<ParameterDescriptor> Parameters { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DefaultActionSelector : IActionSelector
|
public class DefaultActionSelector : IActionSelector
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IActionDescriptorProvider> _actionDescriptorProviders;
|
private readonly IEnumerable<IActionDescriptorProvider> _actionDescriptorProviders;
|
||||||
|
private readonly IEnumerable<IValueProviderFactory> _valueProviderFactory;
|
||||||
|
|
||||||
public DefaultActionSelector(IEnumerable<IActionDescriptorProvider> actionDescriptorProviders)
|
public DefaultActionSelector(IEnumerable<IActionDescriptorProvider> actionDescriptorProviders, IEnumerable<IValueProviderFactory> valueProviderFactories)
|
||||||
{
|
{
|
||||||
_actionDescriptorProviders = actionDescriptorProviders;
|
_actionDescriptorProviders = actionDescriptorProviders;
|
||||||
|
_valueProviderFactory = valueProviderFactories;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionDescriptor Select(RequestContext context)
|
public ActionDescriptor Select(RequestContext context)
|
||||||
|
|
@ -22,7 +25,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
var allDescriptors = _actionDescriptorProviders.SelectMany(d => d.GetDescriptors());
|
var allDescriptors = _actionDescriptorProviders.SelectMany(d => d.GetDescriptors());
|
||||||
|
|
||||||
return allDescriptors.SingleOrDefault(d => Match(d, context));
|
var matching = allDescriptors.Where(ad => Match(ad, context)).ToList();
|
||||||
|
if (matching.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (matching.Count == 1)
|
||||||
|
{
|
||||||
|
return matching[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SelectBestCandidate(context, matching);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Match(ActionDescriptor descriptor, RequestContext context)
|
public bool Match(ActionDescriptor descriptor, RequestContext context)
|
||||||
|
|
@ -36,5 +51,65 @@ namespace Microsoft.AspNet.Mvc
|
||||||
(descriptor.MethodConstraints == null || descriptor.MethodConstraints.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)));
|
(descriptor.DynamicConstraints == null || descriptor.DynamicConstraints.All(c => c.Accept(context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual ActionDescriptor SelectBestCandidate(RequestContext context, List<ActionDescriptor> candidates)
|
||||||
|
{
|
||||||
|
var valueProviders = _valueProviderFactory.Select(vpf => vpf.CreateValueProvider(context)).ToArray();
|
||||||
|
|
||||||
|
var applicableCandiates = new List<ActionDescriptorCandidate>();
|
||||||
|
foreach (var action in candidates)
|
||||||
|
{
|
||||||
|
var isApplicable = true;
|
||||||
|
var candidate = new ActionDescriptorCandidate()
|
||||||
|
{
|
||||||
|
Action = action,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var parameter in action.Parameters.Where(p => !p.Binding.IsFromBody))
|
||||||
|
{
|
||||||
|
if (valueProviders.Any(vp => vp.ContainsPrefix(parameter.Binding.Prefix)))
|
||||||
|
{
|
||||||
|
candidate.FoundParameters++;
|
||||||
|
if (parameter.Binding.IsOptional)
|
||||||
|
{
|
||||||
|
candidate.FoundOptionalParameters++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!parameter.Binding.IsOptional)
|
||||||
|
{
|
||||||
|
isApplicable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isApplicable)
|
||||||
|
{
|
||||||
|
applicableCandiates.Add(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mostParametersSatisfied = applicableCandiates.GroupBy(c => c.FoundParameters).OrderByDescending(g => g.Key).First();
|
||||||
|
if (mostParametersSatisfied == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fewestOptionalParameters = mostParametersSatisfied.GroupBy(c => c.FoundOptionalParameters).OrderBy(g => g.Key).First().ToArray();
|
||||||
|
if (fewestOptionalParameters.Length > 1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The actions are ambiguious.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fewestOptionalParameters[0].Action;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ActionDescriptorCandidate
|
||||||
|
{
|
||||||
|
public ActionDescriptor Action { get; set; }
|
||||||
|
|
||||||
|
public int FoundParameters { get; set; }
|
||||||
|
|
||||||
|
public int FoundOptionalParameters { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultParameterDescriptorFactory : IParameterDescriptorFactory
|
||||||
|
{
|
||||||
|
public ParameterDescriptor GetDescriptor(ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
var bindingInfo = new ParameterBindingInfo()
|
||||||
|
{
|
||||||
|
IsOptional = parameter.IsOptional,
|
||||||
|
IsFromBody = IsFromBody(parameter),
|
||||||
|
Prefix = parameter.Name,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ParameterDescriptor()
|
||||||
|
{
|
||||||
|
Name = parameter.Name,
|
||||||
|
Binding = bindingInfo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsFromBody(ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
// Assume for now everything is read from value providers
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public interface IParameterDescriptorFactory
|
||||||
|
{
|
||||||
|
ParameterDescriptor GetDescriptor(ParameterInfo parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public interface IValueProviderFactory
|
||||||
|
{
|
||||||
|
IValueProvider CreateValueProvider(RequestContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
// This is a temporary placeholder
|
||||||
|
public class QueryStringValueProviderFactory : IValueProviderFactory
|
||||||
|
{
|
||||||
|
public IValueProvider CreateValueProvider(RequestContext context)
|
||||||
|
{
|
||||||
|
return new QueryStringValueProvider(context.HttpContext.Request.Query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class QueryStringValueProvider : IValueProvider
|
||||||
|
{
|
||||||
|
private readonly IReadableStringCollection _values;
|
||||||
|
|
||||||
|
public QueryStringValueProvider(IReadableStringCollection values)
|
||||||
|
{
|
||||||
|
_values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsPrefix(string key)
|
||||||
|
{
|
||||||
|
return _values.Get(key) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
// This is a temporary placeholder
|
||||||
|
public class RouteValueValueProviderFactory : IValueProviderFactory
|
||||||
|
{
|
||||||
|
public IValueProvider CreateValueProvider(RequestContext context)
|
||||||
|
{
|
||||||
|
return new ValueProvider(context.RouteValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
// This is a temporary placeholder
|
||||||
|
public class ValueProvider : IValueProvider
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, object> _values;
|
||||||
|
|
||||||
|
public ValueProvider(IDictionary<string, object> values)
|
||||||
|
{
|
||||||
|
_values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsPrefix(string key)
|
||||||
|
{
|
||||||
|
return _values.ContainsKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
// This is a placeholder and is missing things that we'll need for real model binding
|
||||||
|
public class ParameterBindingInfo
|
||||||
|
{
|
||||||
|
public bool IsOptional { get; set; }
|
||||||
|
|
||||||
|
public bool IsFromBody { get; set; }
|
||||||
|
|
||||||
|
public string Prefix { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class ParameterDescriptor
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public ParameterBindingInfo Binding { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,14 +9,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IControllerAssemblyProvider _controllerAssemblyProvider;
|
private readonly IControllerAssemblyProvider _controllerAssemblyProvider;
|
||||||
private readonly IActionDiscoveryConventions _conventions;
|
private readonly IActionDiscoveryConventions _conventions;
|
||||||
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||||
|
private readonly IParameterDescriptorFactory _parameterDescriptorFactory;
|
||||||
|
|
||||||
public TypeMethodBasedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
public TypeMethodBasedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||||
IActionDiscoveryConventions conventions,
|
IActionDiscoveryConventions conventions,
|
||||||
IControllerDescriptorFactory controllerDescriptorFactory)
|
IControllerDescriptorFactory controllerDescriptorFactory,
|
||||||
|
IParameterDescriptorFactory parameterDescriptorFactory)
|
||||||
{
|
{
|
||||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||||
_conventions = conventions;
|
_conventions = conventions;
|
||||||
_controllerDescriptorFactory = controllerDescriptorFactory;
|
_controllerDescriptorFactory = controllerDescriptorFactory;
|
||||||
|
_parameterDescriptorFactory = parameterDescriptorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ActionDescriptor> GetDescriptors()
|
public IEnumerable<ActionDescriptor> GetDescriptors()
|
||||||
|
|
@ -45,7 +48,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TypeMethodBasedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor, MethodInfo methodInfo, ActionInfo actionInfo)
|
private TypeMethodBasedActionDescriptor BuildDescriptor(ControllerDescriptor controllerDescriptor, MethodInfo methodInfo, ActionInfo actionInfo)
|
||||||
{
|
{
|
||||||
var ad = new TypeMethodBasedActionDescriptor
|
var ad = new TypeMethodBasedActionDescriptor
|
||||||
{
|
{
|
||||||
|
|
@ -77,6 +80,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", RouteKeyHandling.DenyKey));
|
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", RouteKeyHandling.DenyKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ad.Parameters = methodInfo.GetParameters().Select(p => _parameterDescriptorFactory.GetDescriptor(p)).ToList();
|
||||||
|
|
||||||
return ad;
|
return ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue