ASP.Net Mvc 3 Url.Action method uses parameter values from previous request
Asked Answered
B

4

12

When Urls are autogenerated using the Url.Action helper, if a page contains a line similar to

@Url.Action("Edit","Student")

is expected to generate a url like domain/student/edit and its working as expected. But if the requested url contains some parameters, like domain/student/edit/210, the above code uses these parameters from the previous request and generates something similar even though I've not provided any such parameter to the Action method.

In short, if the requested url contains any parameters, any auto generated links of the page (served for that request) will include those parameters as well no matter if I specify them or not in the Url.Action method.

What's going wrong?

Bul answered 14/7, 2011 at 8:1 Comment(0)
Q
9

Weird, can't seem to reproduce the problem:

public class HomeController : Controller
{
    public ActionResult Index(string id)
    {
        return View();
    }

    public ActionResult About(string id)
    {
        return View();
    }
}

and inside Index.cshtml:

@Url.Action("About", "Home")

Now when I request /home/index/123 the url helper generates /home/about as expected. No ghost parameters. So how does your scenario differs?


UPDATE:

Now that you have clarified your scenario it seems that you have the following:

public class HomeController : Controller
{
    public ActionResult Index(string id)
    {
        return View();
    }
}

and inside Index.cshtml you are trying to use:

@Url.Action("Index", "Home")

If you request /home/index/123 this generates /home/index/123 instead of the expected /home/index (or simply / taken into account default values).

This behavior is by design. If you want to change it you will have to write your own helper which ignores the current route data. Here's how it might look:

@UrlHelper.GenerateUrl(
    "Default", 
    "index", 
    "home", 
    null, 
    Url.RouteCollection, 
    // That's the important part and it is where we kill the current RouteData
    new RequestContext(Html.ViewContext.HttpContext, new RouteData()), 
    false
)

This will generate the proper url you were expecting. Of course this is ugly. I would recommend you encapsulating it into a reusable helper.

Quigley answered 14/7, 2011 at 8:21 Comment(6)
Not that way, try to generate the link for the same page without parameters, but request the page with parameters. So in your case, try to generate link for index page itself.Bul
@Threecoins, ahhh OK, got it. That's by design.Quigley
oh, so I cant generate a link without parameters within the same page if the request has got parameters??Bul
@Threecoins, you can but you will have to write your own helper. See my update for an alternative.Quigley
Thank you. better than nothing, will make it an extension to the HtmlHelper, But why is it like this by design? Any particular advantage or historical reasons for that?Bul
this is the extension i made to the UrlHelper public static string GenerateUrl(this UrlHelper urlHelper, string actionName, string controllerName) { var urlHelperWithNewContext = new UrlHelper(new RequestContext(urlHelper.RequestContext.HttpContext, new RouteData()), urlHelper.RouteCollection); return urlHelperWithNewContext.Action(actionName, controllerName); }Launder
S
20

Use Darin's answer from this similar question.

@Url.Action("Edit","Student", new { ID = "" })
Suffrage answered 25/10, 2012 at 19:24 Comment(0)
Q
9

Weird, can't seem to reproduce the problem:

public class HomeController : Controller
{
    public ActionResult Index(string id)
    {
        return View();
    }

    public ActionResult About(string id)
    {
        return View();
    }
}

and inside Index.cshtml:

@Url.Action("About", "Home")

Now when I request /home/index/123 the url helper generates /home/about as expected. No ghost parameters. So how does your scenario differs?


UPDATE:

Now that you have clarified your scenario it seems that you have the following:

public class HomeController : Controller
{
    public ActionResult Index(string id)
    {
        return View();
    }
}

and inside Index.cshtml you are trying to use:

@Url.Action("Index", "Home")

If you request /home/index/123 this generates /home/index/123 instead of the expected /home/index (or simply / taken into account default values).

This behavior is by design. If you want to change it you will have to write your own helper which ignores the current route data. Here's how it might look:

@UrlHelper.GenerateUrl(
    "Default", 
    "index", 
    "home", 
    null, 
    Url.RouteCollection, 
    // That's the important part and it is where we kill the current RouteData
    new RequestContext(Html.ViewContext.HttpContext, new RouteData()), 
    false
)

This will generate the proper url you were expecting. Of course this is ugly. I would recommend you encapsulating it into a reusable helper.

Quigley answered 14/7, 2011 at 8:21 Comment(6)
Not that way, try to generate the link for the same page without parameters, but request the page with parameters. So in your case, try to generate link for index page itself.Bul
@Threecoins, ahhh OK, got it. That's by design.Quigley
oh, so I cant generate a link without parameters within the same page if the request has got parameters??Bul
@Threecoins, you can but you will have to write your own helper. See my update for an alternative.Quigley
Thank you. better than nothing, will make it an extension to the HtmlHelper, But why is it like this by design? Any particular advantage or historical reasons for that?Bul
this is the extension i made to the UrlHelper public static string GenerateUrl(this UrlHelper urlHelper, string actionName, string controllerName) { var urlHelperWithNewContext = new UrlHelper(new RequestContext(urlHelper.RequestContext.HttpContext, new RouteData()), urlHelper.RouteCollection); return urlHelperWithNewContext.Action(actionName, controllerName); }Launder
G
0

Use ActionLink overload that uses parameters and supply null

Gaylor answered 14/7, 2011 at 8:51 Comment(3)
seems like I can't assign null to anonymous property types.Bul
@Mathew Cast null to dynamic to assign it to anonymous property types. But like Darin says, yes, it doesn't work.Baksheesh
@Ken I ended up assigning "/". It is a hack, but works for simple urls.Bul
K
0

You could register custom route for this action for example:

routes.MapRoute("Domain_EditStudentDefault",
            "student/edit",
            new { 
                controller = MVC.Student.Name, 
                action = MVC.Student.ActionNames.Edit,
                ID = UrlParameter.Optional
            },
            new object(),
            new[] { "MySolution.Web.Controllers" }
        );

you then could use url.RouteUrl("Domain_EditStudentDefault") url RouteUrl helper override with only routeName parameter which generates url without parameters.

Karlsruhe answered 28/9, 2015 at 8:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.