asp mvc session variables - asp.net

Need to store some auth information of client on server, to share between 2 pages.
Dont matter how, session, cookie, tempdata, i tried everything, and nothing works, for exampe:
public ActionResult CheckIn(string pass)
{
if (System.Configuration.ConfigurationManager.AppSettings["pass"] == pass)
{
HttpContext.Session.Add("admin", "yes");
}
return View();
}
public ActionResult Helper() {
if (HttpContext.Session["admin"] != null)
{
if (HttpContext.Session["admin"].ToString() == "yes")
return PartialView("InitConfig");
else
return PartialView("StationLogics");
}
else
return PartialView("StationLogics");
}
and i get always null in session in helper method. what i'm doing wrong?

Have you tried HttpContext.Current.Session instead ?
ps. doing that you do is actually not good desing you should reconsider it in your application.

Are you sure that all those if conditions are met? Try with a simple example:
public ActionResult CheckIn()
{
Session["foo"] = "bar";
return View();
}
public ActionResult Helper()
{
var foo = Session["foo"];
if (foo == null)
{
// this won't be null if you called the CheckIn method first
}
return View();
}
Call the CheckIn action first to store a value in the session and then call the Helper action. Unless you have disabled session for this ASP.NET application or cookies in your browser you should get correct value.

Related

ASP.Net Web API Action Result

I'm building an ASP.Net Web API application and i have the following code...
public IHttpActionResult GetCustomers() {
var customers = context.Customers.ToList();
return Ok(customers);
}
I'm using the Ok() method to return customers because i'm using an IHttpActionResult return type.
Now if i have the following method
public void DeleteCustomer(int id) {
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null) {
NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
}
Can I use NotFound() method here when the return type of my ActionMethod is void???
Void does not have a return type. So you can try to call NotFound(), but I'm not sure if this would even compile - Haven't tried. Why don't you just go with an out of the box IHttpActionResult?
public IHttpActionResult DeleteCustomer(int id)
{
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
{
return NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
return Ok(customerInDb);
}
Using IHttpActionResult is the more elegant version. If the id is invalid, you can just safely exit your method and tell the calling client that something went wrong. If everything went well, you're just giving the client a thumbs-up. IF you return your deleted entity or just an empty Ok() should not matter at this point.
Using void may or may not delete the entity in your data storage. The client would never know, because the server would not return any response.

ASP.NET display ModelState.AddModelError

I have this method here, which is a login method and if the username and password is incorrect a ModelError gets added.
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
}
}
return RedirectToAction("Index", "Home");
}
My question is how would I display the ModelError to my View Index.cshtml?
... how would I display the ModelError to my View Index.cshtml?
Showing Error message
I initially made the assumption that you wanted to redirect to the home page (HomeController action Index) based on your call to return RedirectToAction("Index", "Home"); at the bottom of the Login action. Now I am thinking maybe this is a mistake in your flow and you are actually trying to show the error message to the user without redirecting and that you only want to redirect if everything succeeds. IF this is the case then just read this part and skip the rest about how to persist model state across RedirectToAction calls. All you need to do is call View instead of RedirectToAction if there is a failure.
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
}
}
return View(model); // goes back to the login view with the existing model and validation error
// return RedirectToAction("Index", "Home");
}
Login.cshtml include the following somewhere
#Html.ValidationSummary()
Working with RedirectToAction
The reason it is not working is the ViewData, which includes the validation messages, is lost when you execute the RedirectToAction. There are a couple of options for a solution.
Keep either persist the ViewData across the RedirectToAction and then restore it.
Only persist the ModelState and then merge it with the ModelState once the new action specified in the RedirectToAction has executed.
Persist ViewData
In most scenarios this works just fine but could cause problems if your redirected to action (in this case Index on the HomeController) has its own ViewData that it depends on.
LoginController.cs
// simplified code to just show the relevant parts to reproduce the problem/solution
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
// ... some other code
ModelState.AddModelError("", "The user name or password provided is incorrect");
// ... some other code
if (!ModelState.IsValid)
TempData["ViewData"] = ViewData;
return RedirectToAction("Index", "Home");
}
HomeController.cs
public ActionResult Index()
{
if (TempData["ViewData"] != null)
{
// restore the ViewData
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
return View();
}
Home\Index.cshtml
#Html.ValidationSummary()
Merge the ModelState
This is would be my recommended approach because you define how you want this to happen once on a custom ActionFilter attribute and then apply where you want it to occur. You could also put this code directly into your controller but that would violate the DRY principle as soon as you need to do this on multiple controllers.
The approach here is to write the model state to the TempData if the TempData does not already contain a "ModelState" key. If there is already a key present that means that the current request has just written to it and we can read from it and merge that with our existing model state. This will prevent the code from unintentionally overwriting the ViewState or the ModelState as the ModelState is now merged. I can only see this going wrong if there are multiple RedirectToActions that all choose to write to the ModelState but I do not think this is a likely scenario.
ModelStateMergeFilterAttribute.cs
public class ModelStateMergeFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// write to the temp data if there is modelstate BUT there is no tempdata key
// this will allow it to be merged later on redirect
if (filterContext.Controller.TempData["ModelState"] == null && filterContext.Controller.ViewData.ModelState != null)
{
filterContext.Controller.TempData["ModelState"] = filterContext.Controller.ViewData.ModelState;
}
// if there is tempdata (from the previous action) AND its not the same instance as the current model state THEN merge it with the current model
else if (filterContext.Controller.TempData["ModelState"] != null && !filterContext.Controller.ViewData.ModelState.Equals(filterContext.Controller.TempData["ModelState"]))
{
filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
}
base.OnActionExecuted(filterContext);
}
}
LoginController.cs
// simplified the code to just show the relevant parts
[HttpPost]
[ModelStateMergeFilter]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
return RedirectToAction("Index", "Home");
}
HomeController.cs
[ModelStateMergeFilter]
public ActionResult Index()
{
return View();
}
Home\Index.cshtml
#Html.ValidationSummary()
References
Here are some references that also detail some of these approaches. I also relied on some of the input from these previous answers for my answer above.
How do I maintain ModelState errors when using RedirectToAction?
How can I maintain ModelState with RedirectToAction?
If your are using MVC, you can use Validation Summary.
#Html.ValidationSummary();
https://msdn.microsoft.com/en-CA/library/dd5c6s6h%28v=vs.71%29.aspx
Also,pass your model back to your view:
return RedirectToAction("Index", "Home", model);

