Best way to store commonly used values - asp.net

In my Webforms 3.5 application, I have a GridView of users that displays the last time they logged in. This value is stored in the Users table in UTC. When an Administrator views the grid, I want them to view it the time zone the Administrator has selected in their preferences (also stored in the Users table).
I have this working properly for the GridView:
<ItemTemplate>
<%# TimeZoneInfo.ConvertTimeFromUtc(Eval("LastLoginDateTimeUTC"), TimeZoneInfo.FindSystemTimeZoneById(UserService.GetUser(HttpContext.Current.User.Identity.Name).DisplayTimeZone))%>
</ItemTemplate>
So in this case, every time a row is created, a user object is created.
What I would like to do is determine the best way to handle returning commonly used User specific data (such as user.DisplayTimeZone). I have several ideas in mind, but I wanted to get some input on how others are doing it. I was looking at using a User Specific Cache, but didn't want to implement until I had more ideas.
I would like to avoid the Session object, but it's not a requirement. I would prefer to use the HttpRuntime.Cache.
Also, once this is determined, where should the code for this go? In a BasePage class? In the MasterPage? In an MVP BasePresenter?
Thanks
~S

I've done the same using a user specific cache as you mentioned. I actually implemented it in a separate namespace though as static get properties. For example:
namespace MyWeb.Session
public static class CurrentUser {
public static int DisplayTimeZone {
get {
// Check cache first.
...
// Cache miss, load from database and store in cache.
...
}
}
}
}
That way every time I needed the value I simply call MyWeb.Session.CurrentUser.DisplayTimeZone.

Related

Business object persistence on postback

Say I have a page in my web application that lets a user update their contact information. Pretend in order to retrieve or save this information I have the following class:
public class User
{
DataAccesClass dataAccesClass = new DataAccesClass()
public string UserName {get;set;}
public string Address {get;set;}
public string EmailAddress {get;set;}
public User(){}
public static User GetUser(int userID)
{
User user = dataAccesClass.GetUser(userID); //
return user;
}
public void Save()
{
dataAccesClass.SaveUser(this);
}
}
Say that on my Page_Load event I create a new instance of my User class (wrapped in a !isPostBack). I then use it's public properties to populate text fields on said page in my web application. Now the question is... When the page is posted back, what is the correct way to rebuild this class to then save the updated information? Because the class was created on Page_Load !isPostBack event it is not available. What is the correct way to handle this? Should I store it in a Session? ViewState? Should I simply rebuild it every post back? The User class in this example is small so that might influence the correct way to do it but I'd like to be able to take the same approach for much larger and more complex classes. Also, would this class be considered an acceptable business object?
what is the correct way to rebuild this class to then save the updated information?
I would say the best practice would be do not rebuild the class on every postback. You should build the data on the first request, set values on controls, then let the viewstate on those controls persist the data.
If there is a potential for the data to need to be updated, tie re-generation of the object to an event indicating there is actual need to update.
Should I store it in a Session? ViewState? Should I simply rebuild it every post back?
Selecting whether to store the value in session or re-pull from the data layer should be based on the memory footprint of the object, the scalability requirements of the application, the costliness of the database operation, and the likelihood that the object will need to be accessed on any particular request. So I believe that is highly situational.
Also, would this class be considered an acceptable business object?
I don't have a lot of experience with BLL's but it looks like you're on the right track.
Unless profiling indicates otherwise, it's okay to just reconstruct the object with every request. You can also implement some kind of caching in your data access code. Your class is an acceptable business object.
Given that User object might have info you wouldn't want to expose through ViewState, it can be stored in Session.
This is the "standard" way of doing this in ASP.NET.
In the case of your example, reconstructing the object looks fine as it is small. But if you have a small object you inevitably store for a while, I would use session. If the object is large, I would directly use database or session with database connection.
Depending how complex you are thinking of getting a JavaScript framework called knockout.js might be a good fit. You could create a json object to bind to a jQuery template that would build the HTML depending on the object, it handles complex objects very well.

