.NET5 / MVC6中的异步路由约束(或者其他可能的东西)

时间:2015-10-13 06:14:44

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

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

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

用户将使用额外参数调用控制器,我们将调用myName。如果这个值出现在数据库中,我想在控制器方法中记录。

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

http://localhost/api/data/myName

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

不确定我是否需要使用其他东西然后使用路线约束?

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

2 个答案:

答案 0 :(得分: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)。
  4. GetVirtualPath执行以下操作:

    1. 比较一组路线值,看它们是否与路线匹配。
    2. 如果匹配,则将路由值转换为虚拟路径(URL)。这应该与RouteAsync中的逻辑完全相反,因此我们生成匹配的相同URL。
    3. 框架将虚拟路径返回到UrlHelper的任何调用,例如ActionLinkRouteLink的调用。
    4. 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

答案 1 :(得分:0)

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