How to use RouteConfig to append a page URL - c#

I am struggling to get my code work, but I think I've read enough to suggest this is the correct way to approach this.
On my intranet, I'd like the user to type in a single word to search into a textbox, and check a checkbox. When the new page loads, I'd like the URL rewritting services of ASP.NET MVC to kick in and change a value from
mysite.com/?id=blah&isChecked=true
to
mysite.com/home/index/blah/true
My code isn't working in the sense of it gives no error, but doesn't do what I am explaining. So, I've removed the check box to just focus on the textbox.
My only route is
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{MyType}",
defaults: new { controller = "Home", action = "Index", MyType = UrlParameter.Optional }
);
My Controller
public ActionResult Index()
{
ViewBag.Message = "Modify this";
return View();
}
[HttpGet]
public ActionResult Index(string MyType)
{
ViewBag.Message = "..." + MyType;
return View();
}
and my View has
#using (Html.BeginForm("Index", "Home",FormMethod.Get))
{
<input name="MyType" /><br />
<input type="submit" />
}
#Html.ActionLink("Click me", "Index", new { #MyType = "Blah" }) //renders correctly
The problem is, it shows the querystring still in the address bar
mysite.com/?MyType=MySearchValue
instead of
mysite.com/Home/Index/MySearchValue

You can't do this purely with routing because the browser will always send form values as query string parameters when they are part of a GET request. Once the request has been sent to the server, the MVC framework can't do anything about the URL that was used.
This leaves you with only one real option (assuming you don't want to send a custom request using JavaScript), which is to explicitly redirect to the desired URL (meaning you will always have two requests when this form is submitted).
The simplest way of doing this is simply in the controller (rather, in a separate controller to ensure that there is no conflict in method signatures):
public class FormController : Controller
{
public ActionResult Index(string MyType)
{
return RedirectToAction("Index", "MyProperController", new { MyType });
}
}
If you direct your form to this controller action, MVC will then use the routing engine to generate the proper URL for the real action and redirect the browser accordingly.
You could do this from the same controller action but it would involve inspecting the request URL to check whether a query string was used or not and redirecting back to the same action, which is a little odd.

Related

Asp.net get submit method not working when url is mapped

I have a asp.net mvc form and i want to submit it to same page via get method, it's used for search purpose.
The url is mapped with route key value id.
#using (#Html.BeginForm("Contact", "Home",FormMethod.Get))
{
#Html.TextBox("id", null,
new
{
type = "time"
}
);
<input type="submit" />
}
When the form is generated the action attribute is containing the key value like /Home/Contact/myname.
Here myname is value of id present in url.
When form is submitted value key value for id is getting appended to URL like
http://localhost:57247/Home/Contact/myname?id=11%3A11
The action method is reading myname value instead of 11%3A11.
Action Method:
public ActionResult Contact(string id)
{
ViewBag.Message = id;
return View();
}
It's working fine with post method.
How to fix this?
replace #Html.BeginForm("Contact", "Home",FormMethod.Get)
with #Html.BeginForm()
By default forms are sent to same url they are rendered on and default method is get.
#Html.BeginForm() by default produces a METHOD="POST"
As for your parameter you might want to name it differently.
Default Mvc route is configured like this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Depending on mvc version it can be in global.asax or App_Start\routeconfig.cs
So your "MyName" in url perfectly matches default id parameter and it has higher priority than query string parameters.
If you name your parameter differently (not id).
Change it to "q" for example in action and in view.
Your URLs will change to /Home/Contact?q=myname and everything should start working as expected.
Now you say that you want a solution with url mapping.
So you have to figure out for yourself what url scheme you want.
If you have a form and want it to post to /home/contact/myname?id=notyourname, than you have a conflict which to solve you will have to somehow change binding priorities in mvc.
Now you can inspect querystring on your own in your action and figure out new id passed without binding. After that you can return RedirectToAction("Contact", new{id = figuredId}) and the url in browser will be what you want it to be.
You can change the query parameter name and have your action recieve 2 parameters
public ActionResult Contact(string id, string q){
if (!string.IsNullOrWhitespace(q)){
return RedirectToAction("Contact",new{id=q});
}
}
To send request to /Home/Contact you should use #Html.BeginForm("Contact","Home",new{id=null}, FormMethod.Get)

MVC4 and Routing

