MVC Post method not taking any information from get method?? - c#

I have an extremely confusing case. I currently have the following code
//get method
public ActionResult EmailValidation(string email, string token)
{
EmailValidationViewModel model = new EmailValidationViewModel();
model.email = email;
model.token = token;
Member existingMember = workflow.GetMemberByEmail(model.email, vendor.VendorID);
if(existingMember != null)
{
return View();
}
}
[HttpPost]
public ActionResult EmailValidation(EmailValidationViewModel model)
{
}
Now the above code, which I have already tested on a different page, loads the information in the model to the post method automatically. I believe there is a problem with the new view with the code I posted below that is inhibiting it from taking the information from the get method and sending it to the post method.
I believe it has something to do with the following code?
[[Form_Start]]
<form action="/Mobile/Home/EmailValidation" id="EmailValidation" method="post" data-transition="slideup">
[[/Form_Start]]
if you guys might know why it returns the view with the data from the get method in one controller, but it doesnt in the next, please let me know. In addition if you require more information, also just tell me and I'll try to provide you with as much code as possible. Thanks !

This:
if(existingMember != null)
{
return View();
}
is returning a View with no Model.
Change it to this:
if(existingMember != null)
{
return View(existingMember);
}

Related

How can I make a return with parameters in a View c# asp .net mvc?

Sorry for the title, but don't know how to explain it. (.NET ASP MVC)
So what I'm trying is to create a payment request via TripleA API(redirect on their page), if the payment is successful, they will redirect on my success page with some parameters, how can I handle those parameters?
What I've tried:
public IActionResult ErrorPage(string payment_reference, string status)
{
return View(payment_reference,status);
}
https://developers.triple-a.io/docs/triplea-api-doc/dd286311a5afc-make-a-payment-request
(scroll down to success_url for more info)
To expand on Steve's comment, create a record (less code than a class) as follows...
public record ErrorViewModel(string PaymentReference, string Status);
...then use this when you send data to the view...
public IActionResult ErrorPage(string payment_reference, string status)
{
return View(new ErrorViewModel(payment_reference,status));
}
You'll need to update your view to have the following line at the top...
#model ErrorViewModel
That should be all you need.
Based on the documentation, you expect a request like this,
https://www.myshop.com/payment-success?status=paid&payment_reference=ASDDF...&order_currency=USD&order_amount=10
And you translate that into a controller method,
[HttpGet("payment-success")]
public IActionResult ResultPage(string payment_reference, string status, string order_currency, decimal order_amount)
{
var result = new ResultViewModel(payment_reference,status, order_currency, order_amount);
return View(result);
}
I also noticed that the doc says,
Note: This field is required if integrating using External URL Payment Form. For other integrations, either insert the field with a url, or remove the field completely.
So if you use External URL Payment Form integration, then I don't think you will be able to get the status and reference.
The same applies for cancel_url.

Model emptied after returning view

I'm new to ASP and programing in general, so I'm probably doing something fundamentally wrong but here it goes:
Everytime I return a View in my controller the model that I was using in that controller gets emptied. example:
Account acc;
public ActionResult Index()
{
acc = new Account(accountName, password);
return View(acc)
} //At this point there still is a acc object
public ActionResult Edit(string name, string pass)
{
//Here the acc object is null
acc.userName = name;
acc.password = pass;
}
My question would how to acces the account that is currently being used or a way to save the model that was send with de View()
Edit 1
When I tried using TempDate I still encounterd the same problem:
Account acc;
public ActionResult Index()
{
acc = new Account(accountName, password);
TempDate["account"] = acc;
return View(TempDate["account"])
} //TempDate contains 1 object
public ActionResult Edit(string name, string pass)
{
//TempData is empty here
TempDate["account"].userName = name;
TempDate["account"].password = pass;
Return View("Index", TempDate["account"]);
}
Your initial observation when trying to reference acc across two requests happened because ASP.NET creates a new instance of a controller for every request. The GET for Index is one HTTP request; the GET for Edit is a separate HTTP request.
Regarding your first edit to the question, TempData is only valid during the lifetime of a single request. You'll get the same result using it in this scenario. Instead, you should use Session as described in this answer.
The duplicate suggest by Eugene is quite good if you want to try something like Cookie or Session (TempData in MVC)
If you want to store the data on application level you can maintain a collection in static class which can store the data for as long as you want.
You can maintain application level variable also for example Does asp.net MVC have Application variables?

