如果路线不存在 - >使用默认操作转到其他路线?

时间:2016-03-22 03:21:32

标签: c# asp.net routes

所以我在路由方面遇到了一些问题。

此Web应用程序有两个部分:
1.宣传册/展示网站
2.内部站点/客户端应用程序

我们想要一种方法来发布小册子的更改,而无需完整发布所述 Web 应用程序。 访问现有的命名视图会将用户带到一个小册子页面,但如果它不存在,它将像客户端一样,并将它们重定向到他们公司的登录屏幕。

的Global.asax:

//if view doesnt exist then url is a client and should be redirected
routes.MapRoute(
    name: "Brochure",
    url: "{id}",
    defaults: new { controller = "brochure", action = "Brochure", id = "Index" },
    namespaces: new[] { "Web.Areas.Brochure.Controllers" }
);

//This is home page
routes.MapRoute(
    name: "HomeDefault",
    url: "{client}/{action}",
    defaults: new { controller = "home", action = "index" },
    namespaces: new string[] { "Web.Controllers" }
);

控制器:

/// <summary> Check if the view exists in our brochure list </summary>
private bool ViewExists(string name) {
    ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, name, null);
    return (result.View != null);
}

/// <summary> Generic action result routing for all pages. 
/// If the view doesn't exist in the brochure area, then redirect to interal web
/// This way, even when we add new pages to the brochure, there is no need to re-compile & release the whole Web project. </summary>
public ActionResult Brochure(string id) {
    if (ViewExists(id)) {
        return View(id);
    }

    return RedirectToRoute("HomeDefault", new { client = id });
}

此代码可以正常运行,直到我们登录并转到目标网页。它似乎在路线中保留手册动作,并且不想转到后续控制器,导致500错误。 例如当需要时,'domain / client / Brochure':'domain / client / Index'

事情已尝试但未奏效

  • RedirectToRoute()更改为RedirectToAction() - 这会导致a 返回ActionResult Brochure()的有限循环。所以 通过改变控制器不起作用。
  • 在'HomeController'中创建一个名为Brochure()的ActionResult。它 甚至没有受到打击。
  • 作为namespaces传递RedirectToRoute()作为属性。我知道这可能不会起作用,但值得一试。

所以问题是:
我怎样才能让路线正常行动?

3 个答案:

答案 0 :(得分:1)

如果您可以将id限制为所有值的某个子集,则可以将constraints添加到路由(即仅限数字),以便默认处理其余值。

routes.MapRoute(
    name: "Brochure",
    url: "{id}",
    defaults: new { controller = "brochure", action = "Brochure", id = "Index" },
    namespaces: new[] { "Web.Areas.Brochure.Controllers" }
    constraints : new { category = @"\d+"}
);

如果您无法静态地确定限制 - 在BrochureController中自动重定向与您当前的代码类似,则可以正常工作。问题中样本的唯一问题是它再次点击相同的路径并进入无限重定向循环 - 重定向到与第一个规则不匹配的Url:

// may need to remove defaults from second route 
return RedirectToRoute("HomeDefault", new { client = id, action = "index" });

如果标准约束不起作用且您必须在网址中保留单个细分 - 使用自定义约束 - 实现IRouteConstraint并在第一个路径中使用它。请参阅Creating custom constraints

答案 1 :(得分:0)

我可以用两种方法解决这个问题:

方式1

我查看了重定向,然后传入了一个动作,以获得一个在网址中有2个段的路由。即客户/索引索引操作现在处理登录 - 经过自定义控制器 public class HomeController : CustomController

public ActionResult Brochure(string id, string action) {
    if (ViewExists(id)) {
        return View(id);
    }

    return RedirectToAction("Index", "Home", new { client = id, action = "Index" });
}

方式2

(来自@Alexei_Levenkov)
创建自定义路径约束,以便在无法找到视图时忽略路径。

namespace Web.Contraints {
    public class BrochureConstraint : IRouteConstraint {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
            //Create our 'fake' controllerContext as we cannot access ControllerContext here
            HttpContextWrapper context = new HttpContextWrapper(HttpContext.Current);
            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "brochure");
            ControllerContext controllerContext = new ControllerContext(new RequestContext(context, routeData), new BrochureController());

            //Check if our view exists in the folder -> if so the route is valid - return true
            ViewEngineResult result = ViewEngines.Engines.FindView(controllerContext, "~/Areas/Brochure/Views/Brochure/" + values["id"] + ".cshtml", null);
            return result.View != null;
        }
    }
}

namespace Web {
    public class MvcApplication : System.Web.HttpApplication {
        //If view doesnt exist then url is a client so use the 'HomeDefault' route below
        routes.MapRoute(
            name: "Brochure",
            url: "{id}",
            defaults: new { controller = "brochure", action = "Brochure", id = "Index" },
            namespaces: new[] { "Web.Areas.Brochure.Controllers" },
            constraints: new { isBrochure = new BrochureConstraint() }
        );

        //This is home page for client
        routes.MapRoute(
            name: "HomeDefault",
            url: "{client}/{action}",
            defaults: new { controller = "home", action = "index" },
            namespaces: new string[] { "Web.Controllers" }
        );
    }
}

我希望这可以帮助其他人。

答案 2 :(得分:0)

您的配置存在一些问题。我可以解释它有什么问题,但我不确定我是否可以让你走上正轨,因为你没有提供所有的URL(至少不是所有的URL都可以告诉你)。

问题

  1. 您的func doStuff(x: Hashable) { } 路由(其中包含1个可选网址段名为Brouchure)将匹配任意的网址,该网址为0或1个网段(例如作为{id}/)。它匹配您的主页(并且您有另一条名为/client的路由永远不会有机会匹配主页)这一事实让我相信这不是故意的。您可以删除默认值HomeDefault
  2. ,以获得所需的{id}
  3. id = "Index"路由有一个名称空间,表明它可能位于Brouchure。要正确注册该区域,您必须在该路由的最后一行Area或者将其放入).DataTokens["area"] = "Brochure";文件中,这将为您完成。
  4. 进入/Areas/Brouchure/AreaRegistration.cs路线的唯一方法是提供2段网址(例如HomeDefault,这会将您转到/client/Index上的Index方法})。您提供的示例网址包含3个细分。您提供的路线都不会与包含3个细分的网址相匹配,因此如果这些网址没有收到404错误,那么它们显然与您未在问题中提供的路线相匹配。换句话说,您正在错误的地方寻找问题。
  5. 如果您提供整个路由配置,包括所有Area路由和AttributeRouting路由(包括注册它们的行),以及完整描述应该是什么URL转到什么行动方法,我相信你会得到更多有用的答案。

      

    所以问题是:   我怎样才能让路线正常行动?

    未知。在您描述正确之前。

    相关:Why map special routes first before common routes in asp.net mvc?