RedirectToAction after successful post to show a message - asp.net-mvc

When people register on my ASP.NET MVC website I send an activation link via email so they can activate their account and login. I want to show a message when the registration is successful and the email is sent. To do that I redirect to another page.
I do not want to show this page when people go directly to this URL because it is not a normal page. I use TempData to check if they are coming from the registration page.
public ActionResult Register()
{
AccountRegisterView accountView = InitializeAccountRegisterViewWithIssue(false, "");
return View(accountView);
}
[HttpPost]
public ActionResult Register(AccountRegisterView accountView)
{
if (!ModelState.IsValid)
{
return View(accountView);
}
// Register user and send activation link via email...
TempData["success"] = true;
return RedirectToAction("RegisterEmail");
}
public ActionResult RegisterEmail()
{
if (TempData["success"] != null)
{
return View();
}
return RedirectToAction("Login");
}
I would like to know if this is considered best practice. Or should I do this differently?

I think this is a perfectly good use of TempData[]. You need a variable for a one time request to decide if you should show the page or not.
I suppose you could use a session variable, but you would need to remember to clear the session. You could use some type of registration key, but then you would need to track those as well. Long story short, nope, you are good.

Related

What's the purpose of this SignInManager call when the controller has the [Authorize] attribute?

Having set up a default ASP.Net MVC 5 application, I fail to understand why the below snippet has a call to SignInManager.
This is in the ManageController, which has the [Authorize] attribute.
//
// POST: /Manage/RemoveLogin
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RemoveLogin(string loginProvider, string providerKey)
{
ManageMessageId? message;
var result = await UserManager.Get().RemoveLoginAsync(User.Identity.GetUserId<int>(), new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
var user = await UserManager.Get().FindByIdAsync(User.Identity.GetUserId<int>());
if (user != null)
{
await SignInManager.Get().SignInAsync(user, isPersistent: false, rememberBrowser: false);
}
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return RedirectToAction("ManageLogins", new { Message = message });
}
I am wondering if, whenver I retrieve the authenticated user, I should repeat this step, i.e. check if the user is null and if not, await SignInAsync.
Edit: check if the user is null and if it is, await SignInAsync
Now, I've created a new controller, that I've given the [Authorize] attribute, and in the Index() function of the controller, I do:
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId<int>());
If I load that page in two tabs, sign out in one of them and then refresh the page, I'm redirected to the login screen. I've attached a debugger and have been unable to cause a case where the SignInManager is hit.
In what scenario would the user be not-null?
They do entirely different things. The Authorize attribute checks that the user is authenticated and authorized to access the action (based on role permissions and such). It doesn't authenticate the user. That's what the call to SignInManager is for. It actually authenticates the user, so that the user can then pass checks made by the Authorize attribute.
As for when the user might be null, effectively, if the action is protected by Authorize it probably never will be. It would have to take some strange confluence of events where the user was found in the database in order to sign them in, but then somehow was removed by the time you tried to retrieve it. In other words: not bloody likely. Still, it's good practice to always perform a null-check like this when a value could potentially be null, which user could.

Request.UrlReferrer.ToString() Not reload in IE only