AspNetCore MVC - return RedirectToAction is getting ignored

I have an action as below:
[HttpGet]
public IActionResult SendEmailVerificationCode(int userId)
{
SpaceUser user = userManager.FindByIdAsync(userId).Result;
bool taskComleted = SendEmailVerificationLink(userId).IsCompleted;
if (taskComleted)
{
AddToErrorData(InfoMessages.EmailVerificationLinkSent_Params, user.Email);
return RedirectToAction(nameof(HomeController.Index), "Home");
}
else
{
return RedirectToAction("EmailNotConfirmed", new { userId = user.Id });
}
}
When I make the code jump into the else block (when debugging) it makes the redirection to EmailNotConfirmed action, which is in the same controller. But it doesn't redirect to HomeController's Index action. Instead, the browser stays at Account/SendEmailVerificationCode and displays a blank page.
HomeController.Index is as below:
[HttpGet]
public IActionResult Index()
{
return View();
}
I tried these:
In the beginning SendEmailVerificationCode action was async but HomeController.Index wasn't. So I declared them both as async.
Then I deleted the async declaration from both of them.
I tried return RedirectToAction("Index", "Home");.
SendEmailVerificationCode had HttpPost attribute; I changed it to HttpGet.
How can I make the redirection to an action in a different Controller?
Any help would be appreciated.
P.S.: I have been doing research about this issue for a while now and I've read the solutions for questions such as:
MVC RedirectToAction is not working properly
RedirectToAction gets ignored
But none of these or the questions regarding the action not being redirected after an ajax request have helped me.
Thanks.
I figured the problem by adding some logging into the application. It turns out that the actual problem was being hidden.
I was using TempData to store the customized error messages and I was utilizing it via the AddToErrorData function I had displayed in the question.
In AspNetCore, Serializable attribute has disappeared along with ISerializable interface. Therefore, TempData was unable to serialize my custom IList object list.
When I changed the TempData[ConstantParameters.ErrorData] = _errorData; to TempData[ConstantParameters.ErrorData] = JsonConvert.SerializeObject(_errorData); the redirection problem was solved.
For reference: I also had to change the TempData retrieving line as: _errorData = JsonConvert.DeserializeObject<ErrorDataList>(TempData[ConstantParameters.ErrorData].ToString());

Return to second to last URL in MVC (return View with previous filter conditions applied)?

