示例#1
0
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            string         prefix;
            TypeSegment    cast;
            IEdmProperty   property      = GetProperty(odataPath, httpMethod, out prefix, out cast);
            IEdmEntityType declaringType = property == null ? null : property.DeclaringType as IEdmEntityType;

            if (declaringType != null)
            {
                ControllerActionDescriptor actionDescriptor;
                if (cast == null)
                {
                    actionDescriptor = actionDescriptors.FindMatchingAction(
                        prefix + property.Name + "From" + declaringType.Name,
                        prefix + property.Name);
                }
                else
                {
                    IEdmComplexType typeCast;
                    if (cast.EdmType.TypeKind == EdmTypeKind.Collection)
                    {
                        typeCast = ((IEdmCollectionType)cast.EdmType).ElementType.AsComplex().ComplexDefinition();
                    }
                    else
                    {
                        typeCast = (IEdmComplexType)cast.EdmType;
                    }

                    // for example: GetCityOfSubAddressFromVipCustomer or GetCityOfSubAddress
                    actionDescriptor = actionDescriptors.FindMatchingAction(
                        prefix + property.Name + "Of" + typeCast.Name + "From" + declaringType.Name,
                        prefix + property.Name + "Of" + typeCast.Name);
                }

                if (actionDescriptor != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                        routeContext.AddKeyValueToRouteData(keyValueSegment);
                    }

                    return(actionDescriptor);
                }
            }

            return(null);
        }
示例#2
0
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request   = routeContext.HttpContext.Request;

            if (odataPath.PathTemplate == "~/entityset/key" ||
                odataPath.PathTemplate == "~/entityset/key/cast")
            {
                string httpMethod = request.Method.ToUpperInvariant();
                string httpMethodName;
                switch (httpMethod)
                {
                case ODataRouteConstants.HttpGet:
                    httpMethodName = "Get";
                    break;

                case ODataRouteConstants.HttpPut:
                    httpMethodName = "Put";
                    break;

                case ODataRouteConstants.HttpPatch:
                    httpMethodName = "Patch";
                    break;

                case ODataRouteConstants.HttpDelete:
                    httpMethodName = "Delete";
                    break;

                default:
                    return(null);
                }

                Contract.Assert(httpMethodName != null);

                IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType;

                // e.g. Try GetCustomer first, then fallback on Get action name
                ActionDescriptor actionDescriptor = actionDescriptors.FindMatchingAction(
                    httpMethodName + entityType.Name,
                    httpMethodName);

                if (actionDescriptor != null)
                {
                    KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                    routeContext.AddKeyValueToRouteData(keySegment);
                    return(actionDescriptor);
                }
            }

            return(null);
        }
示例#3
0
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            // TODO: do we need to match the action parameters? to match ODataActionParameters or one by one?

            ODataPath   odataPath  = routeContext.HttpContext.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            if (httpMethod == ODataRouteConstants.HttpPost)
            {
                switch (odataPath.PathTemplate)
                {
                case "~/entityset/key/cast/action":
                case "~/entityset/key/action":
                    ControllerActionDescriptor descriptor = GetAction(odataPath).SelectAction(actionDescriptors, isCollection: false);
                    if (descriptor != null)
                    {
                        KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                        routeContext.AddKeyValueToRouteData(keySegment, descriptor);
                    }
                    return(descriptor);

                case "~/entityset/cast/action":
                case "~/entityset/action":
                    return(GetAction(odataPath).SelectAction(actionDescriptors, isCollection: true));

                case "~/singleton/action":
                case "~/singleton/cast/action":
                    return(GetAction(odataPath).SelectAction(actionDescriptors, isCollection: false));
                }
            }

            return(null);
        }