I'm trying to redirect page on previous page when i click on currency menu. In this menu set selected currency in cookies and redirect to Request.UrlReferrer.ToString() so Request page automatic read cookies and apply currency.
Here is my code
public ActionResult Index(string currency)
{
HttpCookie cookie = new HttpCookie("Cookie");
cookie.Values["CODE"] = currency;
cookie.Values["sym"] = Currencies[currency];
cookie.Values["Name"] = CurrenciesName[currency];
string currencyname = GetCurrencySymbol(currency);
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
return Redirect(Request.UrlReferrer.ToString());
//return RedirectToRoute(Request.UrlReferrer.ToString());
}`
for example page1 have some item with amount in USD now user change currency then i send request to CurrencyController with above Action then return to same page1.
Above code working fine in all browsers but not working in IE 11.
give me some idea where I'm doing wrong.
Thanks
First and foremost, you should never rely on UrlReferrer. Its value comes from an HTTP header that is not guaranteed to be sent, and even if it is sent, it can be tampered with. By using it in the way you are, you're opening yourself up to CSRF and man-in-middle attacks.
The correct way to do something like this is to pass along the URL you want to return to. For example, if a user is on a URL like /foo/ and then clicks a link where you want to redirect them back to /foo/ afterwards, then the URL of the link should be something like: /bar/?returnUrl=/foo/.
Then, the action responding to /bar/ would do something like:
public ActionResult Bar(string returnUrl)
{
// do something
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
// redirect to default
}
The Url.IsLocalUrl check is to make sure that the return URL is a path on the current site, again, to prevent malicious attacks.

RedirectToAction is not redirecting at all

i'm using RedirectToAction to redirect after a post to another controller and it's working. so i tried to Redirect to another action in the same controller and it's NOT working too.
public ActionResult finalize(int id)
{
Meeting meeting = db.Meetings.Find(id);
meeting.meetingStatus = "finalized";
db.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Meeting meeting)
{
if (ModelState.IsValid)
{
db.Meetings.Add(meeting);
db.SaveChanges();
// return RedirectToAction("Invitation");
return (RedirectToAction("finalize", new { id = meeting.meetingID}));
}
return View(meeting);
}
you cant make 2 redirects in the same call , a redirect just return an http redirect code to another page , redirecting 2 times just wont work, don't treat action methods like normal methods they are different
for example when you request a page example.com/controller/action
action will be executed and for example it has a return value with RedirectToAction("NotFound")
what will happen in this scenario is
action body will be executed and the return value will send to the client an http header of 302 that says your new destination is /controller/NotFound
so RedirectToAction just return an http code to the client its not calling another method
Update
i was wrong i checked with fiddler2 , you can use redirect to action many times , what will happen the server will send multiple http redirect headers for each one
i jumped to conclusion this fast because i didnt think multiple redirect is the right way to do it, so after i tried it , i can say it works , just create a new project to see where is the problem exactly or use a tool like fiddler2

TempData & Redirect for Errors

I have a controller action in my project that has a situation where it needs to display an error message to the user under certain scenarios. This action occurs in a POST:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition )
return RedirectToAction("SomeActionError");
return RedirectToAction("Index");
}
public ActionResult SomeActionError() {
return View();
}
Currently I have it set up so that it will redirect to an error controller action. I'm not really fond of this approach because in the URL they see /SomeActionError and it also means that the user can directly navigate to this URL.
Is it a bad design/approach to put some flag in TempData and redirect to another controller that checks for the TempData error flag?
Example:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
TempData["DoSomeActionError"] = true;
}
return RedirectToAction("Index");
}
public ActionResult Index() {
// check for error
if( TempData["DoSomeActionError"] ) {
return View("SomeActionError");
}
}
Is this a bad idea? Is there another approach that does something similar (doesn't allow the user to directly navigate to the error action)? I don't want to return the View on the POST action because I don't want them to refresh and cause another POST.
TempData is not per se a bad concept. TempData is for transporting an information to some consumer that reads that information and the information should vanish after it's been read.
The way your're using TempData is odd. A more elegant implementation for your requirements (you should show an error message) is to implement an equivalent to the rails flash concept and don't redirect to an error page but display an error message in your index view. Something like a red banner that says "The record could not be saved".
This question shows a nice flash implementation including the view stuff (not the accepted answer but the answer by #jim)
using tempdata in mvc is not a good approach.
If i were you i'll do as following:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
return RedirectToAction("Index", new{error=true}
}
return RedirectToAction("Index");
}
public ActionResult Index(bool? error) {
// check for error
if(error?? false ) {
return View("SomeActionError");
}
}
While I don't agree TempData is always bad (I find it great for status messages I absolutely don't want passed on the url such as "record saved", I think in your case there may be a better option.
First you don't want an error page to be accessible - may I ask why?
To do a redirect when an error happens only to redirect again is a bit odd. I would throw the exception and handle that exception by your error view. MVC automatically adds the [HandleError] attribute as a global filter, so throw your exception (a custom type if necessary) and handle it in your error page as you see fit since you can access exception details there and it doesn't require a redirect.

asp.net mvc, wrong function being fired. - EDITED

I have master page that has this control that accepts Post verb. My LogOn page is also tied to the master page. When I enter wrong username/password, method of that control that accepts verb also gets fired along with the method to accept username password.
This is on HomeConroller:
[ActionName("ControlTemp"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult ControlTemp(TempClass temp)
{
return PartialView("ControlTemp");
}
This is on AccountController:
[AcceptVerbs(HttpVerbs.Post)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
Now, why do you think things are being posted to ControlTemp too?
EDIT: This is how I am referring to ControlTemp control on masterpage.
<div id = "divControlTemp"> <% Html.RenderAction("ControlTemp", "Home"); %></div>
So after watching debugger, I saw it returns View() if username/password is invalid. It then hits the divControlTemp control, but instead of firing
public ActionResult ControlTemp(), it fires
[ActionName("ControlTemp"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult ControlTemp(TempClass temp)
and that is all I can see from the debugger. So my question is why do you think it thinks it is a post? Is it because the reurn View() was called from a method that was accepting Post verb?
If your question is "can a single http requests fire two separate action methods", the answer is no. Unless of course there is a redirect from one action method to the other or one of the methods calls the other directly. If there are redirections, you can see them in the Firebug console.
But frankly, if this was my software, I'd simply fire up the debugger and see what's going wrong. It shouldn't be too difficult to spot the problem this way.

Resources