ASP.NET MVC HttpPost posting null model - c#

Form posts from webpage MakeBooking to FinalBooking to ascertain certain information such as number of guests, so the FinalBooking page can give you enough textboxes to input guest information for all guests required.
When in debug mode, both models in MakeBooking post are populated. After post, in FinalBooking, model is null.
[HttpPost]
public ActionResult MakeBooking(BookingModel model)
{
return RedirectToAction("FinalBooking", "Booking", new { model = model });
}
public ActionResult FinalBooking(BookingModel model)
{
return View(model);
}
Any info would be appreciated.

It should work
return RedirectToAction("FinalBooking", "Booking", model);

You can not pass a model with RedirectToAction like that. you need to use either TempData or Session to transfer the model object between your calls.
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
The below example shows how to transfer data using TempData.
[HttpPost]
public ActionResult MakeBooking(BookingModel model)
{
TempData["TempBookingModel"]=model;
return RedirectToAction("FinalBooking", "Booking");
}
public ActionResult FinalBooking()
{
var model= TempData["TempBookingModel"] as BookingModel;
return View(model);
}
Internally TempData is using Session as the storage mechanism.

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");
}

Does going from one Action method to the other action method clear class variables?

So in the same controller I have a Login Action method like this:
public ActionResult Login()
{
LoginModel model = this.LoginManager.LoadLoginPageData();
this.ForgotPasswordMethod = model.ForgotPasswordMethod;
return View(model);
}
Notice I set a variable there: ForgotPasswordMethod
So now when there on that page if they click on a link, it call another action result in the same controller class like this:
public ActionResult ForgotPassword()
{
if (!string.IsNullOrWhiteSpace(this.ForgotPasswordMethod) && this.ForgotPasswordMethod.Trim().ToUpper() == "TASKS")
return View();
return null; //todo change later.
}
Notice I tried to read the value of ForgotPasswordMethod , but it was NULL but it is NOT null when I am in the Login() method. So what should I do?
ASP.NET MVC was designed to return back to a cleaner, more straightforward web world built on HTTP, which is stateless, meaning that there is no "memory" of what has previously occurred unless you specifically use a technique that ensures otherwise.
As a result, whatever state you set via one ActionResult will no longer be the same state that exists when another ActionResult is invoked.
How do you "fix" this? You have a variety of options, depending on what your needs are:
Render the value to the client and post the value back to your second ActionResult method.
Store the value as a header and check that header.
Store the value in a cookie and check the cookie.
Store the value in session.
Store the value in a database.
Store the value in a static dictionary.
what if you store forgotpasswordmethod in Viewbag like
public ActionResult Login()
{
LoginModel model = this.LoginManager.LoadLoginPageData();
Viewbag.ForgotPasswordMethod = model.ForgotPasswordMethod;
return View(model);
}
then in the link of your page you can pass the value from the ViewBag
<a href=#Url.Action("ForgotPassword", "Name of your Controller", new { methodName = ViewBag.ForgotPasswordMethod })>Forgot Password</a>
Change your forgotpassword to
public ActionResult ForgotPassword(string methodName)
{
if (!string.IsNullOrWhiteSpace(methodName) && methodName.Trim().ToUpper() == "TASKS")
return View();
return null; //todo change later.
}

Remove serialized Model from URL of MVC controller action

Within my Home controller is the Index() action. Within Index() I return the a user object from the database using the currently authenticated user's ID:
return View(db.Users.Find(User.UserId));
That works properly and the URL is simply:
https://localhost:44301/
However elsewhere in the Home controller in a separate action I modify the current user and pass it back into the index view using:
return RedirectToAction("Index", user);
When I do this the URL becomes cluttered with a serialized version of the User model:
https://localhost:44301/Home/Index/4?Name=katrina&Administrator=True&PasswordEncodedHash=1000%3AqzWR8U6poGKshxHDsP%2B5yFhz5AZ01%2Fv1%3ASqCG0SliIpjX0M0jjkQqAf5aunTVS2gx&Tests=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.Test%5D&UserTestAttempts=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.UserTestAttempt%5D&Phones=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.Phone%5D
I imagine I doing something dumb with the way I am redirecting the action however I cannot figure out how to fix this. I have tried adding a custom route but the "?Name=...." still gets appended to that.
(Edit) Code from that other action:
public ActionResult ToggleAdministrator()
{
if (Request.IsAuthenticated)
{
var user = db.Users.Find(User.UserId);
user.Administrator = !user.Administrator;
db.SaveChanges();
Response.Cookies.Add(cookie);
return RedirectToAction("Index", user);
}
return RedirectToAction("Index", (User)null);
}
I think you don't need to pass whole data while redirecting to some action using RedirectToAction.
Suppose you have an action Index in Home controller.
Public ActionResult Index(int id)
{
-- write the code here to fetch data based on that id
-- like
var user = db.Users.FirstOrDefault(x=>x.Id = id);
return View(user);
}
Now for this you just need to use redirect to action like below:
return RedirectToAction("Index", new { Id= 5 });
Note:
Never pass a complex type object in QueryString or in GET requests

Post method that calls another one for returning the view

In an MVC4 project I need to "refresh" the page depending on some messages that can be present, otherwise I just redirect to a page, and if presenting again the page if them messages are present I would like to avoid just returning the View as it will cause then the double submission when the user tries to refresh it.
What I'm trying to do is this
[HttpGet]
public ActionResult SampleMethod()
{
viewModel = _builder.Build();
return View(viewModel);
}
[HttpPost]
public void SampleMethod(SampleViewModel viewModel)
{
if (ModelState.IsValid)
{
var response = serviceCall;
var errorMessages = response.ErrorMessages;
if (!errorMessages.Any())
{
//Redirect to proper view
}
else
vm = _builder.Build();
}
else vm = _builder.Build(); //There is some validation error I rebuild
CashbackOffersConfirmation(vm);
}
public ActionResult SampleMethodConfirmation(SampleViewModel viewModel)
{
return View("SampleMethod", viewModel);
}
It goes through the process
but the final page is .../SampleMethod instead of .../SampleMethodConfirmation and is blank,
Is this something to do with the routing (quite lost in this)? Is this a correct approach?
Thanks
In order to pass the object model from the view to the controller, you need to make a post request. Make sure you use a form that will generate the post request.
Also make the SampleMethodConfirmation method a post.
E.g.: add [HttpPost] on top of the method in the controller

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