How to display message through ViewBag? - c#

I need to display success msg when user registered. below i attached code. that code not displaying success msg. whats wrong. please help. (This is Asp.net core MVC web application)
[HttpPost]
public ActionResult Register(UserAccount user)
{
if (ModelState.IsValid)
{
_context.UserAccounts.Add(user);
_context.SaveChanges();
ModelState.Clear();
ViewBag.Message = "Successfully Registration Done";
}
return View();
}

Anywhere in your HTML page you can use the viewbag.
Example:
<h4>#ViewBag.Message</h4>

You shouldn't be using ViewBag at all for this. Use TempData instead and follow the PRG (post-redirect-get) pattern.
[HttpPost]
public ActionResult Register(UserAccount user)
{
if (ModelState.IsValid)
{
_context.UserAccounts.Add(user);
_context.SaveChanges();
TempData["Message"] = "Successfully Registration Done";
return RedirectToAction("Foo");
}
return View();
}
On success, you need to redirect the user somewhere else. It makes no sense to return them to the registration form, after they've already registered, and it solves the issue of having to clear the model state. You use TempData to store the message, so it persists through the next request. Then, in your view:
#TempData["Message"]
Where you want it to display.

Related

How to send a text message or a link from controller to view?

I have got a submit button for a form, this controller actionresult method gets called when the button is pressed. Depending on the return of the _shortUrlProcessor.CreateShortURL method. I want to either display a message in red or a create a link under the mentioned submit button. What is the proper way of handling this in MVC? (see comments in code for more clarification as well)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ShortenURL(ShortURLModel model)
{
if(ModelState.IsValid)
{
if(_shortUrlProcessor.CreateShortURL(model.originalURL, model.shortURL))
{
ViewBag.ShortenURLSuccess(model.shortURL); //< ---- send as a localhost:port/model.shortURL link
}
else
{
ViewBag.ShortenURLSuccess("Could not create link"); //<----send as a text label (which would be shown in something like a <div/>)
}
}
return View();
}
Putting this in the view is the way to go, and here is an example using the viewbag approach:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ShortenURL(ShortURLModel model)
{
if(ModelState.IsValid)
{
if(_shortUrlProcessor.CreateShortURL(model.originalURL, model.shortURL))
{
ViewBag.ShortenURLSuccess=true;
ViewBag.ShortenURL=model.shortURL;
}
else
{
ViewBag.ShortenURLSuccess=false;
}
}
return View();
}
And then in the view:
#if (ViewBag.ShortenURLSuccess)
{
Go here
}
else
{
<div class="error">Could not create link</div>
}
If you need more information for the url or the message, you can put those in viewbag variables as well.
it is worth noting that a more popular way to do this is with model binding, but this approach works fine for what it is. You can use the submitted model and move away from the viewbag to be a bit more efficient.

How to Prevent Validators from Running on HttpGet?

After reading this very helpful answer I modified a pair of methods to allow them both to accept the same view model:
[ActionName("AddressCorrection"), HttpGet]
public IActionResult AddressCorrectionGet(AddressCorrectionViewModel model)
{
return View(model); // was return View();
}
[ActionName("AddressCorrection"), HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddressCorrectionPost(AddressCorrectionViewModel model)
{
if (ModelState.IsValid)
{
return View("Index", new ApplicationViewModel { SuccessMessage = "That worked." });
}
model.ErrorMessage = "Something went wrong";
return View(model);
}
Problem is, calling return View(model); in AddressCorrectionGet now treats the invocation as a POST of sorts. Specifically, the validators on AddressCorrection.cshtml run. Instead of seeing a blank form ready for input, I see a form with a bunch of “required fields missing” messages.
How do I prevent the View from running the validators in this case? Or in the more general case, how does the View know that it should vs. should not run validators (I was thinking this was simply based on whether the Request method was GET vs POST. Clearly wrong.), and how can I explicitly tell the view to run or not run the validators?
Use ModelState.Clear(); before return View(model);

model data disappears between controllers

So i have a model with two models in it so that i can render to different views on the same view, one login view and one register view.
This is my model:
public class SignUpLoginModel
{
public LoginModel loginmodel { get; set; }
public RegisterModel registermodel { get; set; }
}
And when i am trying to register a new user with this controller method:
public ActionResult Register(SignUpLoginModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.registermodel.UserName,
model.registermodel.Password,
new
{
FirstName = model.registermodel.Firstname,
LastName = model.registermodel.Lastname,
Country = model.registermodel.Country,
City = model.registermodel.City,
Birthdate = model.registermodel.Birthdate
});
WebSecurity.Login(model.registermodel.UserName, model.registermodel.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Register", "Home", model);
}
So the modelstate.isvalid failes as it should and it redirects to the home controller and the register method and send the model. Here everything works fine, the model contains the data. But when i redirect to another controller
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", model);
}
my model ends up with null instead of the right data. What am i doing wrong?
I'm pretty sure it's because RedirectToAction (neither the overload you are using nor any of the other signatures) doesn't forward your model for you. It sends a 302 back to your browser which then issues a new GET request to a new url - therefore your model data is lost.
So you'd need to do something like this in the first controller
{
TempData["signupModel"]=model;
return RedirectToAction("Register", "Home", model);
}
and then this in the redirect controller:
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", TempData["signupModel"]);
}
But what I don't understand is why you don't just directly return a view the first time around, why do you need to redirect - because from your code you seem to be just redirecting back to the same controller - or have I missed something?
Edit based on comments below
I honestly think you would be better off using Ajax for this because what you're trying to do here is maintain state across multiple controllers/views which is not really idiomatic for MVC.
If you submit the "register" popup form via Ajax, then you never actually leave the Index page, you just execute some code server-side and return some JSON to indicate if your registration was OK or not. When this response indicates an error you can just display an error message on the popup form or whatever, otherwise you can redirect to wherever on the client-side.
OR
When your Register controller decides that registration has failed, return the Home page index view e.g
ViewBag.Message = "RegisterFail";
return View("~/HomePage/HomeController/Index.cshtml", model); //or whatever the virtual path to the home page view is
However I don't like this approach as it sounds to me like you have your register form HTML being generated in-line by the the Home page view, which sounds like mixed concerns to me.