ASP.NET - Loading controls at one time (on application load)

We are working on an ASP.NET application. It has 3- 4 forms displaying country list dropdown. Here we would like to avoid binding these dropdowns each time by getting data from database. Instead looking for a better practice of binding it one time, say on application load/some other.
Would you please let me know how we could go head on this? Any reference link or document would be great.
Many Thanks,
Regards,
Nani
Place the drop down in a user control and enable output caching on the user control.
This solution cause the rendered HTML to be cached so the databinding won't need to be called on every page request.
Another possibility would be to use some caching mechanism on your BL logic. For instance in your page/usercontrol you could have (don't take my syntax too strict ;) )
public partial class MyPaged: Page
{
public void PageLoad(..)
{
if(!IsPostBack)
{
dropDownCountries.DataSource = CountryBL.GetCountries();
dropDownCountries.DataBind();
}
...
}
}
and in your business logic class you do some kind of caching where you may have a singleton class that holds the countries and functions as your cache. A pseudocode method could be
public IList<Country> GetCountries
{
//if the cache is empty or it should be refreshed, fills the local
//list of countries, i.e. the cache, with fresh entries from the DB
//there could be some time condition, i.e. refresh every day or so
EnsureCacheValid();
return CachedCountries; //the cache of countries
}
This could be another option with the advantage that your presentation logic doesn't even know about the caching and if you would add a webservice access or so, you would also benefit from the caching. The only thing you have to pay attention at is if there is the possibility that the user can change the countries (which in your example I don't suppose).

Using session like ViewState

I am fixing an ASP.NET application that makes heavy use of session to track per-page data. One of the problems is that the session bleeds between pages.
ViewState would be a better solution, except:
The data is not serializable
There is too much data to be sending back and forth each postback
So I want to:
create a page key for the session data (i.e. stick a random GUID in a hidden field)
expire data from an abandoned page even if the overall session is active
Is there a good way to expire partial session data?
The following temporary storage locations are available:
Session. This follows a user around and uses a cookie. It can be configured to use a URL param to retrieve. Session can also be configured to be stored in process(inproc) on the web server, in SQL Server, or in a state server. InProc can store any data type, but the others require the type to be serializable.
Cache. Data stored in Cache is available to be used by any user in an session. It works similar to session, as the objects are retrievable via a key. One of the nicer features of cache is that you can control how long things are stored, and you can consume event when they expire. You can store anything here, but you may run into issues with using it in a webfarm.
HttpContext. This is scoped to the current request. Remember, requests can be webservice calls, calls to get webpages to get HTML, or calls to a service that returns images. Anything can be stored here.
ViewState. View state is scoped to a page. Must be serializable.
You may want to examine cache. If you're using a webfarm, it won't work, but you could use a GUID of some sort as the key that you map back to a session.
I would probably do it this way:
Create an object to store the state information you want to be page specific. If different pages need different information, create multiple classes.
Store this object in a single session key: Session["PageSpecific"]; for example.
Create a class which inherits from System.Web.UI.Page.
In the OnLoad event of the base class, clear the session key if the the page is not performing a postback.
Create and call an overloadable method to populate the session object.
Instead of inheriting from System.Web.UI.Page in each of your pages, inherit from your new base class.
Something like this (warning: air code. May contain syntax errors):
public class PageBase
: System.Web.UI.Page
{
protected overrides OnInit(System.EventArgs e) {
base.OnInit(e);
if(!this.IsPostBack) {
Guid requestToken = System.Guid.NewGuid();
ViewState["RequestToken"] = requestToken;
Session["PageSpecific" & requestToken.ToString()] = InitializePageSpecificState();
}
}
protected virtual object InitializePageSpecificState() {
return new GenericPageState();
}
//You can use generics to strongly type this, if you want to.
protected object PageSpecificState {
get {
return Session["PageSpecific" & ViewState["RequestToken"].ToString()];
}
}
}
Perhaps on each page !IsPostBack or through a base page you could null out all references to session data not pertaining to that page. This would "expire" the data each time the user goes to another page in the site.
If the user leaves the site or goes in-active, there's not much you can do until the session expires, but in this scenario there would only be one page worth of session data per user.

