Friday, November 16, 2007

Working with ASP.NET 2.0 ViewState in F#

I'm poking around with ViewState programming in ASP.NET 2.0 with F# and ran into some mental blocks with IEnumerable and how it works with ControlCollection. I also had some mental hurdles to overcome working with IDictionary and Page ViewState

When I tried to implement the ViewState Test example in Chapter 6 of Pro ASP.NET 2.0 in C#, I ran into the problem of working with ViewState. My SaveAllText() method would complain with the message A protected member is called. These are not allowed in lambda expressions since they could escape the object.. Searching the web on this brings me back to Don Syme's blogs which talked about a GenerateMaximallyAccessibleDerivedClass method that was used in an apparently older version of the F# compiler. I'm banging my head against the wall until I tried creating my own mutable StateBag member variable and set it to refer to ViewState. That seemed to let me progress. I'm stil not sure if I introduced any other problems with this, but it did let me bypass the protected member problem and the page worked as expected

My mental hurdle with IDictionary is I did not how to do something such as

string value = dictionary[mykey]
I googled for it and did not turn up with anything at all. Finally, I decided to fire up F# interactive and started to explore a IDictionary object. When I took a look at the signature for
IDictionary.Item
it returned the following signature:
val it : 'a -> obj = <fun:clo@0>
I had not realized that IDictionary.Item was a function! Now I know how to find a value by key with a IDictionary object.

The last mental hurdle I have is with IEnumerator objects. I wanted to do something like

IEnumerable.iter myfunc controls
but I keep getting a complaint about The type ControlCollection is not compatible with the type seq<Control>. Somehow, that error message did not register with me that I'm trying to stuff a nongeneric IEnumerator into a function that's expecting a generic version of IEnumerator object. Finally, after staring at the list of functions available to IEnumerable, I noticed
IEnumerable.untyped_to_typed
Finally, the last piece of this puzzle was solved. Below is the code I was struggling with that now works in F#:


#light

namespace FSharp.HttpHandlers

open System
open System.Data
open System.Configuration
open System.Collections
open System.Web
open System.Web.Security
open System.Web.UI
open System.Web.UI.WebControls
open System.Web.UI.WebControls.WebParts
open System.Web.UI.HtmlControls
//
// View State Test example from Chap 6 of Pro ASP.NET 2.0 in C#
//
type ViewStateTest = class
inherit Page as base

val mutable state : StateBag

new () as this = { state = null;testmsg=null } then
this.state <- this.ViewState


member this.SaveAllText (controls:ControlCollection) (saveNested:bool) =
let rec addtoViewstate (state:StateBag) (control:Control) =
if (control :? TextBox) then
let txtbox = control :?> TextBox
state.Item(control.ID) <- txtbox.Text

if ((control.Controls <> null) && saveNested) then
(IEnumerable.untyped_to_typed control.Controls)
|> IEnumerable.iter (addtoViewstate state)

IEnumerable.iter (addtoViewstate this.state) (IEnumerable.untyped_to_typed controls)

member this.RestoreAllText (controls:ControlCollection) (saveNested:bool) =
let rec restoreFormViewstate (state:StateBag) (control:Control) =
if (control :? TextBox) then
let txtbox = control :?> TextBox
txtbox.Text <- ((state.Item control.ID) :?> string)

if ((control.Controls <> null) && saveNested) then
(IEnumerable.untyped_to_typed control.Controls)
|> IEnumerable.iter (restoreFormViewstate state)

IEnumerable.iter (restoreFormViewstate this.state) (IEnumerable.untyped_to_typed controls)

member this.cmdSave_Click ((sender:obj), (e:EventArgs)) =
this.SaveAllText this.Page.Controls true

member this.cmdRestore_Click ((sender:obj), (e:EventArgs)) =
this.RestoreAllText this.Page.Controls true
end

No comments: