ASP.NET MVC + WebForms - 路由冲突

时间:2022-12-21 03:23:04

I'm building a simple report Web app for rendering reports using ASP.NET MVC3 + WebForms. The reports themselves are rendered by the ReportViewer ASP.NET WebForms control, but I'd like use ASP.NET MVC to create the parameter entry.

我正在构建一个简单的报表Web应用程序,用于使用ASP.NET MVC3 + WebForms呈现报表。报表本身由ReportViewer ASP.NET WebForms控件呈现,但我想使用ASP.NET MVC创建参数条目。

I'd like to have that all requests follow the default routing scheme of '~/{controller}/{action}/{parameters}', except requests for ~/Report, which should go to the report rendering WebForm. What's the right way to do this?

我希望所有请求都遵循'〜/ {controller} / {action} / {parameters}'的默认路由方案,除了〜/ Report的请求,它应该转到报告呈现WebForm。这样做的正确方法是什么?

Expanding a bit..

扩大一点..

I have two routes in Global.asax.cs - the default one and one for the WebForms page.

我在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");
}

The URLs get rendered fine, but the problem with this is that when the request comes in, the first route also eats the URLs for the second one, i.e. ~/Report?id=7 tries to call the Index method on the ReportController (which doesn't exist).

URL被渲染得很好,但问题在于,当请求进入时,第一条路径也会占用第二条路由的URL,即〜/ Report?id = 7尝试在ReportController上调用Index方法(不存在)。

If I change it so that the 'report-rendering' route comes before the 'Default' route, like so:

如果我更改它,以便'报告呈现'路线在'默认'路线之前,如下所示:

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

Now calls to the Html.ActionLink() render incorrect URLs, i.e.

现在调用Html.ActionLink()呈现不正确的URL,即

`@Html.ActionLink("Report list", "Index", "ReportList")`

Renders

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

My current workaround puts the 'Default' route first, while adding a regex constraint to ignore requests for the 'Report' controller, like so:

我当前的解决方法首先放置“默认”路由,同时添加正则表达式约束以忽略对“报表”控制器的请求,如下所示:

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

This doesn't feel clean. Again, What's the right way of doing this?

这感觉不干净。再说一次,这样做的正确方法是什么?

Also, I haven't yet decided how I'll pass the parameters to the rendering form: I could use both query parameters or POST them. I'm guessing that query params are more flexible. What's the best practice here?

另外,我还没有决定如何将参数传递给渲染表单:我可以使用查询参数或POST它们。我猜测查询参数更灵活。这里的最佳做法是什么?

EDIT:

While researching the answer by @LeftyX, seems like I've found an answer. To quote P. Haack from his Routing chapter in the Professional ASP.NET MVC 3 (Named Routes, Chapter 9, page 233):

在研究@LeftyX的答案时,似乎我找到了答案。从职业ASP.NET MVC 3(命名路由,第9章,第233页)中的路由章节引用P. Haack:

... Use names for all your routes and always use the route name when generating URLs. Most of the time, letting Routing sort out which route you want to use to generate a URL is really leaving it to chance, which is not something that sits well with the obsessive-compulsive control freak developer. When generating a URL, you generally know exactly which route you want to link to, so you might as well specify it by name.

...使用所有路由的名称,并在生成URL时始终使用路由名称。大多数时候,让路由选择你要用来生成URL的路由实际上是让它失去了机会,这对于强迫性控制狂的开发者而言并不适合。生成URL时,通常可以确切地知道要链接到哪条路径,因此您也可以按名称指定它。

The mentioned section discusses a very similar situation to the one I described.

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

But since Html.ActionLink() doesn't have an overload with the route name parameter, does this mean I cannot reliably use it anywhere in the entire app if have a route like this?

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

1 个解决方案

#1


1  

This is the best solution I've figured out.
I've registered my route with MapPageRoute (I've put my Report page under a folder called Reports)

这是我发现的最佳解决方案。我已经使用MapPageRoute注册了我的路线(我将报告页面放在名为Reports的文件夹下)

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

I've created my link using RouteLink so you can specify the route to use:

我使用RouteLink创建了我的链接,因此您可以指定要使用的路径:

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

and I can get the id in my WebForm page like this:

我可以在我的WebForm页面中获取id,如下所示:

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

Hope it helps.

希望能帮助到你。

UPDATE:

I've created an Extension Method to make your life easier:

我创建了一种扩展方法,让您的生活更轻松:

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

The best would have been to use ActionLink instead of WebFormActionLink but I have problems with signatures and I am not an expert on this.

最好的方法是使用ActionLink而不是WebFormActionLink,但我有签名问题而且我不是这方面的专家。

#1


1  

This is the best solution I've figured out.
I've registered my route with MapPageRoute (I've put my Report page under a folder called Reports)

这是我发现的最佳解决方案。我已经使用MapPageRoute注册了我的路线(我将报告页面放在名为Reports的文件夹下)

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

I've created my link using RouteLink so you can specify the route to use:

我使用RouteLink创建了我的链接,因此您可以指定要使用的路径:

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

and I can get the id in my WebForm page like this:

我可以在我的WebForm页面中获取id,如下所示:

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

Hope it helps.

希望能帮助到你。

UPDATE:

I've created an Extension Method to make your life easier:

我创建了一种扩展方法,让您的生活更轻松:

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

The best would have been to use ActionLink instead of WebFormActionLink but I have problems with signatures and I am not an expert on this.

最好的方法是使用ActionLink而不是WebFormActionLink,但我有签名问题而且我不是这方面的专家。