I have publish a new website where the website.pt/contact page is now at the website.pt#contact-us - how can change my actual controller's action to reflect this change?
public ActionResult Contact()
{
return View(); -> Index#contact-us
}
#contact-us is a URL location hash and has nothing to do with a View. Instead, try to redirect to that specific URL hash with return Redirect("website.pt#contact-us").
I have form that a user submits. For some reason, in our production environment when they click submit, the form is cleared and they lose all that they filled in when they click submit. I've been lost on this for awhile so any input would really help.
I've tried on multiple browsers and this occurs on each one (Chrome, Safari).
The first action creates the view model for the form, the second one takes that data/model and submits an application:
[Authorize(Roles = "Applicant")]
public IActionResult Application()
{
var vm = _applicantManager.GetApplicationViewModel(CurrentUser.UserName);
return View(vm);
}
[HttpPost]
//[ValidateAntiForgeryToken]
[Authorize(Roles = "Applicant")]
public IActionResult Application(ApplicationViewModel model)
{
var saved = false;
model = _applicantManager.RebuildApplicationViewModel(model);
if (ModelState.IsValid)
{
saved = _applicantManager.SubmitApplication(model, CurrentUser.UserName);
return RedirectToAction("Index");
}
return View(model);
}
I'm thinking if I remove the ValidateAntiForgeryToken that maybe this would solve issue, but am not sure.
Is it possible that the first action needs a route? On testing, it goes to the action with the HttpPost attribute when I click submit on my local environment.
Note: This is a problem on the production server, this does not occur on the local. This leads me to believe that may a possible IIS setting that needs changed?
JavaScript on the Page:
<script>
require(['jquery', 'jqueryui'], function($, jqueryui) {
$(function() {
$("#preHealthAreaDiv input:radio").click(function () {
var selectedVal = $("#preHealthAreaDiv input:radio:checked").val();
if (selectedVal == "Yes") {
$("#preHealthAreaDetail").show();
}
else {
$("#preHealthAreaDetail").hide();
}
})
});
});
</script>
I am building an MVC 5 application and have come to the following problem: I want to show a menu item to the user, after the user has logged in, if the user has an Agreement with me.
I want to set a session variable at the moment the user logs in like:
Session["HasAgreement"] = Agreement.HasAgreement(userId);
and then in my _Layout.cshtml file where I build my menu do something like:
#if (Session["HasAgreement"] == "True")
{
<li>#Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
My problem arises in the AccountController where I have added the logic to the standard Login Action:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
var userId = User.Identity.GetUserId();
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
This is the standard MVC 5 login - except that I have added the two lines right after the "case SignInStatus.Success:" where I try to get the userId and then set the Session variable.
My problem is that at this point in thime the User is not authenticated(I thought that happened in the SignInManager above).
How do I set the session variable right after the user logs in?
The new session isn't set until you hit the next action. This is a common issue with trying to use the result for anything other than redirection. The best course of action would be to use the result to redirect to another action, in which you will then be able to access the session.
Assuming when your user logs in they go to a "dashboard", it might look something like:
SignInStatus.Success case:
case SignInStatus.Success:
return RedirectToAction("Dashboard");
If you require the ability to return to numerous actions, you can return the action name instead of a url and simply do RedirectToAction(returnAction). Obviously if you need to specify a controller as well, you'll need to post a returnController too.
Dashboard action:
[Authorize]
public ActionResult Dashboard() {
var userId = User.Identity.GetUserId();
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return View();
}
I'm not sure where your Agreement object is coming from but you have access to the User property in the View so you could potentially do something like this:
_Layout.cshtml
#if (Agreement.HasAgreement(User.Identity.GetUserId()))
{
<li>#Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
this also assumes that HasAgreement returns a bool which if it doesn't, it really should.
Your problem is not when you update the session variable, but what version of the session your layout page has got.
session isn't the best option for passing data between views. try ViewBag
(although you should always try to use a ViewModel where possible!)
(and you can use the session AS WELL, for the next page load)
This might not work in all cases, but I found the easiest way to set a session variable at Login was to move the logic to the controller action returned by RedirectToLocal(). In my case I made a new post-login entry point to the application called "Main", that has it's own view/controller.
On login the user is always redirected here first, so it guarantees my Session data gets set.
First I changed RedirectToLocal() in the AccountController:
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
//This is the template default
//return RedirectToAction("Index", "Home");
//This is my new entry point.
return RedirectToAction("Index", "Main"); }
Inside my MainController I can access the User object and set my data:
// GET: Main
public ActionResult Index()
{
ApplicationUser sessionuser = db.Users.Find(User.Identity.GetUserId());
Session.Add("UserName", sessionuser.UserName);
return View();
}
And for good measure I'm wiping the session data on logoff:
public ActionResult LogOff()
{
Session.RemoveAll(); //Clear all session variables
//...
}
As an option:
Add new partial view - call it Agreement.
#model bool
#if (Model)
{
<li>#Html.ActionLink("Agreement", "Agreement", "Home")</li>
}
Add new action to your, say, Account controller, call it Agreement
public PartialViewResult Agreement(){
var userId = User.Identity.GetUserId();
bool hasAgreement = Agreement.HasAgreement(userId); // This will be your model
return PartialView("Agreement", hasAgreement);
}
And in your layout do:
#Html.RenderAction("Agreement", "Account")
I have the exact same issue and appear to be using the same version of Identity as you (the OP). I tried what you did (prior to finding this) as well as followed Sippy's advice and put it in RedirectToLocal ActionResult in the AccountController (which didn't work):
In the meantime, I put it in the Global.Asax.cs under:
public void Profile_OnMigrateAnonymous(object sender, ProfileMigrateEventArgs args)
{
...//other code (or not) on migrate anonymous user to authenticated
Session["HasAgreement"] = Agreement.HasAgreement(userId);
}
I also created this void in my Global.asax.cs (catches expired sessions but still logged in):
void Session_Start(object sender, EventArgs e)
{
Session["HasAgreement"] = Agreement.HasAgreement(userId);
}
It works and also updates if the session expires. However, one of the downsides of this is that the session variable will not be updated when a user Logs Off (via Identity). However, I also tried putting my client extension in the LogOff ActionResult after AuthenticationManager.SignOut(); and it doesn't work.
I need my session variable to update after Log Off too, so this won't be my final solution, but it may be good enough for you?
I'll come back and update this if I find a better way, but right now, it's good enough and going on my TODO list.
UPDATE:
To catch the user's logoff event, I used Sippy's idea and changed my LogOff ActionResult in the AccountController to this:
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
return RedirectToAction("SetSessionVariables", "Account");
}
[AllowAnonymous]
public ActionResult SetSessionVariables()
{
Session["HasAgreement"] = Agreement.HasAgreement(userId);
return RedirectToAction("Index", "Home");
}
I think this encompasses all logon/logoff/session scenarios. I might see if I can incorporate what I did for the LogOff into the Logon successful redirect (more so to see when the user is actually "authenticated" than anything).
You can use user Claims to extend Identity data.
Implementation for instance here: How to extend available properties of User.Identity
I'm working with ASP.net and MVC3 . I need to show a popup or go to the login page When the session get expired. Can any one please tell me How to redirect to login page which is having action name as "index" and the controller name as "Home".
My Code is:
This method is in my model.In this model I have to redirect to login page.
protected Product GetCurrentCorp(HttpContextBase context)
{
if (context.Session != null)
{
var selectedProduct = context.Session["SelectedProduct"];
if (selectedProduct != null)
{
var product= selectedProduct as Product;
return product;
}
}
// Here I need to redirect to index page(login page)
throw new ArgumentException("Product is not set, Cannot Continue.");
}
If LoggedOn is your Action and Account is your Controller then you can write your code as:
return RedirectToAction("LoggedOn", "Account");
Hope this will help you.!!!
Use
Redirect
or RedirectToAction
or RedirectToRoute
Also refer old post ASP.Net MVC Redirect To A Different View
This is the self contained action that is showing you examples of redirection to different action or URL.
public ActionResult MyAction()
{
// Use this for action, can also be used to redirect
// to action on different controller by adding parameter
return RedirectToAction("MyActionName");
// Use this for URL
return Redirect("http://example.com/foo/bar");
}
Hope this is of help to you.
You can use RedirectToAction()
return RedirectToAction("ActionName", "ControllerName");
I'm trying to utilize the MVC3 model validation in my project as of current, however I want to have a simple login section to show in the layout at all times if the user is not logged in. I have the majority of code in place, however the only thing I'm stuck on is how I can post the model back to the form for any validation messages that I produce and need to return.
Normally something like this will work:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginModel)
{
if(ModelState.IsValid())
{
//Run Further checks & functions
//Upon successful login, retuns to somewhere (Just site index in this example)
return RedirectToAction("Index", "Site");
}
return View(model);
}
Now obviously this won't work as I can't return View(model); on the partial unless I just want the login form to be displayed, however I want it to post back to the page that I have been editing from. For example: I navigate to a certain page, contact us, and want to login now. I enter my details on the form that is always available and I enter my details. An error occurs (Incorrect password, incorrect login, account doesn't exist etc...) and I should be brought back to the contact page with the form still filled in with the details that I entered (except obviously password) with validation summary working etc...
Also, any forms on the page that the layout has rendered still need to work correctly (with models etc)
I'm open to suggestions on how to get this working by other means of submission/return however it would be ideal to have the MVC model validation working.
If anyone needs me to elaborate on anything said, feel free to comment. I'll be actively responding for a while.
you should create a partial view for login and instead of using "#Html.BeginForm" use #Html.AjaxBegin which submit your page by Ajax call and it RenderHtmlString of login view.
for e.g
public ActionResult Login(LoginModel)
{
if(ModelState.IsValid())
{
//Run Further checks & functions
//Upon successful login, retuns to somewhere (Just site index in this example)
return RedirectToAction("Index", "Site");
}
return RenderPartialViewToString("Login",model);
}
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
after adding "RenderPartialViewToString" method which will return you "RenderHtmlString" of your partial view. you must be pass viewName and Model as parameter to this Method.
in your partail View.
<div id="targetId">
</div>
#using(Ajax.BeginForm("Login",new AjaxOptions{ HttpMethod="POST", UpdateTargetId="targetId"}))
{
<input type="submit" value="save" />
}
Note: you must be pass UpdateTargetId there your result will Append.
See this question: How do I pass value to MVC3 master page ( _layout)?
There are complete guide what to do to pass your model to layout