I have a single controller and view working that calls a web service, and returns a result. At the moment, it's my default controller, called Home, and it uses the Index view page.
It's working. I can post data and then put something on the refreshed screen. It reloads the same view.
Now, once I submit, and I get a good reply, I want to load a different controller/view.
My routes look like this right now:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Home",
"{lang}",
new { controller = "Home", action = "Index", lang="English" });
routes.MapRoute(
"Location",
"{lang}",
new { controller = "Location", action = "Index", lang = "English" });
I created a controlled called Location, and it just has this:
//LocationController
public class LocationController : Controller
{
public ActionResult Index()
{
return View();
}
}
In my home controller, I am doing the logic, and then attempting to load the new page.
[HttpPost]
public ActionResult Index(HomeModel model)
{
var proxy = new Proxy();
var r = proxy.GetLocationByAddress(model.SearchString, o.ToString());
if(r==null)
{
ViewBag.Error = "Error during search";
return View(model);
}
ViewBag.Error = string.Format("Found {0} at {1}, {2}", r.StreetName, r.Latitude, r.Longitude);
return RedirectToAction("Index", "Location");
}
But when I run it, submit it, step through, it hits the RedirectToAction - but ... the Home screen simply refreshes. I never see the new Location view. What am I doing wrong here? I have't grasped Routes yet... I need to pass a new object to the Location.Index screen to display...
Your route mapping is incorrect, check this out: http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-custom-routes-cs
routes.MapRoute(
"Location",
"Location/{lang}",
new { controller = "Location", action = "Index", lang = "English" });
I don't think so you need to make any changes. As in your case you want to load different controller with its respecting view you need below change only
replace this code return RedirectToAction("Index", "Location");
with this code return Redirect("http://www.yoursite.com/Location/Index");
Your change is like redirection from one page to another therefore you need to put your complete path here
please try & reply if any problem

How to call Action on Button click from JQuery

