【问题标题】:Async Route Constraint (or maybe something else) in .NET5/MVC6.NET5/MVC6 中的异步路由约束(或其他东西)
【发布时间】:2015-10-13 06:14:44
【问题描述】:

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

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

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

调用控制器的路径如下所示,其中 data 是我的控制器的名称,myName 是一个字符串,我需要检查它是否存在于数据库中。

http://localhost/api/data/myName

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

不确定我是否需要使用其他东西而不是路由约束?

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

【问题讨论】:

    标签: c# asp.net .net asp.net-mvc asp.net-core-mvc


    【解决方案1】:

    您可以实现自己的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 执行以下操作:

    1. 分析请求以确定它是否与路由匹配。
    2. 如果有匹配项,请设置路由值。
    3. 如果我们有匹配项,请将调用传递给下一个IRouter(通常是MvcRouteHandler)。

    GetVirtualPath 执行以下操作:

    1. 比较一组路由值以查看它们是否与路由匹配。
    2. 如果匹配,则将路由值转换为虚拟路径 (URL)。这通常应该与RouteAsync 中的逻辑完全相反,因此我们会生成匹配的相同 URL。
    3. 框架返回对UrlHelper 的任何调用的虚拟路径,例如ActionLinkRouteLink 进行的调用。

    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;
            }
        }
    }
    

    有关其他示例,请参阅答案 herehere

    【讨论】:

      【解决方案2】:

      我建议您为此使用 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();
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-10
        • 1970-01-01
        • 2017-08-09
        • 1970-01-01
        • 2016-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多