public Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            //Calling this method to populate route data in PageContextMiddleware
            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                //_logger.NoActionsMatched(context.RouteData.Values);
                return(Task.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData = c.GetRouteData();

                return(Task.CompletedTask);
            };

            return(Task.CompletedTask);
        }
        /// <inheritdoc />
        public IReadOnlyList <ActionDescriptor> SelectCandidates(RouteContext context)
        {
            if (context.HttpContext.ODataFeature().IsValidODataRequest)
            {
                var options = _serviceProvider.GetRequiredService <IOptions <ODataOptions> >().Value;

                ActionDescriptor actionDescriptor = null;
                foreach (var convention in options.RoutingConventions)
                {
                    actionDescriptor = convention.SelectAction(context);
                    if (actionDescriptor != null)
                    {
                        break;
                    }
                }

                if (actionDescriptor != null)
                {
                    var list = new List <ActionDescriptor>
                    {
                        actionDescriptor
                    };

                    return(list.AsReadOnly());
                }
            }

            return(_selector.SelectCandidates(context));
        }
    /// <summary>
    ///     Return a list of controller candidates that match the custom controller and action names
    /// </summary>
    private IReadOnlyList <ControllerActionDescriptor>?FindControllerCandidates <T>(
        HttpContext httpContext,
        string?customControllerName,
        string?customActionName,
        string?defaultActionName,
        string?area = null)
    {
        // Use aspnetcore's IActionSelector to do the finding since it uses an optimized cache lookup
        var routeValues = new RouteValueDictionary
        {
            [ControllerToken] = customControllerName,
            [ActionToken]     = customActionName, // first try to find the custom action
        };

        if (area != null)
        {
            routeValues[AreaToken] = area;
        }

        var routeData    = new RouteData(routeValues);
        var routeContext = new RouteContext(httpContext)
        {
            RouteData = routeData
        };

        // try finding candidates for the custom action
        var candidates = _actionSelector.SelectCandidates(routeContext)?
                         .Cast <ControllerActionDescriptor>()
                         .Where(x => TypeHelper.IsTypeAssignableFrom <T>(x.ControllerTypeInfo))
                         .ToList();

        if (candidates?.Count > 0)
        {
            // return them if found
            return(candidates);
        }

        // now find for the default action since we couldn't find the custom one
        routeValues[ActionToken] = defaultActionName;
        candidates = _actionSelector.SelectCandidates(routeContext)?
                     .Cast <ControllerActionDescriptor>()
                     .Where(x => TypeHelper.IsTypeAssignableFrom <T>(x.ControllerTypeInfo))
                     .ToList();

        return(candidates);
    }
Ejemplo n.º 4
0
        public async Task Execute(HttpContext httpContext, string controller, string action, TextWriter writer)
        {
            var routeContext = new RouteContext(httpContext);

            routeContext.RouteData.Values["controller"] = controller;
            routeContext.RouteData.Values["action"]     = action;

            var candidates = _selector.SelectCandidates(routeContext);

            if (candidates == null || candidates.Count == 0)
            {
                throw new Exception("Action selector did not find any candidates.");
            }

            var descriptor = _selector.SelectBestCandidate(routeContext, candidates);

            if (descriptor == null)
            {
                throw new Exception("Action selector dit not find any action descriptor.");
            }

            var invoker = _invokerFactory.CreateInvoker(new ActionContext(routeContext.HttpContext, routeContext.RouteData, descriptor));

            if (invoker == null)
            {
                throw new Exception("Action invoker was null.");
            }

            // Save current response body so we can restore it later
            var currentOutputStream = routeContext.HttpContext.Response.Body;

            using (var outputStream = new MemoryStream())
            {
                // Set our new stream as response body
                routeContext.HttpContext.Response.Body = outputStream;

                try
                {
                    // Invoke controller
                    await invoker.InvokeAsync();

                    // Write the body data to the text writer
                    outputStream.Position = 0;

                    using (var reader = new StreamReader(outputStream))
                    {
                        var output = await reader.ReadToEndAsync();

                        await writer.WriteLineAsync(output);
                    }
                }
                finally
                {
                    // Restore the current response body
                    routeContext.HttpContext.Response.Body = currentOutputStream;
                }
            }
        }
