I needed to get a data from the url on my post method. I have this routing on my asax:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Then on my Home Controller, under Get:
[HttpGet]
public ActionResult Index()
{
var id = ControllerContext.RouteData.GetRequiredString("id");
}
And on Post:
[HttpPost]
public ActionResult SomeNewNameHere(HomeModel homeModel)
{
var id = ControllerContext.RouteData.GetRequiredString("id");
}
My problem here is I need that id from the url on my post method. By debugging, I noticed that it gets the id on the get method, but when i post it, it returns me a null resulting to an error. So basically, RouteValues work on Get but not on my Post. Anything I missed here? Thanks!
Sample url:
http://localhost:1000/Controller/Action/12312121212
EDIT:
I also tried this but no luck:
var id = ControllerContext.RouteData.Values["id"];
The form on the view:
#using (Html.BeginForm("SomeNewNameHere", "Home", FormMethod.Post))
You can add id parameter to the post URL in your view:
#using (Html.BeginForm("SomeNewNameHere", "Home",new { id = Model.ID}, FormMethod.Post))
Add and int Id property to your HomeModel
then in your view, within your form:
#Html.Hiddenfor(m => m.Id)
This will post the Id to your action method
With the help of Ufuk Hacıoğulları, I came up with this solution on my form:
(Html.BeginForm("SomeNewNameHere", "Home",new { id = ViewContext.RouteData.GetRequiredString("id") }, FormMethod.Post))
So what happened here is it includes the id when it do a post.
Your Querystring values and Form values are automatically sent to the ActionResult at the same time, and the ASP.Net MVC Model binder will attempt to bind everything that it can.
So your GET Index ActionResult should be;
[HttpGet]
public ActionResult Index(int id)
{
// access id directly
}
And your POST Index ActionResult should be;
[HttpPost]
public ActionResult SomeNewNameHere(int id, HomeModel homeModel)
{
// access id directly
}
So your URL needs to be /Home/Index?id=1
Related
I have a controller which displays user profiles the Action for showing a profile is just under Index : its /User/123 to show user 123. This is set on route map like this:
routes.MapRoute(
name: "User",
url: "User/{id}",
defaults: new {controller = "User", action = "Index", id = UrlParameter.Optional}
);
Now my controller looks something like this:
public class UserController : Controller
{
[Authorize]
public ActionResult Index(int id)
{
*edited out for simplicity*
return View(model);
}
[Authorize]
[HttpPost]
public ActionResult Follow(int id)
{
*edited out for simplicity*
return RedirectToAction("Index", "User", new { id });
}
}
And my web form:
using (Html.BeginForm("Follow", "User", FormMethod.Post))
{
<input type="submit" value="Follow!" class="btn btn-success" />
}
Now the GET works perfectly but when I submit the POST it isn't handing over the user id from the url /user/123.
Do I need to perform an extra action in the Html.BeginForm if I am going from a GET on Index to a POST on Follow in order for it to hand over the {id} ?
You can use the BeginForm overload that takes RouteValues and pass the id from the Url using the RequestContext
Html.BeginForm("Follow","User", new { id = #Url.RequestContext.RouteData.Values["id"] }, FormMethod.Post);
I'm trying to setup a simple form submission in MVC5, but I'm finding that my method doesn't get fired unless I have both an ActionLink and submit button.
I have a simple model:
public class LoginModel
{
public string username { get; set; }
}
Then I have two methods in my controller, one for when a form submission is available and one when not:
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel myModel)
{
var username = myModel.username;
// do something with username
return View();
}
Finally, my View creates a POSTing form:
#using (Html.BeginForm("Login", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.TextBox("username", string.Empty)
#Html.ActionLink("Enter", "Login")
<input type="submit" name="submit" value="Enter" />
}
I don't really care whether I use an ActionLink or whether I have a submit button (MSDN implies it should be the latter), but if I have only one of them, my [HttpPost] method is not called, and my page is redirected with the username in the query string:
/Home/Login?ReturnUrl=%2F%3Fusername%3DmyUsernameHere
If I have both on the page, I can click the ActionLink and I see that the appropriate method is called with myModel.username containing the value I provided. The submit button, however, will still redirect.
I want this form method to be POST, not GET (which it is in the generated HTML), and for failures to not contain the key as a GET param. What's the problem with having only one of these form submission mechanisms? Why do they not trigger the POST as expected? Is there something more I need to do to 'register' my model with the view, even though it is submitted properly in my workaround scenario?
Edit -- My configured routes are typically as follows:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.RouteExistingFiles = true;
So normally, I'm going to /Login instead of /Home/Login.
Also, I do have some authentication setup, with my HomeController decorated with [Authorize] and my Login methods both with [AllowAnonymous]. When I remove all annotations, I still find that my [HttpPost] is not called, and username shows up as a GET parameter instead of being POSTed.
I believe that the application doesn't understand that you're trying to make a model with just username. So, you are sending a string username and attempting to place it into a model. I'm not entirely sure about that. Could you try binding your form to your model? Here's an example:
View:
#model YourApplication.Models.LoginModel
#using (Html.BeginForm("Login", "Home"))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.username, string.Empty)
<input type="submit" value="Enter" />
}
Controller:
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login([Bind(Include="username")] LoginModel myModel)
{
var username = myModel.username;
// do something with username
return View("Congrats");
}
Here's an alternate option. If you wanted to do something else, maybe try accepting the string "username" and creating your model after? Example:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(string username)
{
LoginModel myModel = new LoginModel();
myModel.username = username;
// do something with username
return View("Congrats");
}
Either way, you should be using the submit button.
So, I am trying to submit a form on a List Page(http://example.com:3480/List) which is actually a Search implementation. So far I have done this:
index.cshtml
#using(Html.BeginForm("Search","ListController"))
{
<input id=query type=text name=query />
<input id=btnsearch type=submit value=Search />
}
ListController.cs
[HttpPost]
public ActionResult Search(FormCollection collection)
{
Response.Write("We are here");
// Get Post Params Here
string var1 = collection["query"];
Response.Write(var1);
return View();
}
Global.asax
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Details",
"Details/{id}/{orderid}",
new { controller = "Details", action = "Index", id = UrlParameter.Optional, orderid = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
}
Upon Clicking it goes to http://example.com:3480/ListController/Search which seems fine.
Now I guess I need to define route in Global.aspx but not sure. What I want is to show result in same View file instead of creating a new one.
At this moment I am unable to get into Search method after POSTing form
Assuming you are currently just using the default route, the reason you are not reaching the action method is that the "Controller" suffix on your route is implicit - it shouldn't be part of your URL.
#using(Html.BeginForm("Search","List"))
Additionally, regarding:
What I want is to show result in same View file instead of creating a new one.
You can easily return a specific view from any controller action by specifying the name of the view in the call to the View method:
return View("Index");
I having some problems overloading the Index action in a controller. In the controller I have the following actions:
public ActionResult Index(int id)
{
return View();
}
public ActionResult Index()
{
return View();
}
Going to either URL (controllername/ or controllername/1) results in a 500 error. However when I use:
public ActionResult Index(int? id)
{
return View();
}
The controllername/ URL works but controllername/1 results in a 404 error. My global.asax is pretty vanilla:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
What I would like to do is be able to handle a null id as well as an integer id value. Any suggestions would be greatly appreciated.
Thanks!
I think you will need to explicit the routes for that:
routes.MapRoute(
"ControllerName", // Route name
"ControllerName/{id}", // URL with parameters
new { controller = "ControllerName", action = "Index", id = UrlParameter.Optional }
);
if it doesn't work, you may need to be more explicit and add this before:
routes.MapRoute(
"ControllerName",
"ControllerName",
new { controller = "ControllerName", action = "Index"}
);
I think you don't need an overload here, but just need a check inside the index action for the null.
Overloading action is not a good idea, because framework would have no idea of which action to call incase of null index.
Adding custom routing for every action overload will cause slower response time because of too many custom routes to resolved.
Hey, one more newbie here, just playing around with .NET MVC. My main task is to have a few semi-static pages on URLs like:
/about/
/about/contacts/
/about/jobs/
I'm using a controller for that called Static and have the following route attached:
routes.MapRoute(
"About",
"about/{id}",
new { controller = "Static", action = "Index", id = UrlParameter.Optional }
);
It seems to work fine as I have the Static controller with the Index method which uses a switch statement to identify which page has to be viewed. I use the RedirectToAction() function to call other actions of the Static controller in order to display pages with other views. My views are:
/Static/About.aspx
/Static/Contacts.aspx
/Static/Jobs.aspx
This method seems to work fine, but what I don't like about it is the redirect, so browsing to /about/contacts I get a redirect to /Static/Contacts which is not what I'd really like to see in the URL.
So my question is - what is the correct way of doing this? And is there a way to explicitly call a certain view from my Index action?
Thanks,
~ K.
Don't do the redirect. Instead of using a switch statement within the Index action, have a separate action for each page (ie. About, Contacts, Job) each with their own view.
Your Static controller could look something like this:
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contacts()
{
return View();
}
public ActionResult Jobs()
{
return View();
}
And if you needed to do any processing specific to Contacts or Jobs, it can be done within their respective actions.
To explicitly call a certain view:
return View("ViewName");
There are seven overloads for the View() method. A number of which allow you to pass the Model:
return View("ViewName", Model);
I'd recommend moving away from Static, and have an About controller. Within that controller, one method per page.
public ActionResult About()
{
return View ("About");
}
//Jobs() and Contacts() follow the same pattern
3 routes to match:
routes.MapRoute(
"Jobs",
"about/jobs",
new { controller = "About", action = "Jobs" }
);
routes.MapRoute(
"Contact",
"about/contact",
new { controller = "About", action = "Contact" }
);
routes.MapRoute(
"About",
"about/",
new { controller = "About", action = "About" }
);
you cant return views from a different controller and have the first controller in the URL.
the only way is use your about controller.
so place your logic in your about controller.
i have the same for myself in my Admin controller. it's just a page with some static links, and some extra pages.
in the index.aspx i have
<ul>
<li>
<%= Html.ActionLink("Evaluaties", "Evaluaties", "Admin")%></li>
<li>
<%= Html.ActionLink("ONAS aanbieders", "Index", "ONASAanbieder")%></li>
<li>
<%= Html.ActionLink("ONAS aanbod", "Index", "ONASAanbod")%></li>
<li>
<%= Html.ActionLink("Helpbox", "Index", "HelpBox")%></li>
</ul>
in the controller I have
public ActionResult Index() {
return View();
}
public ActionResult Evaluaties() {
return View();
}
this works like you described, no need to alter the routes.
obviously i have an Evaluaties.aspx in my Admin folder in the Views folder.
gives me this URL: http://localhost:50152/Admin/Evaluaties