示例#4
0
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            if (httpMethod == ODataRouteConstants.HttpGet)
            {
                ActionDescriptor actionDescriptor = null;
                OperationSegment function         = null;
                switch (odataPath.PathTemplate)
                {
                case "~/entityset/key/cast/function":
                case "~/entityset/key/function":
                    function         = odataPath.Segments.Last() as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false);
                    if (actionDescriptor != null)
                    {
                        routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1], actionDescriptor);
                    }
                    break;

                case "~/entityset/key/cast/function/$count":
                case "~/entityset/key/function/$count":
                    function         = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false);
                    if (actionDescriptor != null)
                    {
                        routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1], actionDescriptor);
                    }
                    break;

                case "~/entityset/cast/function":
                case "~/entityset/function":
                    function         = odataPath.Segments.Last() as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: true);
                    break;

                case "~/entityset/cast/function/$count":
                case "~/entityset/function/$count":
                    function         = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: true);
                    break;

                case "~/singleton/function":
                case "~/singleton/cast/function":
                    function         = odataPath.Segments.Last() as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false);
                    break;

                case "~/singleton/function/$count":
                case "~/singleton/cast/function/$count":
                    function         = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false);
                    break;
                }

                if (actionDescriptor != null)
                {
                    routeContext.AddFunctionParameterToRouteData(function);
                    return(actionDescriptor);
                }
            }

            return(null);
        }
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            string actionNamePrefix = GetActionMethodPrefix(httpMethod);

            if (actionNamePrefix == null)
            {
                return(null);
            }

            if (odataPath.PathTemplate == "~/entityset/key/navigation" ||
                odataPath.PathTemplate == "~/entityset/key/navigation/$count" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation/$count" ||
                odataPath.PathTemplate == "~/singleton/navigation" ||
                odataPath.PathTemplate == "~/singleton/navigation/$count" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation/$count")
            {
                NavigationPropertySegment navigationSegment =
                    (odataPath.Segments.Last() as NavigationPropertySegment) ??
                    odataPath.Segments[odataPath.Segments.Count - 2] as NavigationPropertySegment;
                IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty;
                IEdmEntityType         declaringType      = navigationProperty.DeclaringType as IEdmEntityType;

                // It is not valid to *Post* to any non-collection valued navigation property.
                if (navigationProperty.TargetMultiplicity() != EdmMultiplicity.Many &&
                    httpMethod == ODataRouteConstants.HttpPost)
                {
                    return(null);
                }

                // It is not valid to *Put/Patch" to any collection-valued navigation property.
                if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many &&
                    (httpMethod == ODataRouteConstants.HttpPut || httpMethod == ODataRouteConstants.HttpPatch))
                {
                    return(null);
                }

                // *Get* is the only supported method for $count request.
                if (odataPath.Segments.Last() is CountSegment && httpMethod != ODataRouteConstants.HttpGet)
                {
                    return(null);
                }

                if (declaringType != null)
                {
                    // e.g. Try GetNavigationPropertyFromDeclaringType first, then fallback on GetNavigationProperty action name
                    ControllerActionDescriptor actionDescriptor = actionDescriptors.FindMatchingAction(
                        actionNamePrefix + navigationProperty.Name + "From" + declaringType.Name,
                        actionNamePrefix + navigationProperty.Name);

                    if (actionDescriptor != null)
                    {
                        if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                        {
                            KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                            routeContext.AddKeyValueToRouteData(keyValueSegment);
                        }

                        return(actionDescriptor);
                    }
                }
            }

            return(null);
        }
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            if (!IsSupportedRequestMethod(httpMethod))
            {
                return(null);
            }

            if (odataPath.PathTemplate == "~/entityset/key/navigation/$ref" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation/$ref" ||
                odataPath.PathTemplate == "~/singleton/navigation/$ref" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation/$ref")
            {
                NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments.Last();
                IEdmNavigationProperty        navigationProperty    = navigationLinkSegment.NavigationProperty;
                IEdmEntityType declaringType = navigationProperty.DeclaringEntityType();

                ActionDescriptor refActionName = FindRefActionName(actionDescriptors, navigationProperty, declaringType, httpMethod);
                if (refActionName != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }

                    routeContext.RouteData.Values[ODataRouteConstants.NavigationProperty] = navigationLinkSegment.NavigationProperty.Name;
                    return(refActionName);
                }
            }
            else if ((httpMethod == ODataRouteConstants.HttpDelete) && (
                         odataPath.PathTemplate == "~/entityset/key/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/entityset/key/cast/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/singleton/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/singleton/cast/navigation/key/$ref"))
            {
                // the second key segment is the last segment in the path.
                // So the previous of last segment is the navigation property link segment.
                NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments[odataPath.Segments.Count - 2];
                IEdmNavigationProperty        navigationProperty    = navigationLinkSegment.NavigationProperty;
                IEdmEntityType declaringType = navigationProperty.DeclaringEntityType();

                ActionDescriptor refActionName = FindRefActionName(actionDescriptors, navigationProperty, declaringType, httpMethod);
                if (refActionName != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }

                    routeContext.RouteData.Values[ODataRouteConstants.NavigationProperty] = navigationLinkSegment.NavigationProperty.Name;
                    routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments.Last(e => e is KeySegment), ODataRouteConstants.RelatedKey);
                    return(refActionName);
                }
            }

            return(null);
        }
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            ControllerActionDescriptor actionDescriptor      = null;
            DynamicPathSegment         dynamicPropertSegment = null;

            switch (odataPath.PathTemplate)
            {
            case "~/entityset/key/dynamicproperty":
            case "~/entityset/key/cast/dynamicproperty":
            case "~/singleton/dynamicproperty":
            case "~/singleton/cast/dynamicproperty":
                dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

                if (httpMethod == ODataRouteConstants.HttpGet)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName);
                    actionDescriptor = actionDescriptors.FindMatchingAction(actionNamePrefix);
                }
                break;

            case "~/entityset/key/property/dynamicproperty":
            case "~/entityset/key/cast/property/dynamicproperty":
            case "~/singleton/property/dynamicproperty":
            case "~/singleton/cast/property/dynamicproperty":
                dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

                PropertySegment propertyAccessSegment = odataPath.Segments[odataPath.Segments.Count - 2]
                                                        as PropertySegment;
                if (propertyAccessSegment == null)
                {
                    return(null);
                }

                EdmComplexType complexType = propertyAccessSegment.Property.Type.Definition as EdmComplexType;
                if (complexType == null)
                {
                    return(null);
                }

                if (httpMethod == ODataRouteConstants.HttpGet)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName);
                    actionDescriptor = actionDescriptors.FindMatchingAction(actionNamePrefix + "From" + propertyAccessSegment.Property.Name);
                }
                break;

            default:
                break;
            }

            if (actionDescriptors != null && dynamicPropertSegment != null)
            {
                if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                {
                    KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                    routeContext.AddKeyValueToRouteData(keyValueSegment);
                }

                routeContext.RouteData.Values[ODataRouteConstants.DynamicProperty] = dynamicPropertSegment.Identifier;
                var key   = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty;
                var value = new ODataParameterValue(dynamicPropertSegment.Identifier, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string)));
                routeContext.RouteData.Values[key] = value;
                request.ODataFeature().RoutingConventionsStore[key] = value;
                return(actionDescriptor);
            }

            return(null);
        }
