Best way to store lookup variables?

J

john_c

I'd like to store information for roles in Session variables. RoleA
has a specific set of values, RoleB has a specific set and so one.
When I access values for RoleA, it looks like this:

Session[Utils.RoleA_MBcount] = "30"
Session[Utils.RoleA_BandwidthLimit] = "1000"
Session[Utils.RoleA_FeatureBcountLimit] = "5"
Session[Utils.RoleA_FeatureCcountLimit] = "10"

and similar for the other roles. Those values are initially loaded
from a database. Each role is actually a purchased plan. Similar to
various hosting plans that give you more the more you pay. Once the
roles are initialized into Session variables, I just access the
Session variable to check user limits.

Each of the above properties in Utils is a static string reference.
They're just nice ways to give me intellisense and avoid hard coding
strings everywhere. The problem is that I'll have to hit the Utils.cs
file everytime I want to use these lookup values. If there are four
roles and each one has 10 properties that could be a lot of hits
(especially with more roles) depending on how grouped the lookups are
through out the app.

Is this a concern or is there a better way?

Thanks,
John
 
M

Mark Rae

The problem is that I'll have to hit the Utils.cs file everytime I want to
use these lookup values.

In fact, you don't... The Utils.cs file, like all your other C# code files,
is compiled up into your web app's DLL when you rebuild the app, which is
loaded into memory when the app starts...
Is this a concern or is there a better way?

I wouldn't have thought it was a concern...

As for a better way, that's a little difficult to say... There are certainly
other ways - you could use one of the Collection objects (e.g. ArrayList) or
Generics objects (e.g. Dictionary) if you're using ASP.NET v2, or you could
hold each element separately in Session - if there are any performance
differences, we're probably looking at nanoseconds...
 
J

john_c

In fact, you don't... The Utils.cs file, like all your other C# code files,
is compiled up into your web app's DLL when you rebuild the app, which is
loaded into memory when the app starts...

You're right Mark. Thanks. I guess the "static" accessor threw me
off. Do these static properties stay in memory for the length of the
user session or app session?
I wouldn't have thought it was a concern...

As for a better way, that's a little difficult to say... There are certainly
other ways - you could use one of the Collection objects (e.g. ArrayList) or
Generics objects (e.g. Dictionary) if you're using ASP.NET v2, or you could
hold each element separately in Session - if there are any performance
differences, we're probably looking at nanoseconds...

I am using ASP.NET 2.0. A collection could be used but I think a
better way is to group each role by static class in the Utils class,
which is also static. This just gives a nice intellisense layout. So
you would have

Session[Utils.Roles.RoleA.MBcount]
Session[Utils.Roles.RoleA.BandwidthLimit]
Session[Utils.Roles.RoleA.FeatureBcountLimit]
Session[Utils.Roles.RoleA.FeatureCcountLimit]
 
J

john_c

Also, there will be corresponding Application cache for each plan.
The user Session values are compared against it. This means the
database only needs to be hit when the app loads and for each new user
(session).
 
M

Mark Fitzpatrick

John,
Do you really need it as a session variable? Will it be the same
values for each session? If so then you're going to end up with a lot of
useless memory usage. You could put the values into the cache object. You
could do a check every so often, such as when a request starts, and check to
see if the cache is empty. If so then load the object/array/etc. through
some function and put it into the cache. This would give you a good bit of
control as well since you could determine how much time should occur to
cause the items to fall out of the cache.
 
G

Guest

Hi there John and Mark,

You could go even further and create a base page class with properties you
want. this approach gives you possiblity to get already casted and defaulted
values with great support from intelli sense:

-- begin rolebasepage.cs code --

public class RoleBasePage : System.Web.UI.Page
{
public RoleBasePage() : base()
{
}

private RoleAProperties roleA;
public RoleAProperties RoleA
{
get
{
if (this.roleA == null)
this.roleA = new RoleAProperties(Session);
return this.roleA;
}
}

public sealed class RoleAProperties
{
private System.Web.SessionState.HttpSessionState session;

public RoleAProperties(System.Web.SessionState.HttpSessionState session)
{
if (session == null)
throw new NullReferenceException("session");
this.session = session;
}

public int MBCount
{
get
{
object value = this.session["RoleAMBCount"];
return value == null ? 0 /* default value */ : (int) value;
}
set
{
this.session["RoleAMBCount"] = value;
}
}
}
}
-- end rolebasepage.cs --

-- begin any aspx page code behind --
public partial class MyAnyPage : RoleBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
if (RoleA.MBCount < 10)
{
// do something -
// not enough MB allowance to approve the invoice
// or whatsoever
}
}
}

-- end any aspx page code behind --

Milosz
 
M

Mark Rae

You're right Mark. Thanks. I guess the "static" accessor threw me
off. Do these static properties stay in memory for the length of the
user session or app session?

See the other replies - you need to be *very* careful with statics in
ASP.NET... They can very easily become common across all sessions which,
depending on what they're used for, could be the absolute last thing you
want...
 
J

john_c

No, it doesn't need to be in a session variable. I just need to load
the cache with values for each plan. Then I can check the User object
to find out which role/plan the user is in. From there I have the
values for the plan associated with the user in the Cache and can take
action to display something or not. But how could I cleanly
associate "yes, I know the user's role" with "in the Cache are all of
the values for that role/plan". I need some sort of constuct that
allows me to put those two things together initially. Then when I
need to check the MegaBytes of space a user has, I can just say
User.MBcount or something similar.

