Asp.Net Core MVC How to transfer ModelState via RediretToAction? - asp.net-core-mvc

I want to redirect my signIn Post methode back to the index page (Index Page has login and register form on in) but with the modelstate so i can show the errors if the sign in failed.
I have Read multiple articles about this but they either are outdate or not for asp.net core. I can't find a solution. I have tried to store the ViewData or ModelState in TempData but that doesn't work.
[AllowAnonymous]
[HttpGet]
public IActionResult Index()
{
//How to access have the modelstate from SignIn here?
return View();
}
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Index(SignInModel model)
{
if (ModelState.IsValid)
{
....
return RedirectToAction("","");
}
// here i need to save the modelstate
return RedirectToAction(nameof(Index));
}

Don't try to pass ModelState as it is, ASP.NET will override it. But you can pass anything else. You index method has to support the state as a parameter:
public IActionResult Index(bool? IsValidAuth = null)
{
if(IsValidAuth!=true) {} // do something
}
Then you can pass the state in the second parameter of RedirectToAction:
public async Task<IActionResult> Index(SignInModel model)
{
// ...
return RedirectToAction(nameof(Index), new {IsValidAuth = false});
}

You can store your ModelState Validation error on TempData and will able to get it on your login method to show this error

you have to inject signmanager as service in configure to login
var result = await signInManager.PasswordSignInAsync(
model.Email, model.Password, model.RememberMe, true);
This will handel the user sign process through your application.

Related

How to get action from which have been redirected?

Is there a way to get the name of the action from which I have been redirected inside a controller in ASP.NET MVC3? (By the way, without saving the name of the action in TempData nor Session)
how about like this
public ActionResult getAction(string FromActionName){
if(!string.IsEmptyOrNull(FromActionName)){
//Do something with the action name
}else{
//Do nothing
}
return View();
}
and the post action looks like
[HttpPost]
public ActionResult postAction(Model _model){
//some processing
return RedirectToAction("getAction",new{FromActionName="postAction"});
}

MVC3: PRG Pattern with Search Filters on Action Method

I have a controller with an Index method that has several optional parameters for filtering results that are returned to the view.
public ActionResult Index(string searchString, string location, string status) {
...
product = repository.GetProducts(string searchString, string location, string status);
return View(product);
}
I would like to implement the PRG Pattern like below but I'm not sure how to go about it.
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
return RedirectToAction(); // Not sure how to handle the redirect
}
return View(model);
}
My understanding is that you should not use this pattern if:
You do not need to use this pattern unless you have actually stored some data (I'm not)
You would not use this pattern to avoid the "Are you sure you want to resubmit" message from IE when refreshing the page (guilty)
Should I be trying to use this pattern? If so, how would I go about this?
Thanks!
PRG Stands for Post-Redirect-Get. that means when you post some data to the server back, you should redirect to a GET Action.
Why do we need to do this ?
Imagine you have Form where you enter the customer registration information and clicking on submit where it posts to an HttpPost action method. You are reading the data from the Form and Saving it to a database and you are not doing the redirect. Instead you are staying on the same page. Now if you refresh your browser ( just press F5 button) The browser will again do a similar form posting and your HttpPost Action method will again do the same thing. ie; It will save the same form data again. This is a problem. To avoid this problem, We use PRG pattern.
In PRG, You click on submit and The HttpPost Action method will save your data (or whatever it has to do) and Then do a Redirect to a Get Request. So the browser will send a Get Request to that Action
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
[HttpPost]
public ActionResult SaveCustemer(string name,string age)
{
//Save the customer here
return RedirectToAction("CustomerList");
}
The above code will save data and the redirect to the Customer List action method. So your browser url will be now http://yourdomain/yourcontroller/CustomerList. Now if you refresh the browser. IT will not save the duplicate data. it will simply load the CustomerList page.
In your search Action method, You dont need to do a Redirect to a Get Action. You have the search results in the products variable. Just Pass that to the required view to show the results. You dont need to worry about duplicate form posting . So you are good with that.
[HttpPost]
public ActionResult Index(ViewModel model) {
if (ModelState.IsValid) {
var products = repository.GetProducts(model);
return View(products)
}
return View(model);
}
A redirect is just an ActionResult that is another action. So if you had an action called SearchResults you would simply say
return RedirectToAction("SearchResults");
If the action is in another controller...
return RedirectToAction("SearchResults", "ControllerName");
With parameter...
return RedirectToAction("SearchResults", "ControllerName", new { parameterName = model.PropertyName });
Update
It occurred to me that you might also want the option to send a complex object to the next action, in which case you have limited options, TempData is the preferred method
Using your method
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
TempData["Product"] = product;
return RedirectToAction("NextAction");
}
return View(model);
}
public ActionResult NextAction() {
var model = new Product();
if(TempData["Product"] != null)
model = (Product)TempData["Product"];
Return View(model);
}

How do I redirect a user (who is already logged in) with the incorrect role to view a page?

