send model object from view to controller method ASP.NET MVC C# - c#

I know there are a lot of questions about this, but not in a single one I've seen (and I've been searching for two hours now), did I see what to write in the razor view (.cshtml file) to fire the controller method associated with saving the model object to the database, or how that object is passed.
So I want to make a simple registration page. I created the Users model, created the view associated with the model, named Register.cshtml, and I access the view through the Account controller which has a Register method:
public ActionResult Register()
{
return View();
}
The tutorial I follow uses the default code generated in the View when you create it for the Users model.
<input type="submit" value="Create" class="btn btn-default" />
And states that you should make a method in the Account Controller as follows:
public ActionResult Register(User obj)
{
if (ModelState.IsValid)
{
DatabaseEntities db = new DatabaseEntities();
db.Users.Add(obj);
db.SaveChanges();
}
return View(obj);
}
(where DatabaseEntities is the name of my database)
This doesn't work, because, on running the application, it says that it doesn't know which one of the two methods to fire.
System.Web.Mvc.ActionResult Register() on type Biblioteca.Controllers.AccountController
System.Web.Mvc.ActionResult Register(Biblioteca.Models.User) on type Biblioteca.Controllers.AccountController
This is the error I get.
I thought of renaming the second method RegisterPost(User obj), but then I don't know how to call the method with the argument, because in the razor view, I don't know which is the object that gets created on submitting the form.
I could use an #Html.ActionLink(), but I don't know how to send the object.
I actually tried adding an onclick method to the submit button, as follows:
onclick="location.href='#Url.Action("RegisterPost", "Account")'"
But after filling the form and clicking the submit button, nothing happens. Nothing gets inserted into the database.
I don't know what to do now. Please help.

Add attribute [HttpGet] to the first action and [HttpPost] to the second action:
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(User obj)
{
if (ModelState.IsValid)
{
DatabaseEntities db = new DatabaseEntities();
db.Users.Add(obj);
db.SaveChanges();
}
return View(obj);
}
You can read more on MSDN

To expand a bit, try adding [HttpPost] above the second Action method.
[HttpPost]
public ActionResult Register(User obj)
{
if (ModelState.IsValid)
{
DatabaseEntities db = new DatabaseEntities();
db.Users.Add(obj);
db.SaveChanges();
}
return View(obj);
}

Related

How to redirect to a post action from a get action mvc

I have the following Get action:
[HttpGet]
[AllowAnonymous, OnlyAnonymous]
public ActionResult VerifyVoucherCode()
{
var model = new VerifyVoucherCodeModel();
model.VoucherCode = Request.GetFirstQueryValue("token", "voucherCode");
if (!string.IsNullOrEmpty(model.VoucherCode))
{
// prepopulates the code for the user already in a form
}
return View(model);
}
And a POST action for when the user submits the form:
[HttpPost, AjaxOnly]
[AllowAnonymous, OnlyAnonymous]
[ValidateAntiForgeryToken]
public ActionResult VerifyVoucherCode(VerifyVoucherCode model)
{
return ExecuteAction(() =>
{
// do something
});
}
I want to change the logic so that if the voucher code is in the request, the form is submitted automatically for the user without them having to submit the form themselves (i.e. it takes them straight to that Post action). I've looked at lots of Stack Overflow questions and answers and it seems I cannot redirect to the Post action. I have also tried creating a second Get action which calls the Post action but that does not work either. Does anyone know the correct way to approach this problem?
Thanks
Assuming the model contains a single string for the voucher, you can do something like this:
[HttpGet]
[AllowAnonymous, OnlyAnonymous]
public ActionResult VerifyVoucherCode(string id)
{
if(string.IsNullOrEmpty(id))
{
MyModel model1 = new MyModel();
...
return View(model1);
}
//otherwise process the voucher here
...
return RedirectToAction("SuccessMsg");
}

Connecting multiple Action methods to one View

The problem I am facing is that when the delete link is clicked and my delete actionResult is called it errors out saying there is no view for delete. I have tried setting ActionName("Index") but then I get an ambiguous error message regarding the View Index.
public ActionResult Index()
{
***code goes here****
return View(viewModel);
}
[HttpPost, ActionName("Index")]
[OnAction(ButtonName = "Create")]
public ActionResult Index(***code goes here***)
{
***code goes here****
return RedirectToAction("Index");
}
//GET:
public ActionResult Delete(int? id)
{
***code goes here****
return View(lansing);
}
//POST:
[HttpPost, ActionName("Index")]
[OnAction(ButtonName = "Delete")]
//[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
***code goes here****
return RedirectToAction("Index");
}
I then have one table that gets updated with information that the user puts in as well as delete information when an actionLink is clicked from the table which is handled by both of these ActionResults.
You can specify which view to render by passing the name of the view as first argument to the call of the view method (see the documentation of ASP.NET or ASP.NET Core).
But as the HTTP GET Delete method usually is used to show the user the elements to delete and prompt the user to confirm the deletion (see this ASP.NET Core tutorial), you maybe want to add a dedicated view for it.
The solution to the problem I was facing was to actually perform the the actions of the Delete Post inside of the Get Delete method, because of using one view for both Creation, Editing, and Deleting.
The end result looked like this:
public ActionResult Delete(int? id)
{
***code goes here****
var lansing = db.LansingMileages.Find(id);
viewModel.Records = new[]
{
lansing
};
db.LansingMileages.Remove(lansing);
db.SaveChanges();
return RedirectToAction("Index");
}

Razor form not passing back to controller method

