My primary problem is, that I have a code, which is full of method calls to set/get session variables which makes the source hard to read. I am searching for a better/simpler/more elegant solution. I tried operator overload in classes, wrapper classes, implicit type conversion, but I run into problems with all of them.
I would like to handle session variables like regular variables.
After reading a lot of articles, I came up with the following solution which I'd like to make even simpler:
public class SV_string
{
private string key = ""; //to hold the session variable key
public SV_string(string key)
{
this.key = key; // I set the key through the constructor
}
public string val // I use this to avoid using setter/getter functions
{
get
{
return (string)System.Web.HttpContext.Current.Session[key];
}
set
{
System.Web.HttpContext.Current.Session[key] = value;
}
}
}
I use the same key as the variable name:
public static SV_string UserID = new SV_string("UserID");
UserID.val = "Admin"; //Now the value assignment is quite simple
string user = UserID.val; //Getting the data is quite simple too
UserID = "Admin"; //but it would be even simpler
So is there any way to get the desired behaviour?
Thanks in advance!
You can create the following Session Wrapper and just add your methods/properties/members to it
public static class EasySession
{
public static string UserId
{
get
{
return Get<string>();
}
set
{
Set(value);
}
}
public static string OtherVariableA
{
get
{
return Get<string>();
}
set
{
Set(value);
}
}
public static <datatype> OtherVariableB
{
get
{
return Get<datatype>();
}
set
{
Set(value);
}
}
static void Set<T>(T value, [CallerMemberName] string key = "")
{
System.Web.HttpContext.Current.Session[key] = value;
}
static T Get<T>([CallerMemberName] string key = "")
{
return (T)System.Web.HttpContext.Current.Session[key];
}
}
You will then use it as follow
EasySession.UserId = "Admin"
Better yet. If you are using C# 6.0 then you can add the following to your namespaces
using System;
using static xxx.EasySession;
This will then allow you to just call
UserId = "Admin"
Here is how it works
[CallerMemberName] will get the name of what is calling Get or Set In this case it will then bassically be "UserId
eg Set("UserId","Admin")
Then it will go and just do the following
System.Web.HttpContext.Current.Session["UserId"] = "Admin";
(Ref:https://msdn.microsoft.com/en-us/magazine/dn879355.aspx)
Just use a property to wrap your session variable in.
There's no need for other parts of your code to know that its implementation, uses a Session variable or what key name it is stored in:
public string UserId
{
get
{
return (string)System.Web.HttpContext.Current.Session["UserId"];
}
set
{
System.Web.HttpContext.Current.Session["UserId"] = value;
}
}
I would suggest to create an interface with operations (no properties), and one concrete implementation of that interface that actually accesses those variables as session variables in the HTTP context; but also another mocked implementation that you can use in your unit tests; as HTTP context is not available in those cases.
So in your code you program against those interfaces, and the concrete implementation is injected at run-time. When the site is starting, it's the concrete implementation that uses Session; from tests, it's the mocked implementation.
The reason to use operations instead of properties would be to explicitly tell the user that you are not merely accessing normal properties, but session variables, that might have important side effects.
Warning: avoid to use static!!! This will cause undesirable side effects, like shared data between different users.
Related
I have some delegates, two classes and a struct that look kind of like this:
delegate Value Combination(Value A, Value B);
class Environment
{
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment() { ... } //adds one 'Null' type at index 0 by default
public void AddType(string name, getString tostring, Combination[] combos) { ... }
public Value Combine(Value A, Value B)
{
return combinations[A.index][B.index](A, B);
}
public string getStringValue(Value A)
{
return tostrings[A.index](A);
}
public string getTypeString(Value A)
{
return typenames[A.index];
}
}
class Container
{
public string contents
{
get
{
return data.text;
}
}
public string contentType
{
get
{
return data.type;
}
}
private Value data;
public Container(Value val)
{
data = val;
}
public Container CombineContents(Container B)
{
return new Container(data.Combine(B.data))
}
}
struct Value
{
public string type
{
get
{
return environment.getTypeString(this);
}
}
public string text
{
get
{
return environment.getStringValue(this);
}
}
public readonly int type;
public readonly byte[] raw;
public readonly Environment environment;
public Value(int t, byte[] bin, Environment env)
{
type = t;
raw = bin;
environment = env;
}
public Value Combine(Value B)
{
return environment.Combine(this, B)
}
}
The reason for this structure is that Containers can have Values of various types, which combine with each other in user-defined ways according to the current Environment (which, like Container and Value, is differently named so as to avoid conflicting with the System.Environment class in my actual code- I used the name here to concisely imply its function). I cannot get around the problem with subclasses of Value and generic Containers since values of different types still need to be combinable, and neither Container nor the base Value class can know what type of Value combination should return.
It doesn't seem possible to define the Environment class in a global way, as the existing System.Environment class doesn't seem to allow storing delegates as user variables, and giving it a static method returning an instance of itself would render it unmodifiable*, and would require a new instance of the class to be created every time I want to do anything with Values, which seems like it should be a huge performance hit.
This causes two problems for me:
There is an extra reference padding out all my Values. Values are variable in size, but raw is almost always 8 bits or less, so the difference is significant, especially since in actual implementations it will be fairly common to have several million Values and Containers in memory at once.
It is impossible to define a proper 'null' Value, as a Value must have an Environment in it and the Environment must be mutable. This in turn means that Container constructors that do not take a Value as an argument are much more convoluted.
The only other way around this I can think of would be to have a wrapper class (either an extension of Environment or something with an environment as a parameter) which is required in order to work with Containers or Values, which has all extant Containers and Values as members. This would solve the 'null' problem and neaten up the Value class a bit, but adds a huge amount of overhead as described and makes for a really convoluted interface for the end user. Those problems are, with a good deal of work and some changes in program flow, solvable as well, but by that point I'm pretty much writing another programming language which is far more than I should need.
Is there any other workaround for this that I'm missing, or am I mistaken about any of my disqualifying factors above? The only thing I can think of is that the performance hit from the static implementation might be smaller than I think it would be due to cacheing (I cannot perform realistic benchmarking unfortunately- there are too many variables in how this could be used).
*Note that an environment doesn't strictly speaking need to be modifiable- there would be no problem, technically, for example, with something like
class Environment
{
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment(Combination[][] combos, string[] tnames, getString[] getstrings)
{
combinations = combos;
typenames = tnames;
tostrings = getstrings;
}
}
except that this would be much more awkward for the end user, and doesn't actually fix any of the problems I've noted above.
I had a lot of trouble trying to understand exactly what you were trying to achieve here! So apologies if I'm off the mark. Here is a singleton based example that, if I understand the problem correctly, may help you:
public class CombinationDefinition
{
public string Name;
public getString GetString;
public Combination[] Combinations;
}
public static class CurrentEnvironment
{
public static CombinationDefinition[] Combinations = new CombinationDefinition[0];
public static Environment Instance { get { return _instance.Value; } }
static ThreadLocal<Environment> _instance = new ThreadLocal<Environment>(() =>
{
Environment environment = new Environment();
foreach (var combination in Combinations)
environment.AddType(combination.Name, combination.GetString, combination.Combinations);
return environment;
});
public static Value CreateValue(int t, byte[] bin)
{
return new Value(t, bin, Instance);
}
}
Which can be used as:
CurrentEnvironment.Combinations = new CombinationDefinition[]
{
new CombinationDefinition() { Name = "Combination1", GetString = null, Combinations = null },
new CombinationDefinition() { Name = "Combination2", GetString = null, Combinations = null },
};
Value value = CurrentEnvironment.CreateValue(123, null);
string stringValue = CurrentEnvironment.Instance.getStringValue(value);
Important to note - CurrentEnvironment.Combinations must be set before the Environment is used for the first time as accessing the Instance property for the first time will cause the Environment to be instantiated by its ThreadLocal container. This instantiation uses the values in Combinationsto use the existing AddType method to populate the Environment.
You either need to make Environment a "Singleton" (recomended), or mark everything inside it as static. Another possibility is to use an IoC container, but that may be more advanced than you are ready to go for at this point.
The Singleton pattern usually declared a static Instance property that is initialized to a new instance of the class through a private constructor. All access is done through the static Instance property, which will be available globally. You can read more about Singletons in C# here.
static will allow you to access the members without instantiating an instance of the class and it will act as a "global" container.
Singleton Example:
class Environment
{
private static Environment _instance;
public static Environment Instance
{
get
{
if (_instance == null)
{
_instance = new Environment();
}
return _instance;
}
}
private Environment(){}
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment() { ... } //adds one 'Null' type at index 0 by default
public void AddType(string name, getString tostring, Combination[] combos) { ... }
public Value Combine(Value A, Value B)
{
return combinations[A.index][B.index](A, B);
}
public string getStringValue(Value A)
{
return tostrings[A.index](A);
}
public string getTypeString(Value A)
{
return typenames[A.index];
}
}
Example usage:
Environment.Instance.getStringValue(this);
Please excuse any syntax errors in code, I don't have access to Visual Studio at the moment.
If I have a public property that only has a getter, is it correct to use a private variable to assign the value to then return that value or should I just use return rather then setting the value of userID? In the future we plan to add more functionality that will use the userID field, and Methods will be added to this class that use the userID field. Is there any benefit to one way or the other? Is there some other way that this should be done?
private string userID;
public string ID
{
get
{
if (System.Web.HttpContext.Current.Request.Headers.AllKeys.Contains("UID"))
{
userID = System.Web.HttpContext.Current.Request.Headers["UID"].ToString();
}
else
{
userID = "0000";
}
return userID;
}
}
The way the getter is coded right now does not need an assignment, because subsequent calls ignore the value set by previous methods. However, you could cache the result, like this:
private string userID;
public string ID {
get {
if (userID == null) {
if (System.Web.HttpContext.Current.Request.Headers.AllKeys.Contains("UID")) {
userID = System.Web.HttpContext.Current.Request.Headers["UID"].ToString();
} else {
userID = "0000";
}
}
return userID;
}
}
This implementation avoids reading the "UID" repeatedly by caching the result of the initial retrieval in a private instance variable.
You can do this, but I personally would go, in this case, for a function.
The reason is simple:
One when calls a function, expects that some computation may occur inside of it.
Instead when one calls a property, it's not something that he would expect to happen. When you call a property, you think you call some internal field wrapper.
Repeat, what you do is possible to do, but it's not so good from architectual point of view.
So, my suggession, for this case: use a function.
Use return
You are setting userID in the get
So
public string ID
{
get
{
if (System.Web.HttpContext.Current.Request.Headers.AllKeys.Contains("UID"))
{
return System.Web.HttpContext.Current.Request.Headers["UID"].ToString();
}
else
{
return "0000";
}
}
}
In this instance, you are not persisting any data, therefore having a backing field of userID is pointless.
Because you are using public property, you can change implementation anytime. No userID variable is useless, if you will need it in the future you can always add it.
I have just recently got involved in a classic ASP.NET project which contains lots of storing and reading values from the session and query strings. This could look something like the following:
Session["someKey"]=someValue;
And somewhere else in the code the value in the session is read. Clearly this violates the DRY principle since you'll have the literal string key spread out all over the code. One way to avoid this could be to store all keys as constants that could be referenced everywhere there is a need to read and write to the session. But I'm not sure that's the best way to do it. How would you recommend I best handle this so that I don't violate the DRY principle?
Create a separate public class where you can define your constants, e.g
public class SessionVars
{
public const string SOME_KEY = "someKey";
public const string SOME_OTHER_KEY = "someOtherKey";
}
and then anywhere in your code you can access session variables like this:
Session[SessionVars.SOME_KEY]=someValue;
This way you can get IntelliSence and other bells and whistles.
I think you're reading too much into DRY. I pertains more to things that could be wrapped up in a function. I.e. instead of repeating the same fives lines all over the place wrap those 5 lines in a function and call the function everywhere you need it.
What you have as an example is just setting a value in a dictionary (the session object in this case), and that is the simplest way to store and retrieve objects in it.
I can't remember for the life of me where I humbly re-purposed this code from, but it's pretty nice:
using System;
using System.Web;
namespace Project.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key]
= instance
= new T();
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
The idea behind it two fold. The type created should be the only type you need. It's basically a big strongly-typed wrapper. So you have some object you want to keep extending information in:
public class MyClass
{
public MyClass()
public string Blah1 { get; set; }
}
Then down the road you extend MyClass and you don't want to have to remember all the Key Values, store them in AppSettings or Const variables in Static Classes. You simply define what you want to store:
public class MyClassSession : SessionBase<MyClass>
{
}
And anywhere in your program you simply use the class.
// Any Asp.Net method (webforms or mvc)
public void SetValueMethod()
{
MyClassSesssion.Current.Blah1 = "asdf";
}
public string GetValueMethod()
{
return MyClassSession.Current.Blah1;
}
Optionally you could place the access to this session object in a base page and wrap it in a property:
class BasePage : Page
{
...
public string MySessionObject
{
get
{
if(Session["myKey"] == null)
return string.Empty;
return Session["myKey"].ToString();
}
set
{
Session["myKey"] = value;
}
}
...
}
Here you are repeating the myKey string but it is encapsulated into the property. If you want to go to the extreme of avoiding this, create a constant with the key and replace the string.
I have got several classes looking like the one below, and I need to do some checks in the get method and custom set methods. Adding the code in each get and set method makes everything look really messed up.
Is there a way I can override the get and set methods for all properties in an entire class?
public class Test
{
private DataRow _dr;
public Test()
{
_dr = GetData();
}
public string Name
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)] = value;
}
}
public string Description
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)] = value;
}
}
public string DescriptionUrl
{
get { return _dr[MethodBase.GetCurrentMethod().Name.Substring(4)].ToString(); }
set
{
VerifyAccess(MethodBase.GetCurrentMethod().Name.Substring(4), this.GetType().Name);
_dr[MethodBase.GetCurrentMethod().Name.Substring(4)]= value;
}
}
private void VerifyAccess(string propertyname, string classname)
{
//some code to verify that the current user has access to update the property
//Throw exception
}
private DataRow GetData()
{
//Some code to pull the data from the database
}
}
I think what you need is a Proxy on your class, read about Proxy Pattern and Dynamic Proxies
Not directly, there isn't a way to do it with just a compiler. You'd have to generate your entire binary file, then post-process it with some external tool.
This post describes a somewhat similar issue; I hope it helps.
There's a variety of ways to do it.
One would be to create a proxy class (mentioned before), but that would require a lot of refactoring on your behalf.
Another way is with aspects. These do exactly what you're after (insert code based on a pre-requisite.. i.e. all get methods in a class that inherit from x). I ran into a similar problem (actually the exact same problem - checking for security on method calls), and couldn't find cheap/free aspect software that fulfilled my needs.
So, I decided to use Mono-Cecil to inject code before function calls.
If you're interested (it gets a bit messy dealing with IL codes) I can post an old copy of the source
You should extract common code to separate get/set methods, after that you'll be able to add common logic to your properties. By the way, I would do such extraction anyway to avoid copy/paste in the code.
Smth like this:
public string Name
{
get { return GetProperty(MethodBase.GetCurrentMethod()); }
set
{
SetProperty(MethodBase.GetCurrentMethod(), value);
}
}
private string GetProperty(MethodBase method)
{
return _dr[method.Name.Substring(4)].ToString();
}
private void SetProperty(MethodBase method, string value)
{
string methodName = method.Name.Substring(4);
VerifyAccess(methodName , this.GetType().Name);
_dr[methodName] = value;
}
This can be done with indirect value access, e.g. obj.PropA.Value = obj.PropB.Value + 1 -- you can even keep strong typing information. It can be implemented with either attributes or direct-instantiation.
// attribute -- bind later in central spot with annotation application
[MyCustomProp(4)] CustProp<int> Age;
// direct -- explicit binding, could also post-process dynamically
CustProp<int> Age = new CustProp<int>(4, this);
Alternatively, perhaps using a template system such as TT4 may be a viable approach.
However, don't forget "KISS" :-)
I would love for someone to give a better answer for this.
I'm looking for an answer now… best idea I have had would be to define all the properties you want to have be validated as a generic class. For example:
public class Foo {
public String Name {
get{ return _Name.value; }
set{ _Name.value = value; }
}
private Proxy<String> _Name;
static void main(String[] args) {
Foo f = new Foo();
//will go through the logic in Proxy.
f.Name = "test";
String s = f.Name;
}
}
public class Proxy<T> {
public T value {
get {
//logic here
return _this;
} set {
//logic here
_this = value;
}
}
private T _this;
}
What is the best way to check for the existence of a session variable in ASP.NET C#?
I like to use String.IsNullOrEmpty() works for strings and wondered if there was a similar method for Session. Currently the only way I know of is:
var session;
if (Session["variable"] != null)
{
session = Session["variable"].ToString();
}
else
{
session = "set this";
Session["variable"] = session;
}
To follow on from what others have said. I tend to have two layers:
The core layer. This is within a DLL that is added to nearly all web app projects. In this I have a SessionVars class which does the grunt work for Session state getters/setters. It contains code like the following:
public class SessionVar
{
static HttpSessionState Session
{
get
{
if (HttpContext.Current == null)
throw new ApplicationException("No Http Context, No Session to Get!");
return HttpContext.Current.Session;
}
}
public static T Get<T>(string key)
{
if (Session[key] == null)
return default(T);
else
return (T)Session[key];
}
public static void Set<T>(string key, T value)
{
Session[key] = value;
}
}
Note the generics for getting any type.
I then also add Getters/Setters for specific types, especially string since I often prefer to work with string.Empty rather than null for variables presented to Users.
e.g:
public static string GetString(string key)
{
string s = Get<string>(key);
return s == null ? string.Empty : s;
}
public static void SetString(string key, string value)
{
Set<string>(key, value);
}
And so on...
I then create wrappers to abstract that away and bring it up to the application model. For example, if we have customer details:
public class CustomerInfo
{
public string Name
{
get
{
return SessionVar.GetString("CustomerInfo_Name");
}
set
{
SessionVar.SetString("CustomerInfo_Name", value);
}
}
}
You get the idea right? :)
NOTE: Just had a thought when adding a comment to the accepted answer. Always ensure objects are serializable when storing them in Session when using a state server. It can be all too easy to try and save an object using the generics when on web farm and it go boom. I deploy on a web farm at work so added checks to my code in the core layer to see if the object is serializable, another benefit of encapsulating the Session Getters and Setters :)
That is pretty much how you do it. However, there is a shorter syntax you can use.
sSession = (string)Session["variable"] ?? "set this";
This is saying if the session variables is null, set sSession to "set this"
It may make things more elegant to wrap it in a property.
string MySessionVar
{
get{
return Session["MySessionVar"] ?? String.Empty;
}
set{
Session["MySessionVar"] = value;
}
}
then you can treat it as a string.
if( String.IsNullOrEmpty( MySessionVar ) )
{
// do something
}
The 'as' notation in c# 3.0 is very clean. Since all session variables are nullable objects, this lets you grab the value and put it into your own typed variable without worry of throwing an exception. Most objects can be handled this way.
string mySessionVar = Session["mySessionVar"] as string;
My concept is that you should pull your Session variables into local variables and then handle them appropriately. Always assume your Session variables could be null and never cast them into a non-nullable type.
If you need a non-nullable typed variable you can then use TryParse to get that.
int mySessionInt;
if (!int.TryParse(mySessionVar, out mySessionInt)){
// handle the case where your session variable did not parse into the expected type
// e.g. mySessionInt = 0;
}
In my opinion, the easiest way to do this that is clear and easy to read is:
String sVar = (string)(Session["SessionVariable"] ?? "Default Value");
It may not be the most efficient method, since it casts the default string value even in the case of the default (casting a string as string), but if you make it a standard coding practice, you find it works for all data types, and is easily readable.
For example (a totally bogus example, but it shows the point):
DateTime sDateVar = (datetime)(Session["DateValue"] ?? "2010-01-01");
Int NextYear = sDateVar.Year + 1;
String Message = "The Procrastinators Club will open it's doors Jan. 1st, " +
(string)(Session["OpeningDate"] ?? NextYear);
I like the Generics option, but it seems like overkill unless you expect to need this all over the place. The extensions method could be modified to specifically extend the Session object so that it has a "safe" get option like Session.StringIfNull("SessionVar") and Session["SessionVar"] = "myval"; It breaks the simplicity of accessing the variable via Session["SessionVar"], but it is clean code, and still allows validating if null or if string if you need it.
This method also does not assume that the object in the Session variable is a string
if((Session["MySessionVariable"] ?? "").ToString() != "")
//More code for the Code God
So basically replaces the null variable with an empty string before converting it to a string since ToString is part of the Object class
Checking for nothing/Null is the way to do it.
Dealing with object types is not the way to go. Declare a strict type and try to cast the object to the correct type. (And use cast hint or Convert)
private const string SESSION_VAR = "myString";
string sSession;
if (Session[SESSION_VAR] != null)
{
sSession = (string)Session[SESSION_VAR];
}
else
{
sSession = "set this";
Session[SESSION_VAR] = sSession;
}
Sorry for any syntax violations, I am a daily VB'er
Typically I create SessionProxy with strongly typed properties for items in the session. The code that accesses these properties checks for nullity and does the casting to the proper type. The nice thing about this is that all of my session related items are kept in one place. I don't have to worry about using different keys in different parts of the code (and wondering why it doesn't work). And with dependency injection and mocking I can fully test it with unit tests. If follows DRY principles and also lets me define reasonable defaults.
public class SessionProxy
{
private HttpSessionState session; // use dependency injection for testability
public SessionProxy( HttpSessionState session )
{
this.session = session; //might need to throw an exception here if session is null
}
public DateTime LastUpdate
{
get { return this.session["LastUpdate"] != null
? (DateTime)this.session["LastUpdate"]
: DateTime.MinValue; }
set { this.session["LastUpdate"] = value; }
}
public string UserLastName
{
get { return (string)this.session["UserLastName"]; }
set { this.session["UserLastName"] = value; }
}
}
I also like to wrap session variables in properties. The setters here are trivial, but I like to write the get methods so they have only one exit point. To do that I usually check for null and set it to a default value before returning the value of the session variable.
Something like this:
string Name
{
get
{
if(Session["Name"] == Null)
Session["Name"] = "Default value";
return (string)Session["Name"];
}
set { Session["Name"] = value; }
}
}
in this way it can be checked whether such a key is available
if (Session.Dictionary.ContainsKey("Sessionkey")) --> return Bool
If you know it's a string, you can use the String.IsEmptyOrNull() function.
Are you using .NET 3.5? Create an IsNull extension method:
public static bool IsNull(this object input)
{
input == null ? return true : return false;
}
public void Main()
{
object x = new object();
if(x.IsNull)
{
//do your thing
}
}