I want to send users who have the incorrect role to another page, however when I use:
return RedirectToAction("Index", "Home");
I get the error:
Cannot implicitly convert type 'System.Web.Mvc.RedirectToRouteResult' to 'System.Web.Mvc.ViewResult'
Is this error because I am in an http GET instead of an http POST?
Here is my code as it is:
public ViewResult Index()
{
if (User.IsInRole("Administrator") | User.IsInRole("SuperAdministrator"))
{
//Do Admin Things
return View()
}
else
{
// Send to a different page
return RedirectToAction("Index", "Home"); // I want to do this, but it gives me an error
}
How do I redirect a user based on their role in this situation?
Change your method to return ActionResult instead of ViewResult. The latter expects that you will be returning View(), whereas the former is a base type that will allow any type of ActionResult object, such as those returned by RedirectToAction and View
public ActionResult Index(){
}
instead of
public ViewResult Index(){
}

Using modelstate.isvalid to validate data from inside the controller in MVC3

I am pretty new to ASP.NET MVC3 but i have about 4 years of experience with PHP frameworks.
I am trying to build an MVC3 web app, but i am having issues with validationg my model.
Here is a test controller to show you what i am trying without success to do.
I am trying to pass a value to my model inside the controller, but it doesnt take it into account the parameter.
I tried using modelstate.setmodelvalue, for junk.sentence, but it keeps the value from the POST request which is invalid an that i want to change by default (for test purposes) in the controller.
Can anyone help?
Thanks in advance.
Michael
[HttpPost]
public ActionResult Create(Junk junk)
{
//ModelState.Clear();
junk.sentence = "coucou";
ModelState.SetModelValue("sentence", new ValueProviderResult(junk.sentence, junk.number, null));
//ModelState
if (ModelState.IsValid)
{
db.Junks.Add(junk);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(junk);
}
//
// GET: /Junk/Edit/5
public ActionResult Edit(int id)
{
Junk junk = db.Junks.Find(id);
return View(junk);
}
Try removing it from modelstate:
[HttpPost]
public ActionResult Create(Junk junk)
{
junk.sentence = "coucou";
//ModelState
if (ModelState.IsValid)
{
db.Junks.Add(junk);
db.SaveChanges();
return RedirectToAction("Index");
}
ModelState.Remove("sentence");
return View(junk);
}
This assumes that in your view you have a corresponding input field that was generated using some of the Html helpers such as EditorFor for example:
#Html.EditorFor(x => x.sentence)
or:
#Html.TextBoxFor(x => x.sentence)
ModelState.IsValid returns false when there are model errors added to the model state. MVC validates the properties on your model and creates a list of errors for you in the ModelState. You must remove the errors from the model state that you wish to be ignored from inside your controller action. You can then update the actual values on the model. (Darin Dimitrov shows you an example of doing this)

How do I perform error handling in ASP.NET MVC 3 controller?

I have an Account controller which have:
LoginForm (get action)
Login (post action)
RegisterForm (get action)
Register (post action)
In another controller's index action i use render them as:
Html.RenderAction("RegistrationForm", "Acount");
Html.RenderAction("LoginForm ", "Acount");
Everything works ok and I can register a new user, login and validate with unobtrusive validation.
The problem is when do some back-end validation in Register/Login action and if there is an error I don't know how to transfer the error to be rendered.
I've tried with PRG pattern and it works ok. I get the error displayed on the form with the preserved data, but PRG is not the way to do it.
What is an alternative solution to this problem without using ajax to validate or move those methods in the controller where the RegistrationForm/LoginForms are used?
I want to skip using TempData due to session usage in the background.
EDIT CODE SAMPLE:
class AccountController : SomeBaseController{
[HttpGet]
public PartialViewResult RegistrationForm()
{
return PartialView(new RegisterUser());
}
[HttpPost]
public ActionResult RegisterUser(RegisterUser user)
{
if (ModelState.IsValid)
{
var _user;// create domain user from Register user Model;
var _validationOutput = _userService.DoSomeAwsomeServerSideValidation(_user);// do some custom validation
if (_validationOutput.IsFault)
{
// we preseve tempdata in base controller OnActionExecuted
_validationOutput.ErrorMessages.ForEach(x => ModelState.AddModelError(_validationOutput.ErrorCode, _validationOutput));
// redirect to home controller custom error occured
return RedirectToAction("Index", "Home", user);
}
return RedirectToAction("RegistrationInfo");
}
return RedirectToAction("SomeUserInfoAction");
}
}
class HomeController : SomeBaseController {
Index(){
return View();
}}
HomeControllerMarkup {
#{Html.RenderAction("RegistrationForm", "Acount");}
#{Html.RenderAction("LoginForm", "Acount");}
}
You can manually add errors to your ModelState within your post controller using:
ModelState.AddModelError("", #"You didn't perform task XYZ");
You should then be able to return the view and display the errors in a validation summary:
#Html.ValidationSummary(false, "Login was unsuccessful because...")

Resources