示例#8
0
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request   = routeContext.HttpContext.Request;

            if (odataPath.PathTemplate == "~/entityset/key" ||
                odataPath.PathTemplate == "~/entityset/key/cast")
            {
                string httpMethod = request.Method.ToUpperInvariant();
                string httpMethodName;
                switch (httpMethod)
                {
                case ODataRouteConstants.HttpGet:
                    httpMethodName = "Get";
                    break;

                case ODataRouteConstants.HttpPut:
                    httpMethodName = "Put";
                    break;

                case ODataRouteConstants.HttpPatch:
                    httpMethodName = "Patch";
                    break;

                case ODataRouteConstants.HttpDelete:
                    httpMethodName = "Delete";
                    break;

                default:
                    return(null);
                }

                Contract.Assert(httpMethodName != null);

                IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType;

                // e.g. Try GetCustomer first, then fallback on Get action name
                var actions = actionDescriptors.FindMatchingActions(
                    httpMethodName + entityType.Name,
                    httpMethodName);
                // TODO: Cache these results
                var keyNames = entityType.Key().Select(k => k.Type.AsTypeDefinition().ShortQualifiedName()).ToArray();

                var actionDescriptor = actions.FirstOrDefault(action =>
                {
                    if (action.Parameters.Count == keyNames.Length &&
                        action.Parameters.All(
                            p =>
                    {
                        if (keyNames.Contains(p.ParameterType.EdmName()))
                        {
                            return(true);
                        }
                        var type = typeof(KeyValuePair <string, object>[]);
                        if (p.ParameterType == type)
                        {
                            return(true);
                        }
                        return(false);
                    }))
                    {
                        return(true);
                    }
                    if (action.Parameters.Count == 1 &&
                        typeof(IEnumerable <KeyValuePair <string, object> >).IsAssignableFrom(action.Parameters[0].ParameterType))
                    {
                        return(true);
                    }
                    return(false);
                });
                if (actionDescriptor != null)
                {
                    KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                    routeContext.AddKeyValueToRouteData(keySegment, actionDescriptor);
                    return(actionDescriptor);
                }
            }

            return(null);
        }