I'm working on an MVC5 application. On the home screen is a grid allowing users to view Data and be transferred to a number of Views for various actions on each record. One of these is an [EDIT].
The issue I'm encountering is as follows: due to the amount of data it is convenient to Filter the data down (say to a specific location) and then Edit records from there. The filter on this grid (Grid.MVC from CodePlex) performs filtering partially by modifying the URL (http://homeURL/?grid-filter=Location.DEPT__1__accounting) such as 1 being Equals, 2 being Cotains, 3 being StartsWith, and 4 being EndsWith and then after the next 2 underscores being the search criteria.
This functions fine, however upon [POST] return from the Edit the user currently is returned to main Index view without the filtering criteria still set (forcing them to go in over and over and add filtering criteria before performing the similar EDIT on records of the same criteria).
My POST-EDIT method is currently setup to include:
if (ModelState.IsValid)
{
collection.MODIFIED_DATE = DateTime.Now;
collection.MODIFIED_BY = System.Environment.UserName;
db.Entry(collection).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index", "Home");
}
For my attempts I had first thought to return the View with the updated collection (return View(collection)) but this of course just takes me back to the EDIT view, not the home view with the data grid filtered down as previously specified. I considered adding a field in the database, something like LAST_FILTERED_URL, but this just feels like an overgrown band-aid.
Does anyone know of a clean way to go about this?
EDIT:
I had thought to do something similar to Andrea's suggestion early on, but had not thought of doing an explicit redirect with the Parameter of the url-filter passed in the Redirect. Below is my current code for the GET/POST Edit:
// GET: ENITTY_Collection/Edit/5
public async Task<ActionResult> Edit(int id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ENTITY_COLLECTION entity_Collection = await db.ENTITY_COLLECTION.FindAsync(id);
if (entity_Collection == null)
{
return HttpNotFound();
}
// Other code for Controls on the View
return View(entity_Collection);
}
// POST: ENTITY_Collection/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Id,One_Id,Two_Id,Three_Id,Four_Id,Five_Id,Six_Id,field7,field8,field9,...field18,created_date,created_by,modified_date,modified_by")] ENTITY_COLLECTION entity_Collection)
{
if (ModelState.IsValid)
{
entity_Collection.MODIFIED_DATE = DateTime.Now;
entity_Collection.MODIFIED_BY = System.Environment.UserName;
db.Entry(entity_Collection).State = EntityState.Modified;
await db.SaveChangesAsync();
//return RedirectToAction("Index", "Home");
return View(entity_Collection);
}
// Other code for if Model is Invalid before returning to View.
return View(entity_Collection);
}
I like Andrea's suggestion, but I still need a good way to store the URL the user has when they first navigate to the GET-Edit View, and then use that filtered URL value to return the user to that previous location & filter option when the POST-Edit completes and changes have saved.
Any thoughts?
I'm not sure if this is the most correct way of going about what I'm after, but what appears to be working for me is the use of a Session value.
In my GET method I store the URL:
Session["returnURL"] = Request.UrlReferrer.AbsoluteUri;
Then in my POST I use this value in a Redirect() after saving changes to the record:
var returnURL = (Session["returnURL"] != null) ? Session["returnURL"].ToString() : Url.Action("Index", "Home");
return Redirect(returnURL);
So far all initial testing is resulting in a return to the main view with all sorting/filtering criteria in place before the record was entered into for update.
Have you tried changing passing the current filter to redirect to action as follows?
Note: I am assuming that:
you are redirecting to the same controller
you have a controller parameter called currentFilterValue
RedirectToAction("Index", "Home",new { grid-filter = currentFilterValue });
The default LoginController for an MVC project from Microsoft includes a bunch of methods that use a returnUrl parameter. Using this practice, you could include a return URL when opening the editor, that when editing is done, returns the user back to the prior screen with the filters intact (assuming they are in the URL).
My base class for view models has a property for storing the ReturnURL, which is then stored as a hidden if set.
#Html.HiddenFor(model => model.ReturnUrl)
My action that posts from edit then has this logic:
if (viewModel.ReturnUrl.IsNotNullOrEmptyTrimmed())
{
return RedirectToLocal(viewModel.ReturnUrl, "ActionName", "ControllerName");
}
else
{
// Default hard coded redirect
}
In order to prevent some injections, you will want a validation method (called above) like this for ensuring the URL is valid:
protected ActionResult RedirectToLocal(string returnUrl, string defaultAction, string defaultController)
{
try
{
if (returnUrl.IsNullOrEmptyTrimmed())
return RedirectToAction(defaultAction, defaultController);
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
Uri returnUri = new Uri(returnUrl);
if (Url.IsLocalUrl(returnUri.AbsolutePath))
{
return Redirect(returnUrl);
}
}
catch
{
}
return RedirectToAction(defaultAction, defaultController);
}
Hopefully this gets you some ideas and on the right track.

Asp.Net Mvc - Don't clear error input in form

When I validate a form with Asp.Net Mvc and there's an error on the form, Asp.Net return me the form with the correct error message but clear the content of the input. I would like the content of the input to stay even if this content is wrong. How can I do that ?
UPDATE
Maybe this is because I don't use the default validation. I use the Fluent Validation library.
Here what I do :
var validator = new UserValidator();
var results = validator.Validate(user);
results.AddToModelState(ModelState, "");
if (!ModelState.IsValid)
{
return View("SignUp", user);
}
The problem might be in how you "bind" the model you are passing in the view. If you use a strongly typed view and create the input fields with for example
<%=Html.TexboxFor(m=>m.UserName)%>
or
<%=Html.TextBox("UserName", Model.UserName)%>
then you should see the values after posting.
Regards
In addition to what #Germán Ubillos posted, you can also store the post values in TempData and send them back through.
<%=Html.TextBox("UserName", TempData["UserName"])%>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SomeAction(string UserName)
{
TempData["UserName"] = UserName;
// Do your validation
var validator = new UserValidator();
var results = validator.Validate(user);
results.AddToModelState(ModelState, "");
if (!ModelState.IsValid)
{
return View("SignUp", user);
}
//return some view
}

Categories

Resources