public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup <string, HttpActionDescriptor> actionMap)
        {
            if (odataPath == null || controllerContext == null || actionMap == null)
            {
                return(null);
            }
            if (odataPath.PathTemplate == "~/entityset/key/property" ||
                odataPath.PathTemplate == "~/entityset/key/cast/property" ||
                odataPath.PathTemplate == "~/singleton/property" ||
                odataPath.PathTemplate == "~/singleton/cast/property")
            {
                var segment = odataPath.Segments[odataPath.Segments.Count - 1] as Microsoft.OData.UriParser.PropertySegment;

                if (segment != null)
                {
                    string actionName = actionMap.FindMatchingAction(ActionName);

                    if (actionName != null)
                    {
                        if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                        {
                            Microsoft.OData.UriParser.KeySegment keyValueSegment = odataPath.Segments[1] as Microsoft.OData.UriParser.KeySegment;
                            controllerContext.RouteData.Values[ODataRouteConstants.Key] = string.Join(",", keyValueSegment
                                                                                                      .Keys.Select(k => $"{k.Key}={k.Value}"));
                        }
                        controllerContext.RouteData.Values["propertyName"] = segment.Property.Name;
                        return(ActionName);
                    }
                }
            }
            return(null);
        }
Esempio n. 2
0
 //get all keys FromODataUri
 public static IEnumerable <KeyValuePair <string, object> > GetKeysFromODataUri(this ODataPath path)
 {
     foreach (var segment in path.Segments)
     {
         EdmType edmType = (EdmType)segment.EdmType;
         Microsoft.OData.UriParser.KeySegment keySegment = segment as Microsoft.OData.UriParser.KeySegment;
         if (keySegment != null)
         {
             return(keySegment.Keys);
         }
     }
     return(null);
 }
        public IEnumerable <ControllerActionDescriptor> SelectAction(RouteContext routeContext)
        {
            // Get a IActionDescriptorCollectionProvider from the global service provider
            IActionDescriptorCollectionProvider actionCollectionProvider =
                routeContext.HttpContext.RequestServices.GetRequiredService <IActionDescriptorCollectionProvider>();

            Contract.Assert(actionCollectionProvider != null);

            // Get OData path from HttpContext
            Microsoft.AspNet.OData.Routing.ODataPath odataPath = routeContext.HttpContext.ODataFeature().Path;
            HttpRequest request = routeContext.HttpContext.Request;

            if (request.Method == "GET" && odataPath.PathTemplate.Equals("~/entityset/key"))
            {
                string controllerName = odataPath.Segments[0].Identifier;
                // Get the list of action descriptors for this controller
                var actionDescriptors = actionCollectionProvider.ActionDescriptors.Items
                                        .Cast <ControllerActionDescriptor>()
                                        .Where(ad => ad.ControllerName == controllerName && ad.ActionName == "Get");

                foreach (var actionDescriptor in actionDescriptors.OrderByDescending(item => item.ActionName.Length))
                {
                    // We are only interested in examining actions with two parameters.
                    if (actionDescriptor.Parameters.Count != 1)
                    {
                        continue;
                    }

                    // See if an OdataRouteAttribute exists in the EndpointMetaData
                    ODataRouteAttribute oDataRouteAttribute = actionDescriptor.EndpointMetadata.OfType <ODataRouteAttribute>().FirstOrDefault();
                    string actionName = actionDescriptor.ActionName;
                    Microsoft.OData.UriParser.KeySegment keyFirst = odataPath.Segments[1] as Microsoft.OData.UriParser.KeySegment;
                    object keyParentId = keyFirst.Keys.ToList()[0].Value;
                    routeContext.RouteData.Values["odataPath"] = odataPath;
                    routeContext.RouteData.Values[actionDescriptor.Parameters[0].Name] = keyParentId;
                    routeContext.RouteData.Values[ODataRouteConstants.Key]             = keyParentId;
                    return(new[] { actionDescriptor });
                }
            }
            else if (request.Method == "GET" && odataPath.PathTemplate.Equals("~/entityset/key/unresolved"))
            {
                string controllerName = odataPath.Segments[0].Identifier;
                // Get the list of action descriptors for this controller
                var actionDescriptors = actionCollectionProvider.ActionDescriptors.Items
                                        .Cast <ControllerActionDescriptor>()
                                        .Where(ad => ad.ControllerName == controllerName);

                Microsoft.OData.UriParser.KeySegment keyFirst = odataPath.Segments[1] as Microsoft.OData.UriParser.KeySegment;
                object keyParentId = keyFirst.Keys.ToList()[0].Value;

                string unresolvedPattern = odataPath.Segments[2].ToString();
                // Go from longest named action to shortest to ensure that we don't confuse which action to
                // call if two actions have similar names such that one is a sub-set of the other.
                foreach (var actionDescriptor in actionDescriptors.OrderByDescending(item => item.ActionName.Length))
                {
                    // We are only interested in examining actions with two parameters.
                    if (actionDescriptor.Parameters.Count != 2)
                    {
                        continue;
                    }

                    // See if an OdataRouteAttribute exists in the EndpointMetaData
                    ODataRouteAttribute oDataRouteAttribute = actionDescriptor.EndpointMetadata.OfType <ODataRouteAttribute>().FirstOrDefault();
                    string actionName = actionDescriptor.ActionName;
                    if (oDataRouteAttribute != null)
                    {
                        string pathTemplate = oDataRouteAttribute.PathTemplate;
                        // The only template we want to match is in the shape "{ControllerName}({Parameter 1 Name})/{FunctionName}({Parameter 2 Name})
                        // If the pattern doesn't match that, then return null;
                        string compareStartPath = string.Format("{0}({{{1}}})/", controllerName, actionDescriptor.Parameters[0].Name);
                        string compareEndPath   = string.Format("({{{0}}})", actionDescriptor.Parameters[1].Name);

                        if (!pathTemplate.StartsWith(compareStartPath) || !pathTemplate.EndsWith(compareEndPath))
                        {
                            return(null);
                        }

                        actionName = pathTemplate.Substring(compareStartPath.Length, pathTemplate.Length - compareStartPath.Length - compareEndPath.Length);
                    }

                    // The basic assumption here is that the unresolved segment is a string that looks like this:
                    //      "SomeFunctionName(someParameterValue)"
                    // So the code below attempts to match the right action and strip out the parameter value
                    // with simple string manipulations.
                    unresolvedPattern = unresolvedPattern.Replace(actionName, string.Empty);

                    if (unresolvedPattern.StartsWith("("))
                    {
                        unresolvedPattern = unresolvedPattern.Substring(1);
                    }
                    else
                    {
                        continue;
                    }

                    if (unresolvedPattern.EndsWith(")"))
                    {
                        unresolvedPattern = unresolvedPattern.Substring(0, unresolvedPattern.Length - 1);
                    }
                    else
                    {
                        continue;
                    }

                    // What is left in unresolvedPattern should be a single value representing the
                    // second key value for the function.  Use what we know to set the route data values
                    // and return this matching action descriptor.
                    routeContext.RouteData.Values["odataPath"] = odataPath;
                    routeContext.RouteData.Values[actionDescriptor.Parameters[0].Name] = keyParentId;
                    routeContext.RouteData.Values[actionDescriptor.Parameters[1].Name] = unresolvedPattern;
                    routeContext.RouteData.Values[ODataRouteConstants.Key]             = keyParentId;
                    routeContext.RouteData.Values[ODataRouteConstants.RelatedKey]      = unresolvedPattern;
                    return(new[] { actionDescriptor });
                }
            }
            //else if ("~/entityset/key/navigation")

            return(null);
        }