private void Apply(ControllerModel controller)
        {
            foreach (var action in controller.Actions)
            {
                foreach (var parameter in action.Parameters)
                {
                    if (parameter.BinderMetadata is IBinderMetadata)
                    {
                        // This has a binding behavior configured, just leave it alone.
                    }
                    else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
                    {
                        // Simple types are by-default from the URI.
                        parameter.BinderMetadata = new FromUriAttribute();
                    }
                    else
                    {
                        // Complex types are by-default from the body.
                        parameter.BinderMetadata = new FromBodyAttribute();
                    }

                    // If the parameter has a default value, we want to consider it as optional parameter by default.
                    var optionalMetadata = parameter.BinderMetadata as FromUriAttribute;
                    if (parameter.ParameterInfo.HasDefaultValue && optionalMetadata != null)
                    {
                        optionalMetadata.IsOptional = true;
                    }
                }
            }
        }
コード例 #2
0
        private List <OverloadedParameter> GetOverloadableParameters(ActionSelectorCandidate candidate)
        {
            if (candidate.Action.Parameters == null)
            {
                return(null);
            }

            var isOverloaded = false;

            foreach (var constraint in candidate.Constraints)
            {
                if (constraint is OverloadActionConstraint)
                {
                    isOverloaded = true;
                }
            }

            if (!isOverloaded)
            {
                return(null);
            }

            var parameters = new List <OverloadedParameter>();

            foreach (var parameter in candidate.Action.Parameters)
            {
                // We only consider parameters that are bound from the URL.
                if ((parameter.BinderMetadata is IRouteDataValueProviderMetadata ||
                     parameter.BinderMetadata is IQueryValueProviderMetadata) &&
                    ValueProviderResult.CanConvertFromString(parameter.ParameterType))
                {
                    var optionalMetadata = parameter.BinderMetadata as IOptionalBinderMetadata;
                    if (optionalMetadata == null || optionalMetadata.IsOptional)
                    {
                        // Optional parameters are ignored in overloading. If a parameter doesn't specify that it's
                        // required then treat it as optional (MVC default). WebAPI parameters will all by-default
                        // specify themselves as required unless they have a default value.
                        continue;
                    }

                    var nameProvider = parameter.BinderMetadata as IModelNameProvider;
                    var prefix       = nameProvider?.Name ?? parameter.Name;

                    parameters.Add(new OverloadedParameter()
                    {
                        ParameterDescriptor = parameter,
                        Prefix = prefix,
                    });
                }
            }

            return(parameters);
        }
コード例 #3
0
        private List <OverloadedParameter> GetOverloadableParameters(ActionSelectorCandidate candidate)
        {
            if (candidate.Action.Parameters == null)
            {
                return(null);
            }

            var isOverloaded = false;

            foreach (var constraint in candidate.Constraints)
            {
                if (constraint is OverloadActionConstraint)
                {
                    isOverloaded = true;
                }
            }

            if (!isOverloaded)
            {
                return(null);
            }

            var parameters = new List <OverloadedParameter>();

            foreach (var parameter in candidate.Action.Parameters)
            {
                // We only consider parameters that are bound from the URL.
                if ((parameter.BinderMetadata is IRouteDataValueProviderMetadata ||
                     parameter.BinderMetadata is IQueryValueProviderMetadata) &&
                    !parameter.IsOptional &&
                    ValueProviderResult.CanConvertFromString(parameter.ParameterType))
                {
                    var nameProvider = parameter.BinderMetadata as IModelNameProvider;
                    var prefix       = nameProvider?.Name ?? parameter.Name;

                    parameters.Add(new OverloadedParameter()
                    {
                        ParameterDescriptor = parameter,
                        Prefix = prefix,
                    });
                }
            }

            return(parameters);
        }
コード例 #4
0
        public void Apply(ActionModel action)
        {
            if (IsConventionApplicable(action.Controller))
            {
                var optionalParameters = new HashSet <string>();
                var uriBindingSource   = (new FromUriAttribute()).BindingSource;
                foreach (var parameter in action.Parameters)
                {
                    // Some IBindingSourceMetadata attributes like ModelBinder attribute return null
                    // as their binding source. Special case to ensure we do not ignore them.
                    if (parameter.BindingInfo?.BindingSource != null ||
                        parameter.Attributes.OfType <IBindingSourceMetadata>().Any())
                    {
                        // This has a binding behavior configured, just leave it alone.
                    }
                    else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
                    {
                        // Simple types are by-default from the URI.
                        parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
                        parameter.BindingInfo.BindingSource = uriBindingSource;
                    }
                    else
                    {
                        // Complex types are by-default from the body.
                        parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
                        parameter.BindingInfo.BindingSource = BindingSource.Body;
                    }

                    // For all non IOptionalBinderMetadata, which are not URL source (like FromQuery etc.) do not
                    // participate in overload selection and hence are added to the hashset so that they can be
                    // ignored in OverloadActionConstraint.
                    var optionalMetadata = parameter.Attributes.OfType <IOptionalBinderMetadata>().SingleOrDefault();
                    if (parameter.ParameterInfo.HasDefaultValue && parameter.BindingInfo.BindingSource == uriBindingSource ||
                        optionalMetadata != null && optionalMetadata.IsOptional ||
                        optionalMetadata == null && parameter.BindingInfo.BindingSource != uriBindingSource)
                    {
                        optionalParameters.Add(parameter.ParameterName);
                    }
                }

                action.Properties.Add("OptionalParameters", optionalParameters);
            }
        }
