Calling Html.BeginForm and specifying action - asp.net-mvc

I have been trying to do the following but whatever I try I just keep getting different errors:
#using (Html.BeginForm(Url.Action(this.ViewContext.RouteData.Values["action"] as string)))
This for example produces:
<form action="/adminTests/create?Length=22" method="post">
Has anyone figured out how to do this?

You are using a wrong overload. It should be:
#using (Html.BeginForm(new { action = ViewContext.RouteData.Values.GetRequiredString("action") }))
or:
#using (Html.BeginForm(ViewContext.RouteData.Values.GetRequiredString("action"), ViewContext.RouteData.Values.GetRequiredString("controller"))))
or if you want to generate a form POSTing to the current url use simply (note that this will include any query string parameters):
#using (Html.BeginForm())
For full list of available overloads consult the documentation.

Perhaps try this:
#using (Html.BeginForm("action", "controller"))
This uses the correct overload and has a simpler (imo) syntax.

Edge case answer
If you are posting back to an action of the same name, but you loaded the form with more data from the route you have to do one more thing. In your controller, you need to remove the extra routing values.
RouteData.Values.Remove("CompanyId");
Let me explain.
In my case I was loading the Add Contact form passing it the company id in the route, e.g., contact/add/123 to the Add action public IActionResult Add(int companyId). The Add/Edit contact form is then loaded with a new ViewModel with the CompanyId populated. var model = new ContactViewModel { CompanyId = companyId };
The route now serves no purpose, but if you try to use Html.BeginForm("add", "contact") the form will still have an action of contact/add/123, which will cause the routing to fail.
You can work around this by taking the id on the add and ignoring it (yuk!). Or by passing parameters rather than using routing (probably best), but sometimes there are external reasons that's not an option and you have to work with the situation you have.
The Action in one go for easier reading
[HttpGet]
[Route("add/{companyId}")]
public IActionResult Add(int companyId)
{
var model = new ContactViewModel { CompanyId = companyId };
RouteData.Values.Remove("companyId");
return PartialView("_ContactModal", model);
}
[HttpPost]
[Route("add")]
public IActionResult Add(ContactViewModel model)
{
...
}

Related

SurfaceController generate incorrect URL?

A Form is posted to a SurfaceController 'Submit' action. After saving to the database, it redirects to another action 'LeadContact', in the same controller (using RedirectToAction()), passing in 'Id' as a paramter. The model is then populated and passed to the 'LeadContact' view.
Not sure if I'm doing this correctly, but when 'LeadContact' renders in the browser, the URL shows as
http://localhost:50656/umbraco/Surface/HealthInsurance/LeadContact?leadOptionId=70`
while I'm expecting it to be
http://localhost:50656/HealthInsurance/LeadContact?leadOptionId=70
In short it adds /umbraco/SurfaceContact' into url.
Can you please advise how I can correct it and what I'm doing wrong ?
public ActionResult Submit(FormCollection form)
{
//Some logic and later redirect to another action 'LeadContact'
return RedirectToAction("LeadContact", new { leadOptionId = _id});
}
public ActionResult LeadContact(int leadOptionId)
{
MyViewModel model = new MyViewModel();
//Lines of code to populate data into model
return View("LeadContact", model);
}
Thanks for your help and sharing.
Check your project properties, under Web you most likely have a virtual path specified.

#Url.Action results 404 error when called from form