Thanks.
 
G

Guest

Yes, but ypu need to code quite a lot and you need to spend some time to
familirize youself with custom proofile providers. i'll perape a simple
example but tomorrow (wed late afternoon CET)

Regards
 
J

john_c

Yes, but ypu need to code quite a lot and you need to spend some time to
familirize youself with custom proofile providers. i'll perape a simple
example but tomorrow (wed late afternoon CET)

Hi Milosz. I'll be looking forward to it.
 
G

Guest

I know i know,

Here's the custom profileprovider class that should be placed in app_code
folder. you also need to amend web.config (that's actual place where you
define all properties)

-- begin MyProfileProvider.cs c# code --


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for MyProfileProvider
/// </summary>
public class MyProfileProvider : System.Web.Profile.ProfileProvider
{
public MyProfileProvider()
: base()
{
}

public override int
DeleteInactiveProfiles(System.Web.Profile.ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
{
throw new Exception("The method or operation is not implemented.");
}

public override int DeleteProfiles(string[] usernames)
{
throw new Exception("The method or operation is not implemented.");
}

public override int DeleteProfiles(System.Web.Profile.ProfileInfoCollection
profiles)
{
throw new Exception("The method or operation is not implemented.");
}

public override System.Web.Profile.ProfileInfoCollection
FindInactiveProfilesByUserName(System.Web. Profile.ProfileAuthenticationOption
authenticationOption, string usernameToMatch,
DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int
totalRecords)
{
throw new Exception("The method or operation is not implemented.");
}

public override System.Web.Profile.ProfileInfoCollection
FindProfilesByUserName(System.Web.Profile.ProfileAuthenticationOption
authenticationOption, string usernameToMatch, int pageIndex, int pageSize,
out int totalRecords)
{
throw new Exception("The method or operation is not implemented.");
}

public override System.Web.Profile.ProfileInfoCollection
GetAllInactiveProfiles(System.Web.Profile.ProfileAuthenticationOption
authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int
pageSize, out int totalRecords)
{
throw new Exception("The method or operation is not implemented.");
}

public override System.Web.Profile.ProfileInfoCollection
GetAllProfiles(System.Web.Profile.ProfileAuthenticationOption
authenticationOption, int pageIndex, int pageSize, out int totalRecords)
{
throw new Exception("The method or operation is not implemented.");
}

public override int
GetNumberOfInactiveProfiles(System.Web.Profile.ProfileAuthenticationOption
authenticationOption, DateTime userInactiveSinceDate)
{
throw new Exception("The method or operation is not implemented.");
}

// ApplicationName property is used only if profile data
// depends on application instance - i.e. in case there are many
// applications and the data
public override string ApplicationName
{
get
{
return String.Empty;
}
set
{
}
}

public override SettingsPropertyValueCollection GetPropertyValues(
SettingsContext context, SettingsPropertyCollection collection)
{

System.Web.SessionState.HttpSessionState session =
HttpContext.Current.Session;

SettingsPropertyValueCollection settings =
new SettingsPropertyValueCollection();

foreach (SettingsProperty property in collection)
{
SettingsPropertyValue settingsPropertyValue =
new SettingsPropertyValue(property);

// remember this logic would only work if session
// keys are the same as properties name including grouping

object value = session[property.Name];
// set value for non null PropertyValues only in
// order to force default value defined in the web.config
if (value != null)
{
settingsPropertyValue.PropertyValue = value;
settingsPropertyValue.IsDirty = false;
settingsPropertyValue.SerializedValue = value;
}

settings.Add(settingsPropertyValue);
}

return settings;
}

public override void SetPropertyValues(SettingsContext context,
SettingsPropertyValueCollection collection)
{
System.Web.SessionState.HttpSessionState session =
HttpContext.Current.Session;

if (session == null)
return;

foreach (SettingsPropertyValue settingsPropertyValue in collection)
{
// i assume every sigle property defined for profile is stored in session,
// other wise you have to update session for selected items only

if (settingsPropertyValue.IsDirty)
{
if (settingsPropertyValue.PropertyValue == null)
{
session.Remove(settingsPropertyValue.Name);
}
else
{
session[settingsPropertyValue.Name] =
settingsPropertyValue.PropertyValue;
}
}
}

}
}

-- end code --

-- web.config changes--

<anonymousIdentification enabled="true"/>
<profile enabled="true" defaultProvider="MyProfileProvider"
automaticSaveEnabled="true">
<providers>
<add name="MyProfileProvider" type="MyProfileProvider"/>
</providers>
<properties>
<group name="RoleA">
<add name="MBCount" type="System.Int32" defaultValue="0" readOnly="false"
allowAnonymous="true"/>
</group>
</properties>
</profile>

-- end web.config changes --


-- how to use it on the page --

<asp:Button runat="server" ID="btn" Text="Postback!" />

<script runat="server">

protected void Page_Load(object sender, EventArgs e)
{
// you have to call Profile.Save()
// everytime you change properties to force values
// to be updated in underlying data storage which
// on our case is session. the reason for that is
// very simple - profileprovider.setpropertyvalues
// is called at the final stage of page execution
// after session state is serialized and destroyed
// therefore is not acessible. remember save should
// be called onnce per execution i.e. after you set
// all properties you want.

if (IsPostBack)
{
Profile.RoleA.MBCount++;
Profile.Save();
}
else
{
Profile.RoleA.MBCount = 3;
Profile.Save();
}

Response.Write(Profile.RoleA.MBCount);
}
</script>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top