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.FileSystems;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Startup
|
||||
|
|
@ -19,6 +20,9 @@ namespace Microsoft.AspNet.Mvc.Startup
|
|||
Add<IActionResultHelper, ActionResultHelper>();
|
||||
Add<IActionResultFactory, ActionResultFactory>();
|
||||
Add<IActionDescriptorProvider, TypeMethodBasedActionDescriptorProvider>();
|
||||
Add<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
||||
Add<IValueProviderFactory, RouteValueValueProviderFactory>();
|
||||
Add<IValueProviderFactory, QueryStringValueProviderFactory>();
|
||||
Add<IActionInvokerProvider, ActionInvokerProvider>();
|
||||
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
||||
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultActionSelector : IActionSelector
|
||||
{
|
||||
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;
|
||||
_valueProviderFactory = valueProviderFactories;
|
||||
}
|
||||
|
||||
public ActionDescriptor Select(RequestContext context)
|
||||
|
|
@ -22,7 +25,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
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)
|
||||
|
|
@ -36,5 +51,65 @@ namespace Microsoft.AspNet.Mvc
|
|||
(descriptor.MethodConstraints == null || descriptor.MethodConstraints.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 IActionDiscoveryConventions _conventions;
|
||||
private readonly IControllerDescriptorFactory _controllerDescriptorFactory;
|
||||
private readonly IParameterDescriptorFactory _parameterDescriptorFactory;
|
||||
|
||||
public TypeMethodBasedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||
IActionDiscoveryConventions conventions,
|
||||
IControllerDescriptorFactory controllerDescriptorFactory)
|
||||
IControllerDescriptorFactory controllerDescriptorFactory,
|
||||
IParameterDescriptorFactory parameterDescriptorFactory)
|
||||
{
|
||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||
_conventions = conventions;
|
||||
_controllerDescriptorFactory = controllerDescriptorFactory;
|
||||
_parameterDescriptorFactory = parameterDescriptorFactory;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
@ -77,6 +80,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
ad.RouteConstraints.Add(new RouteDataActionConstraint("action", RouteKeyHandling.DenyKey));
|
||||
}
|
||||
|
||||
ad.Parameters = methodInfo.GetParameters().Select(p => _parameterDescriptorFactory.GetDescriptor(p)).ToList();
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue