Hi Everyone! I thought I’d talk about how I handle working with highly structured data in an ASP.NET web page. For my DMF application, I’m using ASP.NET for the management console for the system and I have a lot of highly structured classes of information.
I had some requirements to meet.
- All the data had to stay within the page until the user clicked SAVE.
- Had to support numerous user controls on the page that displayed tables and forms.
- Can not use Session or other memory storage to keep the data between posts.
Fortunately, my data model was designed to help facilitate the remote manipulation of the data, whether that be in ASP.NET or WPF applications. The data object is loaded from a database table using my database library, edited by the application, then stored back to the database. The data object is a self-contained structured object with many properties, lists, lists of other classes, etc. It is designed so that all the data in the class is XML serializable. Many of the class sub-properties in the object may be stored in serialized format in the database.
So, my Page_Load method will load the object from the database, and then stores it into a special property in the page. Usually, I name this for the type of data it is. For example, if the page is manipulating a TargetRule, I call the property RuleData. This property is actually backed by ViewState using some special functions that I keep in a super class of the page. These special functions serialize and deserialize the object when transferring it to and from ViewState.
Here is the SetData() function I use to save the data into ViewState. As you can see, it is templated so that it works on any object type. It is limited though in that the object must be derived from my XmlBaseType class which adds instant XML serialization capabilities. The new() requirement also makes sure that it is a real object, not a structure or simple type. I also store the value in a private dictionary so that I can do multiple GetData() calls without having to deserialize many times. The ViewState name used is a combination of the class type and an instance name so that multiple instances of a single type can be stored.
[ccle_csharp lines=”-1″ width=”600″] public void SetData(T data, string instanceName) where T : XmlBaseType, new(){
string typeName = data.GetType().Name + instanceName;
_viewData[typeName] = data;
ViewState[typeName] = data.SerializeXML();
}
[/ccle_csharp]
Once the data is stored, it must also be retrievable. The following GetData() method is also a templated function that uses the object’s data type with the added instance name to find the object in ViewState. Once it has figured out the name, it checks the private dictionary to see if it was cached. This saves a deserialization call. If it wasn’t in the page cache, it gets the data into a string and then deserializes it back to a full object. It is then placed into cache for the next call, and returns the object.
[ccle_csharp lines=”-1″ width=”600″] public T GetData(string instanceName) where T : XmlBaseType, new(){
string typeName = typeof(T).Name + instanceName;
if (_viewData.ContainsKey(typeName)) return _viewData[typeName] as T;
T data = default(T);
string s = (string)ViewState[typeName];
if (!string.IsNullOrEmpty(s))
{
data = s.DeserializeXML() as T;
_viewData[typeName] = data;
}
return data;
}
[/ccle_csharp]
The private cache is defined simply as this one line.
[ccle_csharp lines=”-1″ width=”600″] private readonly Dictionary _viewData = new Dictionary();[/ccle_csharp]
And an example of my property declaration is as follows.
[ccle_csharp lines=”-1″ width=”600″] public TargetRule RuleData{
get { return GetData(); }
set { SetData(value); }
}
[/ccle_csharp]
The only issue I have is that I cannot handle generic collections directly yet. I have to create an additional class with the list contained in it and then modify the C# property to wrap the list in the class. The property itself takes and gives the list, but internally, the extra class is used. I have extended my serialization code to work on all objects but have not had a chance to make and test the changes yet.
For all my pages and user controls, I derive them from a BasePage or BaseControl. I put these methods into that base object so that they’re available to all my pages and user controls. I thought about creating extension methods instead, but they don’t have direct access to the ViewState class if I don’t pass that in as well on every call.
Of course, there is one other issue with storing whole objects in ViewState which is the amount of time and data it takes to store that data on the client’s page and get it back again. There are techniques though to store ViewState on a shared folder on the server, and I’ll get into that in a later article.
Using the data is the next step. Basically, at the top of your event method you retrieve a copy of the object from the property. Once done making changes, you write the object back to the property to save it. If you don’t write it back, it doesn’t get saved.
[ccle_csharp lines=”-1″ width=”600″] private void MyFunc(object sender, EventArgs e){
var rule = RuleData;
rule.Name = “This is a new name”;
rule.SomeList = new List
RuleData = rule;
}
[/ccle_csharp]
And that’s how simple it works!