How to deserialize

How to deserialize Task response using Json .
public HttpResponseMessage Put(int id, ModelClass modelbject)
{
if (ModelState.IsValid && id == modelbject.modelbjectID)
{
db.Entry(modelbject).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method. How can i achieve ?
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method.
You don't have to "deserialize" anything. The method returns an HttpResponseMessage, which has the property you're looking for.
var result = yourController.Put(someId, someObject);
var success = result.IsSuccessStatusCode;
Perhaps the fact that this is a web application is adding some confusion to how you're picturing it. But if you have a class which directly calls this method, then what you get back is simply an HttpResponseMessage object. Which can be inspected just like any other object. No actual web layer is involved in that interaction.

About Response.Redirect, FormsAuthentication and MVC

I want to understand the difference in the behavior of a program when we call FormsAuthentication.RedirectFromLoginPage vs. when we call Response.Redirect(FormsAuthentication.GetRedirectUrl()) and manually redirect.
Please see the comments below.
I have a LoginController/Index (two actions, one for HttpGet and one for HttpPost). The View of this controller represents the application's login page.
I also have a home page or landing page, i.e. the page that the user must be taken to after a successful login. This is represented in my application by the HomeController's Index action and the ~Views/Home/Index.cshtml view.
I have presented three scenarios. I understand scenario 1 and I expect it to work the way it does, but I noted a difference in scenarios 2 and 3.
Scenario 1
namespace Controllers
{
[AllowAnonymous]
public class LoginController : Controller
{
[HttpPost]
public ActionResult Index(Login loginViewModel)
{
if (ModelState.IsValid)
{
var user = ValidateUser(loginViewModel);
if (user != null)
{
// Other stuff: set cookies, session state, etc.
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "Invalid password. Please try again.");
}
}
// If the user was a valid user, the flow-of-control won't reach here
// as expected and the user will be taken to the view that is served
// by the HomeController::Index() action. If it is by convention, it will
// be the ~Views/Home/Index.cshtml view. This is fine.
return View();
}
}
}
Scenario 2
namespace Controllers
{
[AllowAnonymous]
public class LoginController : Controller
{
[HttpPost]
public ActionResult Index(Login loginViewModel)
{
if (ModelState.IsValid)
{
var user = ValidateUser(loginViewModel);
if (user != null)
{
// Other stuff: set cookies, session state, etc.
Response.Redirect(FormsAuthentication.GetRedirectUrl(loginViewModel.UserName,
loginViewModel.RememberMe));
}
else
{
ModelState.AddModelError("", "Invalid password. Please try again.");
}
}
// If the user was a valid user, the flow-of-control still reaches here
// as expected. And as expected, it renders the same View, i.e. the View
// associated with the controller we are in, which is ~Views/Login/Index,
// which represents the login page. This is wrong. I shouldn't redirect here.
// I understand this. My question here is two fold:
// 1) I am simply trying to understand the difference in behaviors of the three
// scenarios described in this question.
// 2) Given this, the right way would be to not use Response.Redirect here but instead
// use RedirectToAction. However, if I wanted to use Response.Redirect, what should
// I do?
return View();
}
}
}
Scenario 3
namespace Controllers
{
[AllowAnonymous]
public class LoginController : Controller
{
[HttpPost]
public ActionResult Index(Login loginViewModel)
{
if (ModelState.IsValid)
{
var user = ValidateUser(loginViewModel);
if (user != null)
{
// Other stuff: set cookies, session state, etc.
FormsAuthentication.RedirectFromLoginPage(loginViewModel.UserName,
loginViewModel.RememberMe);
}
else
{
ModelState.AddModelError("", "Invalid password. Please try again.");
}
}
// If the user was a valid user, the flow-of-control still reaches here
// as expected. However, magically, somehow, even though the statement below
// suggests that the user must be taken to the View of the same controller and
// action that we are currently in, i.e. the View of the LoginController::Index()
// action, i.e. the ~Views/Login/Index.cshtml, it magically takes me to the
// ~Views/Home/Index.cshtml instead, which is what is specified as the LoginPage
// attribute of the <authentication>/<forms> element in the web.config.
// I want to know how this happens.
return View();
}
}
}
Update
I am at my wit's end now. Now, even Scenario 1 that uses RedirectToAction is calling the Index() action on the LoginController class.
The actual difference is that FormsAuthentication.RedirectFromLoginPage() sets cookies and then makes redirects but FormsAuthentication.GetRedirectUrl() only returns redirect url.
The funny thing is that implementation of FormsAuthentication.GetRedirectUrl() is like this:
public static String GetRedirectUrl(String userName, bool createPersistentCookie)
{
if (userName == null)
return null;
return GetReturnUrl(true);
}
So actually userName and createPersistentCookie parameters are completely ignored. You must call FormsAuthentication.SetAuthCookie( userName, true/false ) manually before calling GetRedirectUrl.
Agree with Vasily.
RedirectFromLoginPage issues an authentication ticket and places it in the default cookie using the SetAuthCookie method.
You can read something about this behavior here.
If you want to have a better control over the cookie creation you should (encryption, expiration, extending the principal) you should create the cookie yourself.
I explained the whole process here and here.

RedirectToAction usage in asp.net mvc

I want to post some questions about ASP.Net MVC. I am not familiar with web developing, But I was assigned to the web part of a project. We are doing the following: first, we create get & set properties for the person data:
public class Person
{
public int personID {get;set;}
public string personName {get;set;}
public string nric {get;set;}
}
and after login, we put the data in a class Person object and we use RedirectToAction like this:
return RedirectToAction("profile","person",new { personID = Person.personID});
It's working normally, but the parameter are shown in the URL. How can I hide them and also
can I hide the action name? Guide me the right way with some examples, please.
The parameter are shown in the URL because that is what the third parameter to RedirectToAction is - the route values.
The default route is {controller}/{action}/{id}
So this code:
return RedirectToAction("profile","person",new { personID = Person.personID});
Will produce the following URL/route:
/Person/Profile/123
If you want a cleaner route, like this (for example):
/people/123
Create a new route:
routes.MapRoute("PersonCleanRoute",
"people/{id}",
new {controller = "Person", action = "Profile"});
And your URL should be clean, like the above.
Alternatively, you may not like to use ID at all, you can use some other unique identifier - like a nickname.
So the URL could be like this:
people/rpm1984
To do that, just change your route:
routes.MapRoute("PersonCleanRoute",
"people/{nickname}",
new {controller = "Person", action = "Profile"});
And your action method:
public ActionResult Profile(string nickname)
{
}
And your RedirectToAction code:
return RedirectToAction("profile","person",new { nickname = Person.nickname});
Is that what your after?
If you don't want the parameter to be shown in the address bar you will need to persist it somewhere on the server between the redirects. A good place to achieve this is TempData. Here's an example:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
And now on the Profile action you are redirecting to fetch it from TempData:
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if (nickname == null)
{
// nickname was not found in TempData.
// this usually means that the user directly
// navigated to /person/profile without passing
// through the other action which would store
// the nickname in TempData
throw new HttpException(404);
}
return View();
}
Under the covers TempData uses Session for storage but it will be automatically evicted after the redirect, so the value could be used only once which is what you need: store, redirect, fetch.
this may be solution of problem when TempData gone after refresh the page :-
when first time you get TempData in action method set it in a ViewData & write check as below:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
now on the Profile action :
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if(nickname !=null)
ViewData["nickname"]=nickname;
if (nickname == null && ViewData["nickname"]==null)
{
throw new HttpException(404);
}
else
{
if(nickname == null)
nickname=ViewData["nickname"];
}
return View();
}
Temp data is capable of handling single subsequent request. Hence, value gone after refresh the page. To mitigate this issue, we can use Session variable also in this case. Try below:
public ActionResult Index(Person _person)
{
Session["personNickName"] = _person.nickName;
return RedirectToAction("profile", "person");
}
And in "profile" actionmethod:
public ActionResult profile()
{
Person nickName=(Person)Session["personNickName"];
if(nickName !=null)
{
//Do the logic with the nickName
}
}

Resources