Here is a simple pattern for setting up strongly-typed but flexible access to your ViewData, Session, and Request variables.
Add a ViewData “property” by adding the following methods
public static ViewDataDictionary FirstName(this ViewDataDictionary collection, string value) { collection["FirstName"] = value; return collection; } public static string FirstName(this ViewDataDictionary collection) { return collection["FirstName"] as string; }
Add a Session “property” by adding the following methods
public static HttpSessionState FirstName(this HttpSessionState collection, string value) { collection["FirstName"] = value; return collection; } public static string FirstName(this HttpSessionState collection) { return collection["FirstName"] as string; }
Add a Request “property” by adding the following method. Note that the Request collection is read-only
public static string FirstName(this HttpRequest collection) { return collection["FirstName"]; }
Accessing these methods looks like this
ViewState.FirstName("Jason"); var firstName = ViewState.FirstName(); Session.FirstName("Johnny"); var firstName = Session.FirstName(); var firstName = Request.FirstName();
If your extension methods are not in the same namespace as the code that will be using them, you will either need to put a “using (namespace of extension method static class)” on every page you plan to use it, or change the namespace of your extension method static class to be the same as the other pages. This will enable Intellisense and make the extension methods very easy to use.
To add the equivalent of a global using statement to your Razor views, edit your Views/web.config file.
Locate the key “/configuration/system.web.webPages.razor/pages/namespaces”
and add your own namespace by adding an element that looks like <add namespace=”DefaultNamespace.Extensions” />
In the examples, I use “FirstName” as the key. However, your key (at least with the ViewState and Session objects) can be anything you like, as long as you use the same key in the getter and the setter. You can reduce the chance of name collisions with other parts of your application by selecting something more complex or obscure for the key.
For non-nullable types, be sure to handle the situation where the item is not found in the collection. One solution is to return a default value (preferably “default(type)”) when the item is not found. The other solution is to return a Nullable<type> that returns the value when found, else null.