6

I setup a route like that:

routes.MapRoute(
    name: "Pesquisar",
    url: "Pesquisar/{aaa}/{bbb}/{id}",
    defaults: new { controller = "Home", action = "Pesquisar",
                    aaa = UrlParameter.Optional,
                    bbb = UrlParameter.Optional,
                    id = UrlParameter.Optional
    }
);

When I press Send button in a form (with GET method) the url is like that:

http://localhost:00000/Pesquisar?aaa=One&bbb=Two

But I was expecting for:

http://localhost:00000/Pesquisar/One/Two
Fabricio
  • 7,705
  • 9
  • 52
  • 87
  • 1
    does the same thing happen when ID has a value? – Jeroen Vannevel Jul 11 '13 at 01:57
  • @JeroenVannevel: yes. If i type manualy in the browser it works (`http://localhost:00000/Pesquisar/foo/bar/1`) but via form GET it doesn't. I mean, it works, but not with friendly url. – Fabricio Jul 11 '13 at 02:07

5 Answers5

1

When you map a rout, it adds it to the end of a list. When the router looks for the rule to match, it starts at the begining of the list and itterates through it. It will take the first rule that matches, not the most specific rule. Because it is natural to append code to the end, the default rule (which works for almost everything) will be at the start.

Try re-ordering your code to look like this:

        ///The specific rout which you want to use
        routes.MapRoute(
        name: "Pesquisar",
        url: "{action}/{aaa}/{bbb}/{id}",
        defaults: new { controller = "Home", action = "Pesquisar",
                        aaa = UrlParameter.Optional,
                        bbb = UrlParameter.Optional,
                        id = UrlParameter.Optional
        }
        );

        ///The generic catch all router
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

More information can be found in this question:
Setting up ASP.Net MVC 4 Routing with custom segment variables

Community
  • 1
  • 1
David Colwell
  • 2,450
  • 20
  • 31
1

When I press Send button in a form (with GET method) the url is like that:

http://mydomain.com/Pesquisar?aaa=One&bbb=Two

But I was expecting for:

http://mydomain.com/One/Two

This is because the browser is unaware of the fancy url you want, as the standard form Get method is to append form values in the querystring.

What you mostly likely have to do is something like Creating Canonical URLs including an id and title slug, except redirect to the url you want if it's not the url you want to display.

Or you can use jQuery to manually create the url you want on submit, but requires more client side work.

Community
  • 1
  • 1
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
0

Not sure if you get a clean URL directly from a html form GET.

One suggestion would be to POST it to an action, do what you need to do with the data, then on completion, redirect to your clean URL.

e.g.

ViewModel:

public sealed class PesquisarModel
{
    public string aaa { get; set; }
    public string bbb { get; set; }
    public string id { get; set; }
}

Controller Actions:

[HttpGet]
public ActionResult Pesquisar(PesquisarModel m)
{
    return View();
}

[HttpPost]
[ActionName("Pesquisar")]
public ActionResult PesquisarPost(PesquisarModel m)
{
    //do stuff
    return RedirectPermanent("/pesquisar/" + m.aaa + "/" + m.bbb + "/" + m.id);
}

View:

@model MyApplication.Models.PesquisarModel

@using (Html.BeginForm())
{
    @Html.TextBoxFor(m => m.aaa)
    @Html.TextBoxFor(m => m.bbb)
    @Html.TextBoxFor(m => m.id)
    <button type="submit">Submit</button>
}
mnsr
  • 12,337
  • 4
  • 53
  • 79
0

This is the browser behavior. When making a GET request browser appends all KeyValue pairs to querystring.

The mentioned route format will be available, when we use Html.ActionLink or Html.RouteUrl etc.

You could probably write few code in OnActionExecuting ( or you can use any handler) to reconstruct RouteData and redirect with appropriate url. Below code is not tested

var queries = this.Request.QueryString;

foreach(var query in queries)
{
 // Add/Update to RequestContext.RouteData

}

var redirectUrl = Url.RouteUrl("Pesquisar",this.RequestContext.RouteData);

Response.Redirect(redirectUrl);
Manas
  • 2,534
  • 20
  • 21
0

That's expected behavior.

The routing system is on server side. The browser knows nothing about routes, and what you're doing happens in the browser.

If you want to get that route you have to compose it on the client side with a custom script which uses the <form>'s action, an the values of the <input type="text"> values.

You cannot generate the Url on the server side (which could be done with some UrlHelper extension methods) because the changes on the text boxes wouldn't be updated.

This is not advisable because if you make changes on the routes, you could forget to update them in your browser scripts, breaking you application.

You could avoid this problem by creating the url in the server side using an UrlHelper extension method with special placeholders, which could be easily replaced on the client side. I.e. generate an url like this:

http://localhost/Pesquisar/$aaa$/$bbb$/$id$

by providing RouteValues like this: new {aaa="$aaa$, bbb="$bbb$, id="$id$"} to an UrlHelper method. This url can be stored in the value property of a hidden field.

Then, make a browser script for the click event of your button, recover the url with the placeholders from the hidden field, and replace the placeholders with the actual values of the textboxes. To execute the get run this: document.location = theUrl;

If you want to d this for many differnt instances you could create a Helper to geenrate the hidden field with the Url, and a javascript which makes the replacements.

The question is... is it worth the effort?

JotaBe
  • 38,030
  • 8
  • 98
  • 117