开发者

Switching to {controller}/{id}/{action} breaks RedirectToAction

I am trying to use proper REST urls with MVC. To do that I switched default Routing from:

{controller}/{action}/{id}

to

{controller}/{id}/{action}

so instead of:

/Customer/Approve/23

there is now

/Customer/23/Approve

ActionLink seems to work ok, but the following code in CustomerController:

[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
    _customerService.Approve(id);
    return RedirectToAction("Search");  //Goes to bad url
}

ends up on url /Customer/23/Search. While it should be going to /Customer/Search. Somehow it remembers 23 (id).

Here is my rout开发者_开发问答ing code in global.cs

    routes.MapRoute(
        "AdminRoute", // Route name
        "{controller}/{id}/{action}", 
        new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        new { id = new IsIntegerConstraint() }
        );

    routes.MapRoute(
        "Default", 
        "{controller}/{action}", 
        new { controller = "Home", action = "Index" });

If I switch the two functions, RedirectToAction starts working, but using:

Html.ActionLink("Approve", "Approve", new { Id = 23})

Now generates /Customer/Approve?id=23, instead of /Customer/23/Approve.

I could specify direct urls like ~/Customer/23/Approve, instead of using ActionLink and RedirectToAction, but would rather stick to functions provided by MVC.


When you use RedirectToAction(), internally, MVC will take the existing route data (including the Id value) to build the url. Even if you pass a null RouteValueDictionary, the existing route data will be merged with the new empty route value data.

The only way around this I can see is to use RedirectToRoute(), as follows:

return RedirectToRoute("Default", new { controller = "Customer", action = "Search"});

counsellorben


Try passing in new (empty) RouteValueDictionary in your controller

return RedirectToAction("Search", new System.Web.Routing.RouteValueDictionary{});

And here:

Html.ActionLink("Approve", "Approve", new { Id = 23})

I don't even know how can it pick up the Customer controller, since you are not specifying it anywhere. Try providing both controller and action to ActionLink helper.


Try passing the current route data to methon in your controller action:

return RedirectToAction("Search", this.RouteData.Values);


Remove this part:

id = UrlParameter.Optional

may be resolve the problem; when you define "id" as an optional parameter, and you have the "Default" map, the "Default" and the "AdminRoute" are same together! regards.


I was having a similar problem. Route values that were passed to my controller action were being reused when I tried to redirect the user with RedirectToAction, even if I didn't specify them in the new RouteValueDictionary. The solution that I came up with (after reading counsellorben's post) with was to clear out the RouteData for the current request. That way, I could stop MVC from merging route values that I didn't specify.

So, in your situation maybe you could do something like this:

[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
    _customerService.Approve(id);
    this.RouteData.Values.Clear();  //clear out current route values
    return RedirectToAction("Search");  //Goes to bad url
}


I had a similar problem and was able to solve it by adding the id to the default route as well.

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

If there is truly no id in your default route then you could also try:

routes.MapRoute(
    "Default", 
    "{controller}/{action}", 
    new { controller = "Home", action = "Index", id = string.Empty });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