Ejemplo n.º 5
0
        public new Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            string Host = context.HttpContext.Request.Host.Host;

            if (Host == "localhost")
            {
                // Do nothing, normal routing
            }
            else
            {
                context.RouteData.Values["controller"] = "Alternate";
                context.RouteData.Values.Add("Host", Host); // Add a variable for fun
            }

            //All the next code is copied from base class
            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                return(Task.CompletedTask);
            }

            var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor == null)
            {
                return(Task.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData = c.GetRouteData();

                var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                if (_actionContextAccessor != null)
                {
                    _actionContextAccessor.ActionContext = actionContext;
                }

                var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
                if (invoker == null)
                {
                    throw new InvalidOperationException();
                }

                return(invoker.InvokeAsync());
            };

            return(Task.CompletedTask);
        }
Ejemplo n.º 6
0
        public Task RouteAsync(RouteContext context)
        {
            IReadOnlyList <ActionDescriptor> candidates = _actionSelector.SelectCandidates(context);

            if (candidates.Count == 0)
            {
                String path = GetPath(context.HttpContext.Request.Path.Value);
                if (path == null)
                {
                    path = context.HttpContext.Request.Path.Value;
                    String[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                    candidates = GetOperationCadidates(segments);

                    int length = path.Length - segments.Last().Length - 2;
                    if (length > 0)
                    {
                        candidates = candidates.Where(c => String.Compare(c.AttributeRouteInfo.Template, 0, path, 1, length, StringComparison.OrdinalIgnoreCase) == 0).ToList();
                    }
                }
                else
                {
                    String[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                    candidates = SelectCandidates(_actionDescriptorCollectionProvider.ActionDescriptors.Items, segments, context.HttpContext.Request.Method);
                    if (candidates.Count == 0)
                    {
                        candidates = GetOperationCadidates(segments);
                    }
                }
                if (candidates.Count == 0)
                {
                    return(Task.CompletedTask);
                }
            }

            ActionDescriptor actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor != null)
            {
                context.Handler = async ctx =>
                {
                    var            actionContext = new ActionContext(context.HttpContext, ctx.GetRouteData(), actionDescriptor);
                    IActionInvoker actionInvoker = _actionInvokerFactory.CreateInvoker(actionContext);
                    if (actionInvoker == null)
                    {
                        return;
                    }

                    await actionInvoker.InvokeAsync();
                }
            }
            ;

            return(Task.CompletedTask);
        }
Ejemplo n.º 7
0
        public Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                _logger.NoActionsMatched();
                return(TaskCache.CompletedTask);
            }

            var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor == null)
            {
                _logger.NoActionsMatched();
                return(TaskCache.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData = c.GetRouteData();

                var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                if (_actionContextAccessor != null)
                {
                    _actionContextAccessor.ActionContext = actionContext;
                }

                var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
                if (invoker == null)
                {
                    throw new InvalidOperationException(
                              Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
                                  actionDescriptor.DisplayName));
                }

                return(invoker.InvokeAsync());
            };

            return(TaskCache.CompletedTask);
        }
Ejemplo n.º 8
0
        public Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                return(TaskCache.CompletedTask);
            }

            var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor == null)
            {
                return(TaskCache.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData = c.GetRouteData();

                foreach (var routeValue in routeData.Values)
                {
                    routeData.Values[routeValue.Key] = routeValue.Value.ToString().ToProperCase();
                }

                var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                if (_actionContextAccessor != null)
                {
                    _actionContextAccessor.ActionContext = actionContext;
                }

                var invoker = _actionInvokerFactory.CreateInvoker(actionContext);

                return(invoker.InvokeAsync());
            };

            return(TaskCache.CompletedTask);
        }
