public void Ctor_SetRoutePrefixCorrectly(string prefix)
        {
            // Assert
            ODataRouteAttribute routeTemplate = new ODataRouteAttribute("({key})", prefix);

            // Act & Assert
            Assert.Equal("({key})", routeTemplate.PathTemplate);
            Assert.Equal(prefix, routeTemplate.RoutePrefix);
        }
Пример #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ActionModel         action    = context.Action;
            ODataRouteAttribute routeAttr = action.GetAttribute <ODataRouteAttribute>();

            if (routeAttr == null)
            {
                return(false);
            }
            string    prefix = context.Prefix;
            IEdmModel model  = context.Model;

            string routeTemplate = "";
            ODataRoutePrefixAttribute prefixAttr = action.Controller.GetAttribute <ODataRoutePrefixAttribute>();

            if (prefixAttr != null)
            {
                routeTemplate = prefixAttr.Prefix + "/";
            }
            routeTemplate += routeAttr.PathTemplate;

            SelectorModel selectorModel = action.Selectors.FirstOrDefault(s => s.AttributeRouteModel == null);

            if (selectorModel == null)
            {
                selectorModel = new SelectorModel();
                action.Selectors.Add(selectorModel);
            }

            string templateStr = string.IsNullOrEmpty(prefix) ? routeTemplate : $"{prefix}/{routeTemplate}";

            selectorModel.AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(templateStr)
            {
                Name = templateStr
            });
            selectorModel.EndpointMetadata.Add(new ODataEndpointMetadata(prefix, model, templateStr));

            return(true);
        }
Пример #3
0
        internal ODataRouteBuilderContext(
            HttpConfiguration configuration,
            ODataRoute route,
            HttpActionDescriptor actionDescriptor,
            IReadOnlyList <ApiParameterDescription> parameterDescriptions,
            ModelTypeBuilder modelTypeBuilder,
            ODataApiExplorerOptions options)
        {
            Contract.Requires(configuration != null);
            Contract.Requires(route != null);
            Contract.Requires(actionDescriptor != null);
            Contract.Requires(parameterDescriptions != null);
            Contract.Requires(modelTypeBuilder != null);
            Contract.Requires(options != null);

            serviceProvider    = configuration.GetODataRootContainer(route);
            EdmModel           = serviceProvider.GetRequiredService <IEdmModel>();
            AssembliesResolver = configuration.Services.GetAssembliesResolver();
            routeAttribute     = actionDescriptor.GetCustomAttributes <ODataRouteAttribute>().FirstOrDefault();
            RouteTemplate      = routeAttribute?.PathTemplate;
            Route                 = route;
            ActionDescriptor      = actionDescriptor;
            ParameterDescriptions = parameterDescriptions;
            Options               = options;
            UrlKeyDelimiter       = configuration.GetUrlKeyDelimiter();

            var container = EdmModel.EntityContainer;

            if (container == null)
            {
                IsRouteExcluded = true;
                return;
            }

            EntitySet = container.FindEntitySet(actionDescriptor.ControllerDescriptor.ControllerName);
            Operation = container.FindOperationImports(actionDescriptor.ActionName).FirstOrDefault()?.Operation ??
                        EdmModel.FindDeclaredOperations(container.Namespace + "." + actionDescriptor.ActionName).FirstOrDefault();
            ActionType = GetActionType(EntitySet, Operation);

            if (Operation?.IsAction() == true)
            {
                ConvertODataActionParametersToTypedModel(modelTypeBuilder, (IEdmAction)Operation);
            }
        }
        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);
        }