14

I'm currently developing an ASP.NET MVC3 application in VS2010 and I'm having some troubles with @Url.Action helper. I have an ajax request where I use this helper:

var url = '@Url.Action("Action", "Controler", new { a = "a", b = "b" })';
$.post(url).success(function(data) { 
    ... 
});

The problem is that the value of url after this is /Controller/Action?a=a&b=b, note the & between the route values. This isn't working, but if I do:

var url = '@Url.Action("Action", "Controler", new { a = "a", b = "b" })'.replace('amp;', '');

it works perfectly!!!

My action is something like this:

public JsonResult Action(string a, string b) 
{
    ...
}

I have debugged my app and the action gets called and even a is "a", but b is null.

Is this the desired behavior of Url.Action? I don't think so. Please help me, what am I doing wrong? Should I add another parameter to my Url.Action call? Thanks in advance.

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
educampver
  • 2,967
  • 2
  • 23
  • 34
  • I don't think this is an issue with Url.Action but rather jQuery HTML encoding your url. – Tommy Mar 15 '13 at 04:21

6 Answers6

8

The issue here is that when you're using razor syntax: @... the razor engine is encoding the result of Url.Action (which is a string) as an MvcHtmlString. This results in ampersands being encoded as &. To get around this, use Html.Raw (Returns markup that is not HTML encoded.)

var url = '@Html.Raw(Url.Action("Action", "Controller", new { a = "a", b = "b" }))';

Resulting in: '/Controller/Action?a=a&b=b'

Thanks to @GSerg (See comment in Dave Alperovich's answer)... but the desired result isn't javascript encoding. Using HttpUtility.JavaScriptStringEncode("&") results in '\u0026'

ngless
  • 150
  • 2
  • 11
3

It's not you. Javascript identifies the & as a protected character and "encodes it"

You found one way to get around it, I've seen others. As this question is NOT asking the best way, but whether or not it's you, I can assure you that it's NOT YOU. You did nothing clearly wrong. This is the natural behavior of Javascript.

If we are discussing best approached, I prefer to use @Url.Action only to get my URL, and to pass params as params to my JQuery method (the .Ajax method is my favorite).

example borrowed from e.camper

$.post(url, { a: "a", b: "b"}).success(...)
Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
  • so you would do something like this: `var url = '@Url.Action("Action", "Controler")';` and then `$.post(url, { a: "a", b: "b"}).success(...)`?? – educampver Mar 15 '13 at 04:25
  • @e.campver, yes, thats a great example – Dave Alperovich Mar 15 '13 at 04:26
  • 2
    I hate to disprove the *it's NOT YOU* bit, but it is actually you @ecampver - you are generating values for JS strings, this should be done properly: `var url = '@HttpUtility.JavaScriptStringEncode(Url.Action("Action", "Controler", new { a = "a", b = "b" }))';`. Also it's wrong that *Javascript identifies the &* - it is the Razor engine that outputs result of `Url.Action`, which is a string as opposed to `MvcHtmlString`, so it is encoded at the point of generating the HTML response. To prevent this one uses `Html.Raw`, but because we're generating a JS string, we use `JavaScriptStringEncode`. – GSerg Dec 02 '14 at 22:39
  • 1
    @GSerg: Thank's for taking the trouble of commenting this old post, it's always good to learn better ways, greetings :) – educampver Dec 03 '14 at 22:01
3

every thing said in the above answer is great, i want to add something to the way you are sending the ajax request, when you want to send additional data, send it like

var url = '@Url.Action("Action", "Controler")';
$.post(url,{a:'a',b:'b'}).success(function(data) { 
    ... 
});
Dakait
  • 2,531
  • 1
  • 25
  • 43
2

Like I mentioned in my comment, this is a JavaScript encoding issue. The best way to prevent having to do any UrlDecoding or character replacement is to define a route that matches the parameters that you are trying to pass

routes.MapRoute(
            "MyCustomRoute",
            "{Controller}/{Action}/{a}/{b}",
            new {controller = "Controller", action = "Action"}

Place this in your global.asax file above your default route. Now, when you call

var url = '@Url.Action("Action", "Controler", new { a = "a", b = "b" })';

The output will be /Controller/Action/a/b

Tommy
  • 39,592
  • 10
  • 90
  • 121
  • this is an ajax post, does ASP.NET MVC3 uses the routes collection to map this kind of url too?? – educampver Mar 15 '13 at 04:32
  • 1
    Anytime you call a Url helper, MVC will run that through the routing table and try to match. In your example, it appears that you are passing your parameters are part of the URL and not in an actual form POST (which is OK and nothing wrong with doing it that way if you are passing simple items back to the controller). – Tommy Mar 15 '13 at 04:34
  • +1 @Tommy thanks a lot, didn't know that, I'll keep it in mind ;) – educampver Mar 15 '13 at 04:41
0

I know this is a old question but I had a similar issue so I ending doing this:

$.ajax({
        type: "Post",
        url: "@Url.Action("Action", "Controller")",
        data:{ param1 : "@Model.param1", param2 : "@Model.param2", param3:"@Model.param3",......,param20 : "something" },
        success: function (response) {
            $("#yourDiv").html(response);
       }
    });

I hope this can be useful for someone else.

Goca
  • 1,743
  • 2
  • 15
  • 36
0

if a method has more than one "route", when calling Url.Action, give null values to any parameters you don't want.

My sample method is below

[Route("carousel/p/{playlistId}/s/{streamId}")]
[Route("carousel/p/{playlistId}")]
public IActionResult Carousel(string playlistId, string streamId)
{
   ...
}

when creating url, i am using like

Url.Action("Carousel", "Viewer", new { playlistId = "35", streamId = "" });
Sedat Kumcu
  • 2,191
  • 1
  • 17
  • 13