I am trying to pass a textbox's text back to a method in my controller, but the data is not being passed in the parameter
I am genuinely confused, i'm following another example but i'm getting a different result, ie - my method behaving as if no parameter is passed
Code
public ActionResult Index(string searchString)
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
var listOfAnimals = db.Animals.ToList();
if (!String.IsNullOrEmpty(searchString))
{
listOfAnimals = listOfAnimals.Where(a => a.AnimalName.ToLower().Contains(searchString.ToLower())).ToList();
}
return View(listOfAnimals);
}
and here is my razor form from my view page
#using(Html.BeginForm("Index", "Home"))
{
#Html.TextBox("searchString")
<input type="submit" id="Index" value="Index" />
}
Can anybody spot why this isn't working?
If more code is needed, please let me know but i think the issue is isolated to here
You code is correct.
Since you didn't add [HttpGet] or [HttpPost] before index method.
This method was called twice.
The first call ran when producing the page with form via url http://server/Home/Index. This call was an http get and searchString mapped from URL was null, which is correct.
The second call ran when you clicked submit button. Correct value would be mapped by MVC correctly.
You need to have 2 Index actions (two methods), one without decorations (GET verb) and another one decorated with HttpPost (POST verb). Basically, when you go to the index page, the GET action is executed. When you submit the form, a POST request is executed and the Index decorated with HttpPost is executed.
// GET
public ActionResult Index() { ... }
// POST
[HttpPost]
public ActionResult Index(string searchString) { ... }
Francisco Goldenstein wrote the recommended way. It means you can have two Index() actions:
// for GET
public ActionResult Index() { ... }
// for POST
[HttpPost]
public ActionResult Index(string searchString) { ... }
However it is possible to have one Index() method for handling both (GET and POST) requests:
public ActionResult Index(string searchString = "")
{
if(!string.IsNullOrEmpty(searchString)
{ /* apply filter rule here */ }
}
You wrote, your code is not working. Do you mean, your action method is not requested after click on the button? Consider to allow empty value Index(string searchString = "")
If your action method is fired but variable is empty, check the name on the View() side. Textbox must not be disabled, of course.

Unable to call Post ActionResult from View

I am trying to make a POST request from my View by calling an ActionResult in my Controller. Basically there are a list of events in the view and the user can view the details of the event by clicking the event. This part works. However, once they view the details they also have the ability to sign up for the event. This is the part which is not working.
A sample action I'm trying from the view:
#Html.ActionLink("SignUp", "SignUp", new {id = "2"}, null)
This should access this action result:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SignUp(int id)
{
if (ModelState.IsValid)
{
var registratie = new Registratie(User.Identity.GetUserId(), id);
_db.Registraties.Add(registratie);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View("Index");
}
However, I am getting a 404 error. I think it can't find the actionresult?
The details action result is on the same page however and that works:
// GET: /EventPlanner/Details/5
public ActionResult Details(int id)
{
var evenement = _db.Evenementen.Single(e => e.ID == id);
return View(evenement);
}
I don't understand why the signup gives a 404. Any ideas?
You cant use ActionLink for making POST request. You have following alternatives.
Use submit button to post form
Use Ajax.ActionLink()
Use jQuery.ajax.
I would recommend submit button because I feel it is simpler than the rest.
As an example for first approach. Try this
Razor:
#using (#Html.BeginForm("ActionName", "ControllerName"))
{
<input type="hidden" name="id" value="2" />
<input type="submit" value="Post" />
}
Controller:
public class ControllerNameController : Controller
{
[HttpPost]
public ActionResult ActionName(string id)
{
//Your stuff
return View();
}
}
Its because your Detail Action method is a Get method while your SignUp Action method is decorated with [HttpPost] attribute, which means its a Post method. Remove HttpPost from your action method and it will run.
Edit:
For your purpose, I would recommend you use approaches #Lmadoddin Ibn Alauddin
suggested.
You can put your data under form tag and submit it using submit button(I don't recommend by looking at your code and you have not posted HTML too').
Or:
You can make $.ajax() call with type: 'POST' and pass your data like data: {id: 'idvalue'}.
Hope this will help you. Let me know if you face any problem.

How should I setup Registration controller action?

I am fairly new to MVC and i'm looking for advice on how to setup a particular registration controller.
I have a controller called AccountController which has a Register method and I have a Register.cshtml.
Now, one of the biggest problems I seem stuck on is that I have 2 dropdowns that I need to populate based on the response from a service as these values change depending on location and other various parameters.
I have my page started and loading but I'm not sure what to do once a user click 'register'.
#model Adw.Models.RegisterModel //This is my model
#Html.DropDownListFor(m => m.States, new SelectList(Model.States)); // I load my dropdowns here
[AllowAnonymous]
public ActionResult Register(RegisterModel model)
{
model.States = Services.GetStates().Payload;
model.Countries = Services.GetCountries().Payload;
return View(model);
}
So my question is, when a user submits the form, should it come back to this same method? If so what would be the best way to validate that this is a submit rather than an initial load?
Also i haven't done much in the way of error handling and could use a suggestion on that, such as if either of the above service calls fail, then a registration cannot be completed, should that direct to a new page or is there a easy way to build that kind of error into the same page?
You should create two different method. One for GET and second for POST request:
[AllowAnonymous]
[HttpGet]
public ActionResult Register()
{
...
}
[AllowAnonymous]
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// create user
return this.RedirectToAction("SignIn");
}
else
{
return View(model);
}
}
You can review sample from default template.

Categories