With ASP.NET MVC, I want to call action of controller on Button Click from JQuery.
Controller:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
public ActionResult PersonInfo(string name, string city)
{
// other code for assign ViewData
return View();
}
}
I have two textBox and one Button in Index.chtml page. I want to display Url like 'http://localhost:2526/PersonName'. for city I want optional perameter and don't want in Url. so, I mapped route as below:
routes.MapRoute(
"Default", // Route name
"",
new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute(
"PersonInfo", // Route name
"{name}", // URL with parameters
new { controller = "Home", action = "PersonInfo", name= "" , city = ""} // Parameter defaults
From browser if I enter Url like 'http://localhot:2526/John' then PersonInfo view displayed successfully.
I visited link related my question. But I also want to pass parameters.
Anyone help me How can I call action on button click from JQuery.
you can pass parameters as query string for example:
$('#buttonId').click(function(){
document.location =
'#Url.Action("MyAction","MyController")'+'?'+'parameterToSend = #value';
});
your link will be like
MyController/MyAction?parameterToSend=value
You want to add the paramaters inside the Url.Action Method to avoid the / at the end of your host.
#Url.Action("PersonInfo","Home" , new {name=Model.Name, city=Model.City })
//I believe this will look at your routes and generate localhost:2526/John/JohnsCity
Are your paramaters part of your model? If so the above will work. If not than you can use 1AmirJalali answer but replace the / before appending the paramaters since if they paramaters are not part of your model then they are probably coming via javascript variables.

Nested Html.Action calls in Razor

EDIT: Obviously this is a vastly simplified version of my site and if I make a test app, with this pattern it works fine. In our real app, we are using T4MVC and this is all within an area. I'm guessing one of these factors is causing my issue...
EDIT2: All the default routes are defined and if I navigate directly to /AreaName/ControllerName/SubChild?val=123 it renders.
I have a peculiar problem with Mvc and am hoping someone can help...
I have a controller with the following action methods
public ActionResult Index()
{
return View(GetModel());
}
public ActionResult Result Child(string blah)
{
return View(GetModel(blah));
}
public ActionResult Result SubChild(int val)
{
return View(GetModel(val));
}
I then have 3 razor views.
Index.cshtml
<div>
#Html.Action("Child", new { blah = "raaa"})
</div>
Child.cshtml
<div>
#*ERROR HERE*#
#Html.Action("SubChild", new { val = 123})
</div>
SubChild.cshtml
<h1>#Model.val</h1>
When I navigate to / I get an exception thrown saying that
"No route in the route table matches the supplied values." on the Html.Action calling the SubChild Action.
This is all within the same area and the same controller. If I change the markup and use Html.Partial for the call to the Child view (and construct the model and pass it in the view), it renders fine. The issue comes when I call Html.Action within a view that's already being rendered using Html.Action.
I've tried fully qualifying the action using
/area/controller/action, specifying the controller in the Html.Action call, passing the area as a parameter in the route values and combinations of all of these.
Does anyone have any ideas what this might be? I'm assuming that you can call Html.Action in Views that are being rendered using it, I guess I might be wrong...
Well, out of the box MVC 3 has the default route parameter named id. Your SubChild action has a parameter named val, so that is probably the issue.
Either rename the parameter in the Action to id, or add a new route
routes.MapRoute(
"SubChild",
"{controller}/SubChild/{val}",
new
{
controller = "ControllerName",
action = "SubChild",
val = UrlParameter.Optional
}
);
Are your parameters really named blahand val? Because normally the first parameter is always called id. Check the method RegisterRoutes(RouteCollection routes) in your global.asax.cs. There must be something like
routes.MapRoute("Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }); // Parameter defaults
That indicates how your parameters have to be named.
I think your Actions have to be like this:
public ActionResult Index()
{
return View(GetModel());
}
public ActionResult Result Child(string id)
{
return View(GetModel(id));
}
public ActionResult Result SubChild(int id)
{
return View(GetModel(id));
}
Then the code in your views has to be:
Index.cshtml
<div>
#Html.Action("Child", new { id = "raaa"})
</div>
Child.cshtml
<div>
#Html.Action("SubChild", new { id = 123})
</div>
It appears the problem is to do with our areas and routing setup.
On the 2nd pass, we are losing the reference to the area in the routevaluedictionary and as such it can't find the correct route. Where we are registering the area, we need to register the correct route.
Thanks for the help with this, I've upvoted the other answers as I think they may help someone else in the future.

ASP.NET MVC2 Custom routing with wildcard or free text url

I have a requirement to add specific functionality to an asp.net mvc2 web site to provide addtional SEO capability, as follows:
The incoming URL is plain text, perhaps a containing a sentence as follows
"http://somesite.com/welcome-to-our-web-site" or
"http://somesite.com/cool things/check-out-this-awesome-video"
In the MVC pipeline, I would like to take this URL, strip off the website name, look up the remaining portion in a database table and call an appropriate controller/view based on the content of the data in the table. All controllers will simply take a single parameter bieng the unique id from the lookup table. A different controller may be used depnding on different urls, but this must be derieved from the database.
If the url cannot be resolved a 404 error needs to be provided, if the url is found but obsolete then a 302 redirect needs to be provided.
Where the url is resolved it must be retained in the browser address bar.
I have had a look at the routing model, and custom routing and can't quite work out how to do it using these, as the controller would not be predefined, based on a simple route. I am also unsure of what to do to provide 404, 302 back to the headers also. Perhpas I need a custom httpmodule or similar but going there went beyond my understanding.
This must be possible somehow... we did it years ago in Classic ASP. Can anyone help with some details on how to achieve this?
Well, the simplest way would be to have an id somewhere in the url (usually the first option)
routes.MapRoute(
"SEORoute", // Route name
"{id}/{*seostuff}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, seostuff = UrlParameter.Optional } // Parameter defaults
);
In your controller you'd have something like
public class HomeController {
public ActionResult Index(int id) {
//check database for id
if(id_exists) {
return new RedirectResult("whereever you want to redirect", true);
} else {
return new HttpNotFoundResult();
}
}
}
If you don't want to use the id method you could do something else like...
routes.MapRoute(
"SEORoute", // Route name
"{category}/{page_name}", // URL with parameters
new { controller = "Home", action = "Index", category = UrlParameter.Optional, pagename = UrlParameter.Optional } // Parameter defaults
);
public ActionResult Index(string category, string page_name) {
//same as before but instead of looking for id look for pagename
}
The problem with the latter is that you would need to account for all types of routes and it can get really difficult if you have a lot of parameters that match various types.
This should get you in the right direction. If you neeed some clarification let me know and I'll see if I can write a specific route to help you
Additional
You could probably do what you're looking for like
public ActionResult Index() {
//Create and instance of the new controlle ryou want to handle this request
SomeController controller = new SomeController();
controller.ControllerContext = this.ControllerContext;
return controller.YourControllerAction();
}
but I don't know any of the side effects by doing that...so it's probably not a good idea - but it seems to work.

Categories