C# .NET5/MVC6中的异步路由约束(或其他约束)

C# .NET5/MVC6中的异步路由约束(或其他约束),c#,asp.net,.net,asp.net-mvc,asp.net-core-mvc,C#,Asp.net,.net,Asp.net Mvc,Asp.net Core Mvc,我需要创建一个路由约束,但是这个约束需要使用我的一个服务,并且这个服务方法使用异步 现在,理想情况下,从这个routeConstraint返回的数据,我希望传递给控制器,以便在被调用的操作中使用,如果约束已经满足 用户将调用带有额外参数的控制器,我们将调用myName。如果该值出现在数据库中,我希望该记录出现在控制器方法中 调用控制器的路径看起来是这样的,其中data是我的控制器的名称,myName是一个字符串,我需要检查它是否存在于数据库中 如果myName不存在,则不应调用控制器。如果是,

我需要创建一个路由约束,但是这个约束需要使用我的一个服务,并且这个服务方法使用异步

现在,理想情况下,从这个routeConstraint返回的数据,我希望传递给控制器,以便在被调用的操作中使用,如果约束已经满足

用户将调用带有额外参数的控制器,我们将调用myName。如果该值出现在数据库中,我希望该记录出现在控制器方法中

调用控制器的路径看起来是这样的,其中data是我的控制器的名称,myName是一个字符串,我需要检查它是否存在于数据库中

如果myName不存在,则不应调用控制器。如果是,则应调用该方法,但myName值可用

不确定我是否需要使用其他的路径约束

注意:
我无法将其作为参数添加到此控制器中的每个方法,因此请不要建议它。

您可以实现自己的
IRouter
,它由MVC6异步解析
IRouter
是每个路由实现的接口,因此您的操作级别较低

namespace Microsoft.AspNet.Routing
{
    public interface IRouter
    {
        // Populates route data (including route values) based on the
        // request
        Task RouteAsync(RouteContext context);

        // Derives a virtual path (URL) from a list of route values
        VirtualPathData GetVirtualPath(VirtualPathContext context);
    }
}
RouteAsync
执行以下操作:

  • 分析请求以确定其是否与路由匹配
  • 如果有匹配项,请设置路由值
  • 如果有匹配项,则将调用传递给下一个
    IRouter
    (通常是
    MvcRouteHandler
  • GetVirtualPath
    执行以下操作:

  • 比较一组管线值以查看它们是否与管线匹配
  • 如果匹配,则将路由值转换为虚拟路径(URL)。这通常与
    RouteAsync
    中的逻辑完全相反,因此我们生成匹配的相同URL
  • 框架返回对
    UrlHelper
    的任何调用的虚拟路径,例如
    ActionLink
    RouteLink
    发出的调用
  • RouteAsync的典型实现如下所示

    public async Task RouteAsync(RouteContext context)
    {
        // Request path is the entire path (without the query string)
        // starting with a forward slash.
        // Example: /Home/About
        var requestPath = context.HttpContext.Request.Path.Value;
    
        if (!requestPath == <some comparison (slice the string up if you need to)>)
        {
            // Condition didn't match, returning here will
            // tell the framework this route doesn't match and
            // it will automatically call the next route.
    
            // This is similar to returning "false" from a route constraint.
            return;
        }
    
        // Invoke MVC controller/action.
        // We use a copy of the route data so we can revert back
        // to the original.
        var oldRouteData = context.RouteData;
        var newRouteData = new RouteData(oldRouteData);
        newRouteData.Routers.Add(_target);
    
        // TODO: Set this in the constructor or based on a data structure.
        newRouteData.Values["controller"] = "Custom"; 
        newRouteData.Values["action"] = "Details";
    
        // Set any other route values here (such as "id")
    
        try
        {
            context.RouteData = newRouteData;
    
            // Here we are calling the nested route asynchronously.
            // The nested route should generally be an instance of
            // MvcRouteHandler.
    
            // Calling it is similar to returning "true" from a
            // route constraint.            
            await _target.RouteAsync(context);
        }
        finally
        {
            // Restore the original values to prevent polluting the route data.
            if (!context.IsHandled)
            {
                context.RouteData = oldRouteData;
            }
        }
    }
    
    公共异步任务RouteAsync(RouteContext上下文)
    {
    //请求路径是整个路径(不带查询字符串)
    //从正斜杠开始。
    //示例:/Home/About
    var requestPath=context.HttpContext.Request.Path.Value;
    如果(!requestPath==)
    {
    //条件不匹配,返回此处将
    //告诉框架此路由不匹配,然后
    //它将自动调用下一条路线。
    //这类似于从管线约束返回“false”。
    返回;
    }
    //调用MVC控制器/操作。
    //我们使用路由数据的副本,以便可以恢复
    //与原文一致。
    var oldRouteData=context.RouteData;
    var newRouteData=新路由数据(旧路由数据);
    newRoutedData.Routers.Add(_目标);
    //TODO:在构造函数中或基于数据结构设置此选项。
    newRoutedData.Values[“controller”]=“Custom”;
    newRoutedData.Values[“action”]=“Details”;
    //在此处设置任何其他管线值(如“id”)
    尝试
    {
    context.RouteData=newRouteData;
    //这里我们异步调用嵌套路由。
    //嵌套路由通常应该是
    //MvcRouteHandler。
    //调用它类似于从
    //路由约束。
    wait_target.RouteAsync(上下文);
    }
    最后
    {
    //恢复原始值以防止污染管线数据。
    如果(!context.IsHandled)
    {
    context.RouteData=oldRouteData;
    }
    }
    }
    

    请参阅答案和其他一些示例。

    我建议您为此使用AsyncActionFilter

    假设您的路由模板:
    {controller}/{action}/{myName}

    实现AsyncActionFilter:

    using Microsoft.AspNet.Mvc;
    using Microsoft.AspNet.Mvc.Filters;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.Framework.Internal;
    
    namespace ActionFilterWebApp.Filters
    {
        public class ThirdPartyServiceActionFilter : ActionFilterAttribute
        {
            public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
            {
                var routeKey = "myName";
                var routeDataValues = context.RouteData.Values;
                var allowActionInvoke = false;
    
                if (routeDataValues.ContainsKey(routeKey))
                {
                    var routeValue = routeDataValues[routeKey];
                    //allowActionInvoke = ThirdPartyService.Check(routeValue);
                }
    
                if (!allowActionInvoke)
                {
                    //if you setting up Result property - action doesn't invoke
                    context.Result = new BadRequestResult();
                }
    
                return base.OnActionExecutionAsync(context, next);
            }
        }
    }
    
    在控制器上添加
    ThirdPartyServiceActionFilter

       [ThirdPartyServiceActionFilter]
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
        }