In my page i have used Session["user_id"] to know the status of user. Is there any page specific property to replace Session["user_id"].
Session is the best place to store user id!
You can wrap user id keeping using next extension method:
as far as Page.User returns IPrincipal then:
public static string UserId (this IPrincipal user)
{
get
{
return HttpContext.Current.State["user_id"];
}
set
{
HttpContext.Current.State["user_id"] = value;
}
}
Usage (inside a web page);
this.Request.User.UserId; // get, set
you can use a query string to store the user id instead of a session, moving it along from page to page.
another option is to use a viewstate, but this is limited per page and does not move along to other pages
Related
I am building an MVC 4 intranet site that I would like to have persistent data with in a footer. I'm going to hold a few basic stats that are unique to each user. I want this data to persist across all pages during a user's visit to the site.
What is the best best way to persist this data? A cookie? It's just a few non-senstive bits of information that will be pulled from AD. I was thinking hidden fields but that seems a bit cumbersome.
Thanks for the insight!
While you could use sessions for this task, I would caution against. Sessions should be avoided as much as possible.
You can use a child action to build the footer, using AD to get the relevant details, and then render this in your layout. If you're concerned about AD being hit every request to render the footer, then just cache the result.
public class FooController : Controller
{
...
[ChildActionOnly]
public ActionResult Footer()
{
// query AD and stuff the info in a view model
return PartialView("_Footer", model);
}
}
Then, in your layout:
#Html.Action("Footer", "Foo")
Of course, you'll need to move your current footer view code into a partial view, named _Footer.cshtml based on this example.
To cache, just prefix the child action with:
[OutputCache(Duration = 3600, VaryByCustom = "User")]
Duration is in seconds, so the above would cache for an hour. And you'll need the following method added in Global.asax:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "User")
{
if (context.Request.IsAuthenticated)
{
return context.User.Identity.Name;
}
return null;
}
return base.GetVaryByCustomString(context, custom);
}
I want to make it possible for user to change his profile details(except UserId,Username and password(password changed in another view))
so in my method when I make it like that
public void SaveUser(UserProfile user)
{
context.Entry(user).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
I get an error Store update, insert, or delete statement affected an unexpected number of rows (0). After that I have surfed the stackoverflow, where someone suggested to make it another way, so i edited my SaveUser method
public void SaveUser(UserProfile user)
{
var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter
)context).ObjectContext;
try
{
objectContext.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
objectContext.Refresh(RefreshMode.ClientWins, context.UserProfiles);
objectContext.SaveChanges();
}
}
after these changes I don't get this error anymore, however my profile details are not changed.
My HttpPost Edit method(HttpGet retrieves correct information)
[HttpPost]
public ActionResult Edit(UserProfile user)
{
if (ModelState.IsValid)
{
repository.SaveUser(user);
return View(user);
}
return View();
}
In my Edit view I have only LabelFor's and EditorFor's for everything(except Id,Username and Password) and Submit button.
Trying to solve that all day long and have not succeeded yet.
Most likely your user's primary key UserId property value is 0 because you don't use the UserId in your view. You are then trying to update an entity with key value 0 that doesn't exist in the database and causes the exception.
Put a hidden form field into your view that carries the user's UserId between client and server back and forth:
#Html.HiddenFor(model => model.UserId)
Normally if you use default routing you should have a route http://www.mysite.com/{controller}/{action}/{id}. If the url is then http://www.mysite.com/User/Edit/3 MVC tries to bind the value 3 to a property with name id (upper or lower case don't matter). Your Update should work then. But I guess your primary key property in User is not Id, but something else - like UserId. In that case the model binder can't find your key property and leaves its value as default (= 0).
Therefore as an alternative to the hidden field you could give the user's key property the name Id or specialize the route to use UserId as parameter.
I am converting a webapp from a frameset layout to Masterpage layout. Each of the pages within the frameset use a common custom class to aquire the logged in user, this custom class inherits from Page.
I thought that an interface would be the proper way to convert this however I was really wrong. What is the best and most efficient means to store a global variable or class so that each content page for the Masterpage can reference the logged in user class?
Make it a simple static class with static method that will return logged user class, there is no need to tie this code with ASP.NET page. If getting the logged on user requires some time vise expensive operations (like DB query for example) store logged user class instance in the session. Something like this :
public static class Users
{
public static User GetLoggedUser()
{
if (HttpContext.Current.Session["LoggedUser"] != null)
{
return (User)HttpContext.Current.Session["LoggedUser"];
}
else
{
User usr = GetLoggedUserSomehow(); // here goes your current code to get user
HttpContext.Current.Session["LoggedUser"] = usr;
return usr;
}
}
}
I dunno whether I described my question well but I'm trying to send some element to other page either with a hyperlink or a Response.Redirect() and it's a key which make some access to the DB so I don't want to send it via url and get it. what should I do? thanks.
You can store it in session, or you could use some type of encoding and pass it in the QueryString.
Another option would be to store the value in ViewState and use Server.Transfer to direct the user to the other page. With Server.Transfer you'll still be able to access the ViewState from the other page like this:
private string ValueFromOtherPage
{
get
{
if (ViewState["value"] != null)
{
return ViewState["value"].ToString();
}
else
{
string value;
if (Context.Handler != null)
{
value = (Context.Handler as PreviousPageName).MyStoredValue;
ViewState["value"] = value;
}
return value;
}
}
}
Take a look at this article for encoding/encrypting the QueryString:
http://www.codeproject.com/KB/web-security/QueryStringEncryptionNET.aspx
You can use session variables to store objects:
Session["VariableName"] = yourObject;
Note that overusing these session variables may lead to memory leaks.
You can save it in a session
You can send a GUID which represent some info (in the QS)
You can use cookies.
The users of my web application may have more than one browser window (or tab) open and pointed to the same page. We're using cookie based session id's, and the user will usually work within the same session id in both browsers/tabs. I would like to be able to uniquely identify which browser window (and tab) that requested an ASP.NET page (in order to make sure, that data stored in the session does not get mixed up).
(e.g. I would be happy if the browser would generate and send a window/tab-id with the http request, as it publishes HTTP_USER_AGENT)
Any ideas?
--thomas
If I was going to implement something like this I would probably start with a Dictionary<Type, List<Guid>> and store this in the users session. I would also probably make this be a custom type that delegates the dictionary and have a factory method that works similar to
public Guid GeneratePageIdentifier(Page thepage)
{
var guid = Guid.New();
if(_dictionary[thepage.GetType()] == null)
_dictionary[thepage.GetType()] = new List<Guid> { guid };
else
((List<Guid>)_dictionary[thepage.GetType()]).Add(guid);
return guid;
}
Then embed the guid that's returned from that method on the VIewState of the page. On your page methods that execute actions that you need to validate which page it is you would be able to validate that guid is inside the collection do something. You might also want to implement a custom a type with a guid property to enscapulate more information about why you're doing this or what you need for it to be meaningful.
The Viewstate on each page will be different, maybe you can use some kind of unique identifier created on every page loaded?
It is by default not possible due to the stateless nature of the web, but you could add a "page identifier" that gets generated with each opened page and transmitted for every action.
I'd recommend that you refactor the application in a way that those mixups can't happen, no matter from which page/tab/window the request originates.
As Mark Redman said, you can use Viewstate + Session in order to store values specific to the page.
ViewState is good for storing the key (string), Session for storing whatever type of complex objects.
Use the ViewState or a hidden field in order to load at the first call a GUID.
public string PageUid
{
get
{
if (ViewState["UID"] == null)
ViewState.Add("UID", Guid.NewGuid().ToString());
return ViewState["UID"].ToString();
}
}
Then use the session to get/set your values using this key:
string MyPagesessionVariable
{
get
{
if (Session["MYVAR" + PageUid] == null)
{
Session["MYVAR" + PageUid] = "VALUE NOT SHARED WITH OTHER TABS/WINDOWS";
}
return Session["MYVAR" + PageUid];
}
set
{
Session["MYVAR" + PageUid] = value;
}
}