Ejemplo n.º 9
0
        public Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                return(Task.CompletedTask);
            }

            var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor == null)
            {
                if (_logger.IsEnabled(LogLevel.Error))
                {
                    _logger.LogError($"Could not identify an action for the supplied context.");
                }
                return(Task.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData     = c.GetRouteData();
                var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                var invoker       = _actionInvokerFactory.CreateInvoker(actionContext);
                if (invoker == null)
                {
                    throw new InvalidOperationException($"Could not invoke {actionDescriptor.DisplayName}");
                }

                return(invoker.InvokeAsync());
            };

            return(Task.CompletedTask);
        }
Ejemplo n.º 10
0
        public Task RouteAsync(RouteContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var candidates = _actionSelector.SelectCandidates(context);

            if (candidates == null || candidates.Count == 0)
            {
                //_logger.NoActionsMatched(context.RouteData.Values);
                return(Task.CompletedTask);
            }

            var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);

            if (actionDescriptor == null)
            {
                //_logger.NoActionsMatched(context.RouteData.Values);
                return(Task.CompletedTask);
            }

            context.Handler = (c) =>
            {
                var routeData = c.GetRouteData();

                var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                var invoker       = _actionInvokerFactory.CreateInvoker(actionContext);
                if (invoker == null)
                {
                    throw new InvalidOperationException($"Could not invoke {actionDescriptor.DisplayName}");
                }

                return(invoker.InvokeAsync());
            };

            return(Task.CompletedTask);
        }
        private ActionContext GetModuleActionContext(ActionContext actionContext, ModuleContext moduleContext, ModuleAction moduleAction)
        {
            RouteContext context = new RouteContext(actionContext.HttpContext);

            context.RouteData = new RouteData();
            context.RouteData.Values.Add("area", moduleContext.ModuleInfo.Name);
            context.RouteData.Values.Add("pageModuleId", moduleContext.PageModuleId);
            context.RouteData.Values.Add("controller", moduleAction.ControllerName);
            context.RouteData.Values.Add("action", moduleAction.ActionName);
            context.RouteData.PushState(actionContext.RouteData.Routers[0], null, null);


            var actionDescriptions = _actionSelector.SelectCandidates(context);
            var actionDescriptor   = _actionSelector.SelectBestCandidate(context, actionDescriptions);

            if (actionDescriptor == null)
            {
                throw new NullReferenceException("Action cannot be located, please check whether module has been installed properly");
            }

            var moduleActionContext = new ActionContext(actionContext.HttpContext, context.RouteData, actionDescriptor);

            return(moduleActionContext);
        }
