Sergey Shishkin

on agile software development

ProfileTextBox – coding ASP.NET without ViewState

ViewState is bad! No, it’s not an axiom. It’s like to say ‘drugs are bad’ – in general, yes, but they are used in medicine as well. So, ViewState is a kind of drug – you may use it in some exceptional cases, but many developers are addicted to the ViewState and use it here, there and everywhere.

What about ControlState?

Fortunately, in ASP.NET 2.0 ViewState model was revised – ControlState was included and developers were allowed to disable the ViewState without any fear to break any functionality of built-in controls. ControlState is the same drug as a ViewState, but its usage became more complicated, compare to ViewState, to make developers of controls think twice before using it. 

Exceptional cases?

I was developing a web form with new ASP.NET 2.0 Wizard web control when I understood that I have to use some sort of a ViewState. Wizard control simply switches controls’ Visible property to show only appropriate controls for each step. This behavior has its drawback – on the last step there are no values from previous steps in the Request.Form. So I needed to store values of controls somehow through the whole wizard lifecycle until the last step where actual data processing takes its place. Just to avoid the use of ViewState I looked at the ASP.NET 2.0 Profile API and decided to use it as a storage for my data.

Why Profile?

Profile approach has number of benefits. Firstly, user can leave my wizard somewhere in the middle of it, return to the site after a week or two, and the wizard will show the same step that the user has left. Secondly, all the data persists on a server-side and the user is not able to corrupt the data. Finally, it allows the developer to avoid the ViewState and ControlState.

ProfileTextBox

To reduce the amount of code for managing persistence of controls values I inherited the TextBox control and implemented profile-based persistence in my custom web control. First thing I done was switching the ViewState off 🙂

    protected override void OnInit (EventArgs e)
   
{
       
this.EnableViewState = false;
       
base.OnInit(e);
   
}

Then I defined a property to map my control’s value to the user’s profile property:

    private string _profileProperty;
   
[Bindable(true)]
   
[Category("Behavior")]
   
[DefaultValue("")]
   
[Description("Profile property.")]
   
public virtual string ProfileProperty
   
{
       
get
       
{ return _profileProperty; }
       
set
       
{
           
if (string.IsNullOrEmpty(value))
           
{
               
throw new ArgumentNullException();
           
}
           
_profileProperty = value;
       
}
   
}

To serialize/deserialize typed profile property to the TextBox.Text string property the same approach was used that is used in Profile API itself – TypeConverter class:

    private TypeConverter GetConverter ()
   
{
       
TypeConverter conv = TypeDescriptor.GetConverter(
           
ProfileCommon.Properties[ProfileProperty].PropertyType);
       
if (conv != null
           
&& conv.CanConvertFrom(typeof(string))
           
&& conv.CanConvertTo(typeof(string)))
       
{
           
return conv;
       
}
       
return null;
   
}

The most interesting part of this control is in the next two methods:

    private void DisplayValue ()
   
{
       
object value = Context.Profile[ProfileProperty];
       
if (value != null)
       
{
           
TypeConverter conv = GetConverter();
           
if (conv != null)
           
{
               
base.Text = conv.ConvertToInvariantString(value);
           
}
       
}
   
}

    private void PersistValue ()
   
{
       
string value = Page.Request.Form[this.UniqueID];
       
if (value != null)
       
{
           
TypeConverter conv = GetConverter();
           
if (conv != null)
           
{
               
Context.Profile[ProfileProperty] =
                   
conv.ConvertFromInvariantString(value);
           
}
       
}
   
} 

I think the code is self-explanatory, so only few comments on it: TypeConverter object is created using type information from profile property. To display the value the TextBox.Text property is used – After a post back the value is read out of Page.Request.Form. The only thing left to do was to include this persistence logic into web control object model:

    protected override void OnLoad (EventArgs e)
   
{
       
base.OnLoad(e);
       
if (Page.IsPostBack)
       
{
           
PersistValue();
       
}
       
DisplayValue();
   
}

Now this control with defined ProfileProperty property can be added to the web form.

<nt:ProfileTextBox Runat="server" ID="tbAttendees" ProfileProperty="Tmp.AttendeesCount" /> 

And don’t forget that one need to define Tmp.AttendeesCount property profile schema in web.config to use the control.

Conclusion

Returning to the initial problem I can now replace all TextBoxes with this new ProfileTextBox control and forget about them – all the data will be automatically synchronized with the current user’s profile. Along with the ability to use this control in complex UI scenarios like Wizard control, one can use it to create user’s profile editing web form without any line of code-behind. Also, nice feature would be to use AJAX to save values to the profile on the fly. 

This ProfileTextBox control is definitely not a universal ready-to-use solution for persisting and displaying any type of data, but this is only an example of approach one can use to build web UI avoiding a ViewState when it is possible.

ProfileTextBox.zip (1.2 KB)

Advertisements

Written by Sergey Shishkin

11.05.2006 at 12:34

Posted in Uncategorized

%d bloggers like this: