ASP.NET MVC + WebForms - 路由冲突

6
我正在使用ASP.NET MVC3 + WebForms构建一个简单的报告Web应用程序来呈现报告。报告本身由ReportViewer ASP.NET WebForms控件呈现,但我想使用ASP.NET MVC创建参数输入。
我希望所有请求都遵循“~/{controller}/{action}/{parameters}”的默认路由方案,除了对“~/Report”的请求,它应该转到报告呈现WebForm。如何正确实现?
稍微扩展一下...
在Global.asax.cs中有两个路由 - 默认路由和一个用于WebForms页面的路由。
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

    routes.MapPageRoute("report-rendering", "Report", "~/Render.aspx");
}

URL地址的呈现很好,但问题在于当请求到来时,第一个路由也会捕获第二个路由的URL,即~/Report?id=7 尝试调用ReportController中的Index方法(该方法不存在)。如果我将“report-rendering”路由放在“Default”路由之前,就像这样:
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapPageRoute("report-rendering", "Report", "~/Render.aspx");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );
}

现在对Html.ActionLink()的调用会呈现错误的URL,即:
`@Html.ActionLink("Report list", "Index", "ReportList")`

呈现。
`http://localhost:49910/Report?action=Index&controller=ReportList`

我的当前解决方法是将“默认”路由放在最前面,同时添加一个正则表达式约束来忽略对“报告”控制器的请求,如下所示:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    new { controller = @"(?!report$).*" }
);

这感觉不太干净。再次问一下,什么是正确的方法?

此外,我还没有决定如何将参数传递给渲染表单:我可以使用查询参数或将其POST。我猜查询参数更灵活。这里有什么最佳实践?

编辑:

在查找@LeftyX的答案时,似乎我已经找到了一个答案。引用P. Haack在Professional ASP.NET MVC 3(命名路由,第9章,第233页)中的Routing章节:

... 为所有路由使用名称,并始终在生成URL时使用路由名称。大多数情况下,让Routing确定您要使用哪个路由来生成URL实际上是交给机会,这不是一个好的开发者所喜欢的事情。当生成URL时,您通常确切地知道要链接到哪个路由,因此最好通过名称指定它。

上述部分讨论了与我描述的非常相似的情况。

但是由于Html.ActionLink()没有带路由名称参数的重载,这是否意味着如果我有一个像这样的路由,就无法在整个应用程序中可靠地使用它?

1个回答

1

这是我想出的最佳解决方案。
我已经使用MapPageRoute注册了我的路由(我将我的报告页面放在一个名为“报告”的文件夹下

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapPageRoute(
          "report-rendering",
          "Report/{id}",
          "~/Reports/Report.aspx"
         );

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
            );
}

我使用RouteLink创建了我的链接,这样你就可以指定要使用的路由:

@Html.RouteLink("Report list", "report-rendering", new { id = 7 })

我可以在我的WebForm页面中像这样获取id

protected void Page_Load(object sender, EventArgs e)
{
    var id = Page.RouteData.Values["id"] as string;
}

希望能有所帮助。 更新: 我创建了一个扩展方法,让你的生活更轻松:
public static class ExtensionMethods
{
    public static MvcHtmlString WebFormActionLink(this HtmlHelper htmlHelper, string linkText, string ruoteName, object routeValues)
    {
        var helper = new UrlHelper(htmlHelper.ViewContext.RequestContext);

        var anchor = new TagBuilder("a");
        anchor.Attributes["href"] = helper.RouteUrl(routeName, routeValues);
        anchor.SetInnerText(linkText);
        return MvcHtmlString.Create(anchor.ToString());
    }
}

最好使用ActionLink而不是WebFormActionLink,但我在签名方面遇到了问题,我不是这方面的专家。

谢谢你的回答。我明白你的意思了。因为你添加了{id}参数,所以没有提供{id}值的.RouteLink()调用不再匹配该路由。然而,在指定id参数的情况下生成路由将匹配此路由。这个:@Html.ActionLink("Page 1", "Page", "Home", new { id = 1 }, null)将生成这个:http://localhost:49910/Report/1?action=Page&controller=Home这不是你期望的结果,对吧? - Ronald Zarīts
@ghostskunks:我知道。恐怕你得使用RouteLink来为WebForms生成链接,或者你可以尝试扩展ActionLink。 - LeftyX
@ghostskunks:我尝试着组织了一些东西(更新的答案),但是,正如我所说,我不是专家。这只是一个想法。 - LeftyX
1
你的方法可能有效。由于链接渲染期望提供所有路由参数值,如果您指定一个唯一的参数名称,比如reportId而不是id,并且不指定默认值,则链接渲染将不会选择此路由。也就是说,对于路由routes.MapPageRoute("report-rendering","Report/{reportId}", "~/Render.aspx");,这个:@Html.ActionLink("Page 2", "Page", "Home", new { id = 2 }, null)生成的是:http://localhost:49910/Home/Page/2,但是这个:`@Html.RouteLink("Run report", "report-rendering", new { reportId = 1 })`将生成:http://localhost:49910/Report/1。 - Ronald Zarīts
感谢您的更新和扩展方法,但在为报告呈现生成链接的站点上并没有问题 - 在那里可以始终使用Html.RouteLink()并提供名称。问题是在其他页面必须始终使用RouteLink(),否则ActionLink()可能会生成不正确的链接。 - Ronald Zarīts
@ghostskunks:是的,我知道,但由于您没有调用控制器/操作,我认为您应该使用ActionLink。 - LeftyX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接