Ejemplo n.º 12
0
        private ActionContext GetActionContext(RouteContext routeContext, bool isMVCAction = false)
        {
            IReadOnlyList <ActionDescriptor> actionDescriptors = null;

            if (isMVCAction)
            {
                //MVC Route Actions
                actionDescriptors = _actionSelector.SelectCandidates(routeContext);
            }
            else
            {
                var actions = _actionDescriptorCollectionProvider.ActionDescriptors;

                //Attributed Actions
                var attributeRoutedActions = actions.Items.Where(a => a.AttributeRouteInfo?.Template != null && !a.AttributeRouteInfo.SuppressPathMatching).ToList();

                actionDescriptors = attributeRoutedActions.Where(ad =>
                                                                 ad.RouteValues.ContainsKey("area") &&
                                                                 string.Equals(ad.RouteValues["area"], routeContext.RouteData.Values["area"] as string, StringComparison.OrdinalIgnoreCase) &&
                                                                 string.Equals(ad.RouteValues["controller"], routeContext.RouteData.Values["controller"] as string, StringComparison.OrdinalIgnoreCase) &&
                                                                 string.Equals(ad.RouteValues["action"], routeContext.RouteData.Values["action"] as string, StringComparison.OrdinalIgnoreCase)).ToList();
            }



            var actionDescriptor = _actionSelector.SelectBestCandidate(routeContext, actionDescriptors); //SelectBestCandidate(routeContext, actionDescriptors);

            if (actionDescriptor == null)
            {
                throw new NullReferenceException("Action cannot be located, please check whether module has been installed properly");
            }

            var moduleActionContext = new ActionContext(routeContext.HttpContext, routeContext.RouteData, actionDescriptor);

            return(moduleActionContext);
        }
        /// <summary>
        /// Creates a set of transformed route values that will be used to select an action.
        /// </summary>
        /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
        /// <param name="values">The route values associated with the current match.</param>
        /// <returns>A task which asynchronously returns a set of route values.</returns>
        public override ValueTask <RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            if (httpContext == null)
            {
                throw Error.ArgumentNull(nameof(httpContext));
            }

            if (values == null)
            {
                throw Error.ArgumentNull(nameof(values));
            }

            if (httpContext.ODataFeature().Path != null)
            {
                // Noted: if there's a route mapping with ODataPrefix == null,
                // for example: router.MapODataRoute(routeName: "odata", routePrefix: null, ...)
                // This route will match all requests.
                // Therefore, this route will be a candidate and its tranformer will be called.
                // So, we use the ODataPath setting to verify whether the request is transformed or not.
                // Maybe we have a better solution later.
                return(new ValueTask <RouteValueDictionary>(result: null));
            }

            (string routeName, object oDataPathValue) = values.GetODataRouteInfo();
            if (routeName != null)
            {
                HttpRequest request   = httpContext.Request;
                string      oDataPath = oDataPathValue as string;
                // Create request container
                request.CreateRequestContainer(routeName);

                // Check whether the request is a POST targeted at a resource path ending in /$query
                if (request.IsQueryRequest(oDataPath))
                {
                    request.TransformQueryRequest();

                    oDataPath = oDataPath.Substring(0, oDataPath.LastIndexOf('/' + ODataRouteConstants.QuerySegment, StringComparison.OrdinalIgnoreCase));
                    values[ODataRouteConstants.ODataPath] = oDataPath;
                }

                // We need to call Uri.GetLeftPart(), which returns an encoded Url.
                // The ODL parser does not like raw values.
                Uri    requestUri      = new Uri(request.GetEncodedUrl());
                string requestLeftPart = requestUri.GetLeftPart(UriPartial.Path);
                string queryString     = request.QueryString.HasValue ? request.QueryString.ToString() : null;

                // Call ODL to parse the Request URI.
                ODataPath path = ODataPathRouteConstraint.GetODataPath(oDataPath, requestLeftPart, queryString, () => request.GetRequestContainer());
                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.Path              = path;
                    odataFeature.RouteName         = routeName;
                    odataFeature.IsEndpointRouting = true; // mark as Endpoint routing

                    // Noted: we inject the ActionSelector and use it to select the best OData action.
                    // In .NET 5 or later, this maybe change.
                    RouteContext routeContext     = new RouteContext(httpContext);
                    var          condidates       = _selector.SelectCandidates(routeContext);
                    var          actionDescriptor = _selector.SelectBestCandidate(routeContext, condidates);
                    ControllerActionDescriptor controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
                    if (controllerActionDescriptor != null)
                    {
                        RouteValueDictionary newValues = new RouteValueDictionary();
                        foreach (var item in values)
                        {
                            newValues.Add(item.Key, item.Value);
                        }

                        foreach (var item in routeContext.RouteData.Values)
                        {
                            newValues[item.Key] = item.Value;
                        }

                        newValues["controller"] = controllerActionDescriptor.ControllerName;
                        newValues["action"]     = controllerActionDescriptor.ActionName;
                        newValues["odataPath"]  = oDataPathValue;

                        // Noted, here's a working around for mulitiple actions in same controller.
                        // For example, we have two "Get" methods in same controller, in order to help "EndpointSelector"
                        // to select the correct Endpoint, we save the ActionDescriptor value into ODataFeature.
                        odataFeature.ActionDescriptor = controllerActionDescriptor;
                        // Add handler to handle options calls. The routing criteria has been patched to allow endpoint discovery using the correct cors headers
                        if (request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase))
                        {
                            var metadata = actionDescriptor.EndpointMetadata;
                            // For option request can set this as the action will be handled by the cors middleware
                            var metadataCollection = metadata?.Any() == true
                                ? new EndpointMetadataCollection(metadata)
                                : EndpointMetadataCollection.Empty;
                            // This workaround allows the default cors middleware to read the annotations if the user has them enabling fine-grained cors access control with endpoints
                            var endpoint = new Endpoint(null, metadataCollection, controllerActionDescriptor.ActionName);
                            httpContext.SetEndpoint(endpoint);
                        }

                        return(new ValueTask <RouteValueDictionary>(newValues));
                    }
                }
                else
                {
                    // The request doesn't match this route so dispose the request container.
                    request.DeleteRequestContainer(true);
                }
            }

            return(new ValueTask <RouteValueDictionary>(result: null));
        }
        /// <summary>
        /// Creates a set of transformed route values that will be used to select an action.
        /// </summary>
        /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
        /// <param name="values">The route values associated with the current match.</param>
        /// <returns>A task which asynchronously returns a set of route values.</returns>
        public override ValueTask <RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            if (httpContext == null)
            {
                throw Error.ArgumentNull(nameof(httpContext));
            }

            if (values == null)
            {
                throw Error.ArgumentNull(nameof(values));
            }

            if (httpContext.ODataFeature().Path != null)
            {
                // Noted: if there's a route mapping with ODataPrefix == null,
                // for example: router.MapODataRoute(routeName: "odata", routePrefix: null, ...)
                // This route will match all requests.
                // Therefore, this route will be a candidate and its tranformer will be called.
                // So, we use the ODataPath setting to verify whether the request is transformed or not.
                // Maybe we have a better solution later.
                return(new ValueTask <RouteValueDictionary>(result: null));
            }

            (string routeName, object oDataPathValue) = values.GetODataRouteInfo();
            if (routeName != null)
            {
                HttpRequest request = httpContext.Request;

                // We need to call Uri.GetLeftPart(), which returns an encoded Url.
                // The ODL parser does not like raw values.
                Uri    requestUri      = new Uri(request.GetEncodedUrl());
                string requestLeftPart = requestUri.GetLeftPart(UriPartial.Path);
                string queryString     = request.QueryString.HasValue ? request.QueryString.ToString() : null;

                // Call ODL to parse the Request URI.
                ODataPath path = ODataPathRouteConstraint.GetODataPath(oDataPathValue as string, requestLeftPart, queryString, () => request.CreateRequestContainer(routeName));
                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.Path              = path;
                    odataFeature.RouteName         = routeName;
                    odataFeature.IsEndpointRouting = true; // mark as Endpoint routing

                    // Noted: we inject the ActionSelector and use it to select the best OData action.
                    // In .NET 5 or later, this maybe change.
                    RouteContext routeContext     = new RouteContext(httpContext);
                    var          condidates       = _selector.SelectCandidates(routeContext);
                    var          actionDescriptor = _selector.SelectBestCandidate(routeContext, condidates);
                    ControllerActionDescriptor controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
                    if (controllerActionDescriptor != null)
                    {
                        RouteValueDictionary newValues = new RouteValueDictionary();
                        foreach (var item in values)
                        {
                            newValues.Add(item.Key, item.Value);
                        }

                        foreach (var item in routeContext.RouteData.Values)
                        {
                            newValues[item.Key] = item.Value;
                        }

                        newValues["controller"] = controllerActionDescriptor.ControllerName;
                        newValues["action"]     = controllerActionDescriptor.ActionName;
                        newValues["odataPath"]  = oDataPathValue;

                        // Noted, here's a working around for mulitiple actions in same controller.
                        // For example, we have two "Get" methods in same controller, in order to help "EndpointSelector"
                        // to select the correct Endpoint, we save the ActionDescriptor value into ODataFeature.
                        odataFeature.ActionDescriptor = controllerActionDescriptor;

                        return(new ValueTask <RouteValueDictionary>(newValues));
                    }
                }
                else
                {
                    // The request doesn't match this route so dispose the request container.
                    request.DeleteRequestContainer(true);
                }
            }

            return(new ValueTask <RouteValueDictionary>(result: null));
        }