I work on ASP.NET MVC application. Table is being populated using jQuery, but it doesn't matter now.
The problem is this:
When I make a call with form tags, I get an error 404 Not Found. By inspecting I confirmed that model is bound OK (it's populated).
When I comment out form tags, I can make a call to method, but with model being null (like it's not bound).
Here is some of code I use:
#model PayrollModel
#*#using (Html.BeginForm("Index", "Request", FormMethod.Post, new { id = "frmPersonView" }))
{*#
<table data-dataurl="#Url.Action("PayrollData", "Payroll")" id="tblData" class="table hover table-bordered table-striped"></table>
#*}*#
Here is my controller method:
[HttpGet]
public ActionResult PayrollData(PayrollModel model)
{
//do something
}
Edited:
I found out why this happens:
Request URL:
http:// localhost/CT.ISVDV.WebUI/Payroll/PayrollData?sEcho=1&iColumns=5&sColumns=&iDisplayStart=0&iDisplayLength=10&mDataProp_0=FIRSTNAME&mDataProp_1=LASTNAME&mDataProp_2=RIGHTGROUPNAME&mDataProp_3=DISABILITYTYPENAME&mDataProp_4=AMOUNT&iSortCol_0=0&sSortDir_0=asc&iSortingCols=1&bSortable_0=true&bSortable_1=true&bSortable_2=true&bSortable_3=true&bSortable_4=true&SelectedTypes%5B3%5D=4&SelectedTypes%5B4%5D=5&SelectedTypes%5B5%5D=6&SelectedTypes%5B6%5D=7&SelectedTypes%5B7%5D=8&SelectedTypes%5B8%5D=9&SelectedTypes%5B9%5D=10&SelectedTypes%5B10%5D=11&SelectedTypes%5B11%5D=12&SelectedTypes%5B12%5D=13&SelectedTypes%5B13%5D=14&SelectedTypes%5B14%5D=15&SelectedTypes%5B15%5D=16&SelectedTypes%5B16%5D=17&SelectedTypes%5B17%5D=18&SelectedTypes%5B18%5D=19&SelectedTypes%5B19%5D=20&SelectedTypes%5B20%5D=21&SelectedTypes%5B21%5D=22&SelectedTypes%5B22%5D=23&SelectedTypes%5B23%5D=24&SelectedTypes%5B24%5D=25&SelectedTypes%5B25%5D=26&PayrollDate=01.12.2014&PayrollSearch.RIGHTGROUPIDList.Value%5B0%5D=4&PayrollSearch.RIGHTGROUPIDList.Value%5B1%5D=5&PayrollSearch.RIGHTGROUPIDList.Value%5B2%5D=6&PayrollSearch.RIGHTGROUPIDList.Value%5B3%5D=7&PayrollSearch.RIGHTGROUPIDList.Value%5B4%5D=8&PayrollSearch.RIGHTGROUPIDList.Value%5B5%5D=9&PayrollSearch.RIGHTGROUPIDList.Value%5B6%5D=10&PayrollSearch.RIGHTGROUPIDList.Value%5B7%5D=11&PayrollSearch.RIGHTGROUPIDList.Value%5B8%5D=12&PayrollSearch.RIGHTGROUPIDList.Value%5B9%5D=13&PayrollSearch.RIGHTGROUPIDList.Value%5B10%5D=14&PayrollSearch.RIGHTGROUPIDList.Value%5B11%5D=15&PayrollSearch.RIGHTGROUPIDList.Value%5B12%5D=16&PayrollSearch.RIGHTGROUPIDList.Value%5B13%5D=17&PayrollSearch.RIGHTGROUPIDList.Value%5B14%5D=18&PayrollSearch.RIGHTGROUPIDList.Value%5B15%5D=19&PayrollSearch.RIGHTGROUPIDList.Value%5B16%5D=20&PayrollSearch.RIGHTGROUPIDList.Value%5B17%5D=21&PayrollSearch.RIGHTGROUPIDList.Value%5B18%5D=22&PayrollSearch.RIGHTGROUPIDList.Value%5B19%5D=23&PayrollSearch.RIGHTGROUPIDList.Value%5B20%5D=24&PayrollSearch.RIGHTGROUPIDList.Value%5B21%5D=25&PayrollSearch.RIGHTGROUPIDList.Value%5B22%5D=26&tblData_length=10&
Up to this point, everything is right, but then i also passes some strange values that are not model properties. This happens only if I use form tags, and I need those.
DXScript=1_157%2C1_89%2C1_88%2C17_28%2C17_2%2C1_149%2C1_86%2C1_141%2C1_96%2C17_7%2C1_139%2C1_98%2C1_97%2C17_8%2C1_155%2C1_125%2C1_156%2C1_118%2C17_9%2C1_148%2C1_147%2C1_132%2C17_27%2C1_142%2C1_93%2C1_119%2C1_99%2C1_151%2C1_126%2C17_13%2C1_108%2C1_115%2C1_137%2C1_92%2C1_152%2C1_128%2C17_15%2C1_129%2C1_120%2C17_11%2C1_131%2C1_140%2C1_134%2C17_18%2C1_145%2C17_20%2C1_143%2C1_138%2C1_146%2C1_150%2C17_23%2C17_26%2C1_95%2C5_5%2C5_4%2C4_11%2C4_10%2C4_6%2C4_7%2C4_9%2C17_14%2C4_12%2C1_107%2C1_110%2C4_13%2C4_14%2C1_106%2C1_124%2C17_12%2C1_144%2C7_48%2C1_91%2C7_50%2C17_19%2C1_100%2C1_103%2C1_111%2C17_0%2C1_114%2C1_101%2C17_1%2C1_102%2C17_3%2C1_104%2C1_116%2C17_5%2C1_130%2C1_113%2C17_16%2C17_17%2C1_112%2C17_24%2C1_117%2C10_2%2C10_1%2C10_3%2C10_4%2C17_4%2C9_15%2C9_12%2C9_10%2C17_21%2C9_14%2C9_11%2C9_13%2C8_10%2C8_17%2C8_24%2C8_26%2C8_9%2C8_12%2C8_13%2C8_18%2C17_22%2C8_21%2C8_23%2C8_22%2C8_16%2C8_19%2C8_20%2C8_14%2C8_15%2C8_25%2C8_11%2C6_12%2C17_25&DXCss=%2FCT.ISVDV.WebUI%2Fimg%2Ffavicon.ico%2C%2FCT.ISVDV.WebUI%2FContent%2Fjvectormap%2Fjquery-jvectormap-1.2.2.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fbootstrap.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2Ffont-awesome.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fionicons.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2FiCheck%2Fall.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fcolorpicker%2Fbootstrap-colorpicker.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2Ftimepicker%2Fbootstrap-timepicker.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fmorris%2Fmorris.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fdatepicker%2Fdatepicker3.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fdaterangepicker%2Fdaterangepicker-bs3.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fbootstrap-wysihtml5%2Fbootstrap3-wysihtml5.min.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fcss%2Fselect2.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fselect2-bootstrap.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fdatatables%2FdataTables.bootstrap.css%2C%2FCT.ISVDV.WebUI%2FContent%2FAdminLTE.css%2C%2FCT.ISVDV.WebUI%2FContent%2FSite.css%2C%2FCT.ISVDV.WebUI%2FContent%2Fjquery.bootstrap-touchspin%2Fjquery.bootstrap-touchspin.css%2C1_9%2C1_11%2C0_844%2C0_842%2C1_8%2C0_691%2C0_694%2C0_682%2C1_4%2C0_684%2C0_805%2C0_698%2C4_2%2C0_700%2C5_1%2C0_782%2C0_762%2C0_764%2C7_1%2C7_0%2C1_1%2C0_657%2C0_869%2C0_871%2C0_777%2C8_2%2C0_779%2C8_0%2C0_794%2C6_2%2C0_796&_=1417596051723
How can I prevent this from happening?
Your formatting is off. Try mix single quotes with double ones:
data-dataurl='#Url.Action("PayrollData", "Payroll")'
PayrollData expects a PayrollModel model and you're providing none. There's no reasonable way to send a whole model using Url.Action so consider sending only an ID.
data-dataurl='#Url.Action("PayrollData", "Payroll", new { id = model.ID })'
I think you are very confused on how it all works, especially model binding.
Normally you would have something like this (Lets say we are working only have Payroll controller)
[HttpGet]
public ActionResult Index()
{
// here you would get your model that displays some data on that page
PayrollIndexModel model = fetchModelData();
return View(model)
}
and its view
#model PayrollIndexModel
#Model.PageTitle
#using (Html.BeginForm("Request", "Payroll", FormMethod.Post, new { id = "frmPersonView" }))
{
<table data-dataurl="#Url.Action("PayrollData", "Payroll")" id="tblData" class="table hover table-bordered table-striped"></table>
}
then if you click Save on the form you would call the one below where PayrollModel is binded to your model class and later you can do things with it.
[HttpPost]
public ActionResult Request(PayrollModel model)
{
// save stuff to database
}
To get this one working
#Url.Action("PayrollData", "Payroll")
You have to create actions this way as you are requesting data by GET method and not sending anything to the server:
[HttpGet]
public ActionResult PayrollData()
{
PayrollModel model = fetchModelData();
return View(model)
}
However, I see that you use DataTables library and last time I used it I remember that Datatable is expecting JSON object. So here you should send JSON.
[HttpGet]
public ActionResult PayrollData()
{
PayrollModel model = fetchModelData();
return Json(model)
}
Your model converted to JSON should be formatted in the way that JQuery DataTable can parse it (understand it) such as:
{ "iTotalRecords":11,
"iTotalDisplayRecords":11,
"sEcho":1,
"aaData":[{"FirstName":"Dan","LastName":"Callahan","PhoneNumber":"(123) 555-5552","Age":35,"Birthday":"\/Date(218955600000)\/"},
{"FirstName":"Tom","LastName":"Gun","PhoneNumber":"(123) 555-5559","Age":59,"Birthday":"\/Date(-534538800000)\/"},
{"FirstName":"James","LastName":"Halk","PhoneNumber":"(123) 555-5554","Age":21,"Birthday":"\/Date(660027600000)\/"},
{"FirstName":"Jarold","LastName":"Interface","PhoneNumber":"(123) 555-5556","Age":39,"Birthday":"\/Date(86932800000)\/"},
{"FirstName":"Kevin","LastName":"Kentucky","PhoneNumber":"(123) 555-5551","Age":40,"Birthday":"\/Date(92638800000)\/"},
{"FirstName":"Justin","LastName":"Michaels","PhoneNumber":"(123) 555-5555","Age":27,"Birthday":"\/Date(470898000000)\/"},
{"FirstName":"Erich","LastName":"Milton","PhoneNumber":"(123) 555-5558","Age":54,"Birthday":"\/Date(-370724400000)\/"},
{"FirstName":"Mike","LastName":"Peterson","PhoneNumber":"(123) 555-5550","Age":24,"Birthday":"\/Date(568184400000)\/"},
{"FirstName":"Jason","LastName":"Ralph","PhoneNumber":"(123) 555-5557","Age":27,"Birthday":"\/Date(468306000000)\/"},
{"FirstName":"John","LastName":"Thompson21","PhoneNumber":"(123) 555-5545","Age":27,"Birthday":"\/Date(473317200000)\/"}
]}
To make your life easier check this library which does a lot of tedious work for you:
https://github.com/ALMMa/datatables.mvc
Good Luck.

MVC sending data from View to Controller

I am quite new to MVC 3.
I know how to send a strongly typed object from a Controller to a View. What I have now, is a View which contains a table/form which consists of that data.
The user can change that data whilst they're are in that View (html page).
When they click on "Save", how do I send the data from the View back to the Controller so that I can update my database.
Do I overload the Controller method so that it accepts a parameter of the model type? Can you please provide some source code.
(Please do not show code of persisting data to a database, I know how to do that part).
Thank you very much for helping me.
I would also prefer using #Html.BeginForm()
I like creating an action method made for my post data. So let's say you have a UserViewModel:
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Then a UserController:
public class UserController
{
[HttpGet]
public ActionResult Edit(int id)
{
// Create your UserViewModel with the passed in Id. Get stuff from the db, etc...
var userViewModel = new UserViewModel();
// ...
return View(userViewModel);
}
[HttpPost]
public ActionResult Edit(UserViewModel userViewModel)
{
// This is the post method. MVC will bind the data from your
// view's form and put that data in the UserViewModel that is sent
// to this method.
// Validate the data and save to the database.
// Redirect to where the user needs to be.
}
}
I'm assuming you have a form in your view already. You'll want to make sure that the form posts the data to the correct action method. In my example, you'd create the form like so:
#model UserViewModel
#using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
#Html.TextBoxFor(m => m.Name)
#Html.HiddenFor(m => m.Id)
}
The key to all this is the model binding that MVC does. Make use of the HTML helpers, like the Html.TextBoxFor I used. Also, you'll notice the top line of the view code I added. The #model tells the view you'll be sending it a UserViewModel. Let the engine do work for you.
Edit: Good call, did that all in Notepad, forgot a HiddenFor for the Id!
In MVC, the act of scraping out data from POST or GET HttpRequests is referred to as Model Binding - there are plenty of SO questions relating to this.
Out of the box, MVC will bind your Get and Post variables based on convention, e.g. a form field with the name 'FormName' will be bound back to a parameter on your controller with the same name.
Model binding also works for objects - MVC will instantiate an object for your controller, and set the properties with the same name as your form.

Query String from BeginForm in MVC 3

I want to use BegingForm with Get method and this is what I do
#using (Html.BeginForm("Search","Home",FormMethod.Get))
{
//My input elements
}
public class HomeController : Controller
{
public ActionResult Search(string queryString)
{
}
}
but query string always comes back as null. I think, I need to do something with route but no luck
routes.MapRoute(
"SearchRoute", // Route name
"Home/Search{queryString}", // URL with parameters
new { controller = "Home", action = "Search", filter = UrlParameter.Optional } // Parameter defaults
);
Obviously, the coming url to the server is something like
Home/Search?query="blah"&query2="blah"&query3="blah"
What am I doing wrong? What is the correct way to get the query parameters in my controller when I want to use get with beginform?
Also, what if the content of my BeginForm can change and so the query string parameter names could be different depending on the rendered page but I want one Search method that analyze the query string and do the right thing?
Also, is a way for them to query parameters to come in a dictionary?
Obviously, the coming url to the server is something like
Home/Search?query="blah"&query2="blah"&query3="blah"
That's how HTML <form> with method GET works and this has nothing to do with ASP.NET MVC, it's plain HTML. You can't do much about it other than having your controller action look like this:
public ActionResult Search(SearchViewModel model)
{
...
}
Where SearchViewModel will contain properties for each input field on this form. Also you don't need this SearchRoute as it won't work that way.
This being said you could probably use javascript in order to subscribe for the onsubmit event of the form, cancel the default submission (which exhibits the behavior you are observing currently), manually fetch all the values inside your form and then manually generate the url you want and redirect to it using window.location.href = '....';. I am mentioning this only for completeness but absolutely not as something that I recommend or that you should ever do.
If you want to get the items from the query string, just use the "Request" object from the ControllerBase:
public ActionResult Search()
{
var queries = new List<string>();
foreach (var parameter in Request.QueryString)
{
queries.Add(parameter.ToString());
}
//Do Stuff with the query parameters...
return View("Index");
}
And "Request.QueryString" is a dictionary just as you wanted :)

How to change action parameters and get it to work without changing routing in asp.net mvc?

In my route I have something like this:
controller/action/{id}
To my knowledge this means it will call any action with the parameter id like the following:
public ActionResult Detail(string id)
{
}
What do I have to do to make the following work without registering the particular route in global.asax file:
public ActionResult Detail(string customerId)
{
}
If you really don't want to rename the method parameter, you can use BindAttribute to tell MVC what its logical name should be:
public ActionResult Detail([Bind(Prefix = "id")] string customerId)
You can also pass customerId as query string, which is normally what I do:
<%: Html.ActionLink("Detail", "Detail", new { #customerId = Model.CustomerID}, null)%>
MVC does not enforce the routing, but rather try to resolve routing based on your url AND query string.
have a route like - controller/action/{customerId} or just rename the parameter customerId to id and then use it the particular way you want.

Resources