Data Class in ASP.Net

I am a VB.net winforms programmer attempting to build an ASP.Net app. I use data classes(objects) through reflection in most of my vb projects and was trying to adapt it to ASP.net using the VB code behind. I have a webpage that serves as an add/edit page for contact info. I instatiate my class which grabs the contact data from the data base then I have a process that loops through the controls on the form and matches up with a property in the data class. I can display data no problem. When I edit data and click the submit button my code calls a then loops through the controls on the form again and matches the control to the property of the data class to update the property of the class. However, my data class is no longer valid. I know web programming is different then winforms but I can't seem to get over the hump on this one. Is this the wrong way to go about this? Is my data class only available on the server side? Do I just reinstantiate the initial class and then loop through the propeties and change what the user changed and then call the update method (see redundant)? How can I get data class into a session object (I made an attempt in the past but was under tight deadlines and had to abandon it, maybe I need to revisit it?)?
Thanks
If you decide to keep some of your data in Session, you owe it to yourself to look at this post. Your code will be much cleaner and easier to maintain.
Yes, you need to reload the data class from the database as one option, or use an alternative approach. The reason is web is stateless, so all local variables are destroyed then the server side page unload process occurs. This means that in between requests, you need something to store your data.
You can read/write an object via the Session colleciton, as so:
Session["A"] = myobj;
myobj = (ObjType)Session["A"];
And so session stores an object for a specific user. Alternatively, cache stores application level data, so one instance of an object is available to all users (where session is unique to each user). You can make cache unique to a user by appending a user ID to the cache string.
var o = Cache.Get("A");
if (o != null) { .. }
Cache.Add("A", o, ...);
And so these mechanisms help you temporarily retain data.
You need to save your data class somewhere, usually in a session variable, otherwise it goes away as soon as the page gets sent back the user. Or else you need to recreate the data class again upon posting.

Need to store a static value for the duration of a request. How?

I have an ASP.NET MVC application. I have come to an idea of generating autoincremented values to be used as unique element ids. The question is, how can I have and work with a global variable which should be there for the duration of a request (page generation) but no longer?
I thought of using TempData for this shared variable and then just delete this key when the page is done. But then, where in code to purge this TempData key? Obviously it has to be some very last piece of code where the page has been rendered already.
Any input is highly appreciated.
EDIT: I have a number of HTML helpers that can be called from various views and partial views, so declaring a variable on a page and passing it to each helper is obviously not a good solution. I wish to just use the helpers and know they all are getting unique ids behind the scenes.
Okay, I have googled a little bit and found a solution on ASP.NET forums.
http://forums.asp.net/t/1401685.aspx
Obviously, I can use the HttpContext.Current.Items collection to have my little static variable for the duration of a request.
If all you need is to store a number, the resources that would take to manage its lifestyle would take a lot more than just having a one static integer and always reusing it.
Do not bother deleting the key after each request. Just use a static (I think this is shared in visual basic) integer, use and increment it every time you need a unique value. Also take its mod with a ridiculously high number each time to make sure it will not be reused in a single request and it will never overflow.
Why don't you define your integer variable at the top of the page view file?
Use it throughout the view rendering execution and at the end of it you can easily leave it as is. You don't have to explicitly destroy anything. Your variables live for the duration of request only. IIS is stateless service (if you subtract Session, Cache and Application variables) so it doesn't really remember anything explicitly.
I would imagine you could use the Application_BeginRequest and Application_EndRequest methods in global.asax.cs; Note I can't double check the method names currently, but I think they are close.
You could create a member variable in your controller which would be regenerated for each request:
public class ItemController : Controller
{
private int _UniqueID = 0;
public ActionResult Index()
{
foreach (var item in items)
{
item.UniqueID = _UniqueID++;
}
// etc...
}

Resources