ASP.NET 如果控制器返回 NotFound,请尝试其他路由匹配或其他控制器

问题描述 投票:0回答:1

我有 2 个路由映射可以处理相同的路由,但是一个是来自 CMS 的动态路由,另一个使用不同的控制器,例如

app.MapControllerRoute(
    name: "Dynamic",
    pattern: "/{urlPath:regex(urlA|urlB)}/{slug}",
    defaults: new { controller = "Controller1", action = "Index" });

 app.MapControllerRoute(
    name: "NonDynamic",
    pattern: "/{slug}/{*path}",
    defaults: new { controller = "Controller2", action = "Index" });

如果

NonDynamic
-> Controller1 返回 404,我该如何尝试 Controller2 或
Dynamic
。 问题是我不知道Controller1是否可以处理它,直到我尝试处理它并检查CMS是否有该页面,但如果没有,我想用完全不同的controller2来处理它
RedirectTo
不是一个选项 - 我不想有 301 或 302 重定向。 似乎也不可能在另一个控制器中使用来自不同控制器的操作并保持上下文。

我可以将所有逻辑从 Controller2 复制到 Controller1,然后根据 cms 响应使用不同的操作,但这很混乱,我不想混合这 2 个控制器。

有没有办法从控制器返回并告诉应用程序继续寻找另一条路线匹配?

asp.net asp.net-mvc asp.net-core routes
1个回答
0
投票

这是一个中间件,您可以通过设置魔法

HttpContext.Item
在管道中通知它。当它检测到这一点时,它会找到您想要执行的端点并将其发送回中间件管道。这会以各种方式破坏,但它似乎适用于您问题中的具体情况。

public async Task InvokeAsync(HttpContext httpContext, EndpointDataSource endpointDataSource)
{
    //on the way up, just proceed
    await next(httpContext);

    //on the way down, see if we got handed a route name to execute
    if (httpContext.Items["ReexecuteRouteName"] is string routeName)
    {
        httpContext.Items.Remove("ReexecuteRouteName");

        //find the endpoint by the given route name
        var endpoint = endpointDataSource.Endpoints.FirstOrDefault(e =>
            e.Metadata.GetMetadata<RouteNameMetadata>()?.RouteName == routeName);

        if (endpoint is null)
            return;

        //clear previously parsed route values
        var routeValues = httpContext.GetRouteData().Values;
        routeValues.Clear();

        //populate with new ones according to the new endpoint
        var route = endpoint.Metadata.GetMetadata<IRouteDiagnosticsMetadata>();
        var routeTemplate = TemplateParser.Parse(route?.Route);
        var templateMatcher = new TemplateMatcher(routeTemplate, new());
        templateMatcher.TryMatch(httpContext.Request.Path, routeValues);

        //set the endpoint
        httpContext.SetEndpoint(endpoint);

        //go back up the middleware pipeline
        await next(httpContext);
    }
}

在控制器1中:

public IActionResult Index(string urlPath, string slug)
{
    var myPage = await db.QueryFirstOrDefaulf<PageStuff>(sql, new { slug });

    if (myPage is null) 
    {
        HttpContext.Items.Add("ReexecuteRouteName", "NonDynamic");
        //make sure not to start the response here
        return new NotFoundResult();
    }

    return View();
}
© www.soinside.com 2019 - 2024. All rights reserved.