コード例 #5
0
 public void Apply(ApplicationModel application)
 {
     foreach (var controller in application.Controllers)
     {
         foreach (var action in controller.Actions)
         {
             foreach (var parameter in action.Parameters)
             {
                 if (parameter.BinderMetadata is IBinderMetadata || ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
                 {
                     // behavior configured or simple type so do nothing
                 }
                 else
                 {
                     // Complex types are by-default from the body.
                     parameter.BinderMetadata = new FromBodyAttribute();
                 }
             }
         }
     }
 }
コード例 #6
0
 private void Apply(ControllerModel model)
 {
     foreach (var action in model.Actions)
     {
         foreach (var parameter in action.Parameters)
         {
             if (parameter.BinderMetadata is IBinderMetadata)
             {
                 // This has a binding behavior configured, just leave it alone.
             }
             else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
             {
                 // Simple types are by-default from the URI.
                 parameter.BinderMetadata = new FromUriAttribute();
             }
             else
             {
                 // Complex types are by-default from the body.
                 parameter.BinderMetadata = new FromBodyAttribute();
             }
         }
     }
 }
 public void Apply(ApplicationModel application)
 {
     foreach (var controller in application.Controllers)
     {
         foreach (var action in controller.Actions)
         {
             foreach (var parameter in action.Parameters)
             {
                 if (parameter.BindingInfo?.BindingSource != null ||
                     parameter.Attributes.OfType <IBindingSourceMetadata>().Any() ||
                     ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
                 {
                     // behavior configured or simple type so do nothing
                 }
                 else
                 {
                     // Complex types are by-default from the body.
                     parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
                     parameter.BindingInfo.BindingSource = BindingSource.Body;
                 }
             }
         }
     }
 }
コード例 #8
0
        private List <OverloadedParameter> GetOverloadableParameters(ActionSelectorCandidate candidate)
        {
            if (candidate.Action.Parameters == null)
            {
                return(null);
            }

            var isOverloaded = false;

            foreach (var constraint in candidate.Constraints)
            {
                if (constraint is OverloadActionConstraint)
                {
                    isOverloaded = true;
                }
            }

            if (!isOverloaded)
            {
                return(null);
            }

            var    parameters = new List <OverloadedParameter>();
            object optionalParametersObject;

            candidate.Action.Properties.TryGetValue("OptionalParameters", out optionalParametersObject);
            var optionalParameters = (HashSet <string>)optionalParametersObject;

            foreach (var parameter in candidate.Action.Parameters)
            {
                // We only consider parameters that are marked as bound from the URL.
                var source = parameter.BindingInfo?.BindingSource;
                if (source == null)
                {
                    continue;
                }

                if ((source.CanAcceptDataFrom(BindingSource.Path) ||
                     source.CanAcceptDataFrom(BindingSource.Query)) &&
                    ValueProviderResult.CanConvertFromString(parameter.ParameterType))
                {
                    if (optionalParameters != null)
                    {
                        var isOptional = optionalParameters.Contains(parameter.Name);
                        if (isOptional)
                        {
                            // Optional parameters are ignored in overloading. If a parameter doesn't specify that it's
                            // required then treat it as optional (MVC default). WebAPI parameters will all by-default
                            // specify themselves as required unless they have a default value.
                            continue;
                        }
                    }

                    var prefix = parameter.BindingInfo?.BinderModelName ?? parameter.Name;

                    parameters.Add(new OverloadedParameter()
                    {
                        ParameterDescriptor = parameter,
                        Prefix = prefix,
                    });
                }
            }

            return(parameters);
        }
コード例 #9
0
        protected virtual async Task <ActionDescriptor> SelectBestCandidate(
            RouteContext context,
            List <ActionDescriptor> candidates)
        {
            var applicableCandiates = new List <ActionDescriptorCandidate>();

            foreach (var action in candidates)
            {
                var isApplicable = true;
                var candidate    = new ActionDescriptorCandidate()
                {
                    Action = action,
                };

                var actionContext        = new ActionContext(context, action);
                var actionBindingContext = await _bindingProvider.GetActionBindingContextAsync(actionContext);

                foreach (var parameter in action.Parameters.Where(p => p.ParameterBindingInfo != null))
                {
                    if (!ValueProviderResult.CanConvertFromString(parameter.ParameterBindingInfo.ParameterType))
                    {
                        continue;
                    }

                    if (await actionBindingContext.ValueProvider.ContainsPrefixAsync(
                            parameter.ParameterBindingInfo.Prefix))
                    {
                        candidate.FoundParameters++;
                        if (parameter.IsOptional)
                        {
                            candidate.FoundOptionalParameters++;
                        }
                    }
                    else if (!parameter.IsOptional)
                    {
                        isApplicable = false;
                        break;
                    }
                }

                if (isApplicable)
                {
                    applicableCandiates.Add(candidate);
                }
            }

            if (applicableCandiates.Count == 0)
            {
                return(null);
            }

            var mostParametersSatisfied =
                applicableCandiates
                .GroupBy(c => c.FoundParameters)
                .OrderByDescending(g => g.Key)
                .First();

            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);
        }