Call controller from another controller and return a view

I call an Action from a Login controller to authenticate users, once the user is authenticated I would like to call either the Cashier or the Supervisor action, depending on the user's role, and display the appropriate view.
I can break on AuthenticateUserByCard but RedirectToAction doesn't seem to be working.
I'm not sure if what I'm trying to do is deviating from the MVC architecture, if so please suggest the correct way to do this
Login controller:
public class LoginController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult AuthenticateUserByCard(string token)
{
//Authenticate user and redirect to a specific view based on the user role
Role role = GetRoleByToken(token);
if(role.UserType == UserType.Supervisor)
return RedirectToAction("Supervisor", "Login", new { id = token });
else
return RedirectToAction("Cashier", "Login", new { id = token });
return null;
}
public ActionResult Supervisor(string id)
{
//Do some processing and display the Supervisor View
return View();
}
public ActionResult Cashier(string id)
{
//Do some processing and display the Cashier View
return View();
}
}
Java Script:
$.get("/Login/AuthenticateUserByCard",{token:token});
jQuery post and get ignore 301 browser redirects returned from the server. You would normally need to handle them yourself. This can get messy: How to manage a redirect request after a jQuery Ajax call
All you really need in this case is to return the choice of methods, but make them return explicit views (not implicit). The default would always be to return the view based on the IIS-called method i.e. "AuthenticateUserByCard" unless you specify the view.
e.g.
public class LoginController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult AuthenticateUserByCard(string token)
{
//Authenticate user and redirect to a specific view based on the user role
Role role = GetRoleByToken(token);
if(role.UserType == UserType.Supervisor)
return Supervisor(token);
else
return Cashier(token);
return null;
}
public ActionResult Supervisor(string id)
{
//Do some processing and display the Supervisor View
return View("Supervisor");
}
public ActionResult Cashier(string id)
{
//Do some processing and display the Cashier View
return View("Cashier");
}
This will not change the URL though. If you need that too try the other answer I linked. You basically handle the redirect in jQuery and goto the new page.
Alternatively, to change the URL, put the desired URL into a hidden field of the returned views and extract that value to update the browser URL (just a thought) :)

ActionResult for Layout

I am trying to make a login form which is located in Layout itself therefor not in any View. Problem is I dont know how to write an ActionResult for the Layout.
If I put my code in lets say ActionResult Index() then it will only work on Index page. So is there something like ActionResult for Layout itself ?
I would do it like this:
Create a login action to return the specific partial.
public ActionResult Login()
{
if (User.Identity.IsAuthenticated)
{
return PartialView("_loggedInPartial");
}
else
{
return PartialView("_notLoggedInPartial");
}
}
Call it within your layout.cshtml like this:
#Url.Action("Login", "Account");
Update
You could also retrieve the user and return it to the _notLoggedInPartial view to display some user credentials or a welcome message like this:
...
else
{
// User retrieval code from db
return PartialView("_notLoggedInPartial", model);
}
...
People generally won't prefer doing this, but still below is the simplest way to achieve
Create a form(html/ajax) in the layout itself with login fields.
Post it from there to your "login post" action.
using (Html.BeginForm("Login", "Account")){
#Html.TextBox("Username")
#Html.TextBox("Password")
<input type="submit" value="Login">
}
AccoutController must contain an action with below structure.
[HttpPost]
Public ActionResult Login(string Username, string Password)
{
//handle appliaction logic
}

Categories

Resources