Wednesday, November 14, 2007

Programming ASP.NET 2.0 with F#

Setting up Visual Studio

Thanks to Robert Pickering and his book "Foundations of F#", setting up Visual Studio to develop ASP.NET application is fairly simple. Below is a list of steps to do so:

  1. Create a F# project
  2. Create a website
  3. Add the F# project created in Step #1 to the website project
  4. Copy the .fsharpp file from the F# project folder to the website project folder
  5. Open the F# project solution file (.sln file) in notepad and change the path to the .fsharpp file so that it points to the .fsharp file in the website project folder
  6. Create a \Bin folder in the website project
  7. Open the F# project properties and set the project type to "DLL" and configure the output to create the dll in the \Bin folder of the website project
At the same time, I'm working through the book "Pro ASP.NET 2.0 in C# 2005" by Matthew MacDonald. Below are some of the code examples that are translated from the C# versions from Chapter 3 of the book:


PageFlow.aspx


<%@ Page Inherits="FSharp.HttpHandlers.PageFlow" %>

<html>
<head runat="server">
<title>Page Flow Example from Chap 3 of Pro ASP.NET 2.0 in C#</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>
<asp:Label ID="lblInfo" runat="server" EnableViewState="false" />
</p>
<p>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="OnButtonClick"/>
</p>
</div>
</form>
</body>
</html>

pageflow.fs

#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

type PageFlow = class
inherit Page as base

// map to <asp:Label id="lblInfo>
val mutable lblInfo : Label

// maps to <asp:Button id="Button1">
val mutable Button1 : Button

new () as this = { lblInfo = null; Button1 = null }

override this.OnLoad e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.Load even handled.<br />"
if this.Page.IsPostBack then
this.lblInfo.Text <- this.lblInfo.Text + "<b>This is the second time you've seen this page.</b><br />"

base.OnLoad(e)

override this.OnInit e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.Init event handled.<br />"

override this.OnPreRender e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.PreRender event handled.<br />"

override this.OnUnload e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.OnUnload event handled.<br />"

member this.OnButtonClick ((sender:obj), (e:EventArgs)) =
this.lblInfo.Text <- this.lblInfo.Text + "Button1.Click event handled.<br />"

end

ControlTree.aspx

<%@ Page Inherits="FSharp.HttpHandlers.ControlTree" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head >
<title>Control Tree Example from Chap 3 of Pro ASP.NET 2.0 in C </title>
</head>
<body>
<div>
<p><i>This is static HTML (not a web control).</i></p>
</div>
<form id="frm" runat="server">
<div>
<asp:panel id="MainPanel" runat="server" Height="112px">
<p><asp:Button id="Button1" runat="server" Text="Button1"/>
<asp:Button id="Button2" runat="server" Text="Button2"/>
<asp:Button id="Button3" runat="server" Text="Button3"/></p>
<p><asp:Label id="Label1" runat="server" Width="48px">
Name:</asp:Label>
<asp:TextBox id="TextBox1" runat="server"></asp:TextBox></p>
</asp:panel>
<p><asp:Button id="Button4" runat="server" Text="Button4"/></p>

</div>
</form>
<div>
<p><i>This is static HTML (not a web control).</i></p>
</div>
</body>
</html>

controltree.fs

#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

type ControlTree = class
inherit Page as base

new () as this = {}

override this.OnLoad e =
this.DisplayControl this.Page.Controls 0
this.Response.Write("<hr/>")


member this.DisplayControl (controls:ControlCollection) (depth:int) =
for control in controls do
// Use the depth parameter to indent the control tree
this.Response.Write(new String('-', depth*4) + "> ")

// Display this control
this.Response.Write(control.GetType().ToString()
+ " - <b>" + control.ID + "</b><br/>")

if (control.Controls <> null) then
this.DisplayControl control.Controls (depth+1)



end

DynamicButton.aspx

<%@ Page Inherits="FSharp.HttpHandlers.DynamicButton" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Dynamic Button Example from Chap 3 of Pro ASP.NET 2.0 in C#</</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel id="Panel1" style="Z-INDEX: 101; LEFT: 24px; POSITION: absolute; TOP: 32px" runat="server"
Width="364px" Height="142px">
<p>
<asp:Label id="Label1" runat="server">(No value.)</asp:Label></p>
<p>
<asp:PlaceHolder id="PlaceHolder1" runat="server"></asp:PlaceHolder>
<asp:Button id="cmdReset" runat="server" Width="112px" Text="Reset Text" OnClick="cmdReset_Click"></asp:Button><br/>
</p>
<hr/>
<p>
<asp:Button id="cmdCreate" runat="server" Width="137px" Text="Create Button" OnClick="cmdCreate_Click"></asp:Button>
<asp:Button id="cmdRemove" runat="server" Width="141px" Text="Remove Button" OnClick="cmdRemove_Click"></asp:Button>
</p>
</asp:Panel>
</div>
</form>
</body>
</html>

dynamicbutton.fs

#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


type DynamicButton = class
inherit Page as base

val mutable Panel1 : Panel
val mutable Label1 : Label
val mutable cmdReset : Button
val mutable cmdCreate : Button
val mutable cmdRemove : Button

new () as this = {
Panel1=null
Label1=null
cmdReset = null
cmdCreate = null
cmdRemove = null }

override this.OnLoad e =
let newButton = new Button()
newButton.Text <- "* Dynamic Button *"
newButton.ID <- "newButton"
newButton.Click.Add(fun e -> this.Label1.Text <- "You clicked the dynamic button.")
this.Panel1.Controls.Add(newButton)

member this.Button_Click ((sender:obj), (e:EventArgs)) =
this.Label1.Text <- "You clicked the dynamic button."

member this.cmdReset_Click ((sender:obj), (e:EventArgs)) =
this.Label1.Text <- "(No value.)"

member this.cmdRemove_Click ((sender:obj), (e:EventArgs)) =
let foundButton = this.Page.FindControl("newButton") :?> Button
if foundButton <> null then
foundButton.Parent.Controls.Remove(foundButton)

// Button is automatically created in postback
member this.cmdCreate_Click ((sender:obj), (e:EventArgs)) = ()


end

#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


type DynamicButton = class
inherit Page as base

val mutable PlaceHolder1 : PlaceHolder
val mutable Label1 : Label
val mutable cmdReset : Button
val mutable cmdCreate : Button
val mutable cmdRemove : Button

new () as this = {
PlaceHolder1=null
Label1=null
cmdReset = null
cmdCreate = null
cmdRemove = null }

override this.OnLoad e =
let newButton = new Button()
newButton.Text <- "* Dynamic Button *"
newButton.ID <- "newButton"
newButton.Click.Add(fun e -> this.Label1.Text <- "You clicked the dynamic button.")
this.PlaceHolder1.Controls.Add(newButton)

member this.Button_Click ((sender:obj), (e:EventArgs)) =
this.Label1.Text <- "You clicked the dynamic button."

member this.cmdReset_Click ((sender:obj), (e:EventArgs)) =
this.Label1.Text <- "(No value.)"

member this.cmdRemove_Click ((sender:obj), (e:EventArgs)) =
let foundButton = this.Page.FindControl("newButton") :?> Button
if foundButton <> null then
foundButton.Parent.Controls.Remove(foundButton)

// Button is automatically created in postback
member this.cmdCreate_Click ((sender:obj), (e:EventArgs)) = ()


end

PageFlowTracing.aspx

<%@ Page Inherits="FSharp.HttpHandlers.PageFlowTracing" Trace="true"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Page Flow Tracing Example from Chap 3 of Pro ASP.NET 2.0 in C#</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p><asp:Label id="lblInfo" runat="server" EnableViewState="False" /></p>
<p>
<asp:Button id="Button1" runat="server"
Text="Button" OnClick="Button1_Click" />
</p>

</div>
</form>
</body>
</html>

pageflowtracing.fs

#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


type PageFlowTracing = class
inherit Page as base

val mutable lblInfo : Label
val mutable Button1 : Button

new () as this = {
lblInfo = null
Button1 = null }

override this.OnLoad e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.Load event handled.<br/>"
if this.Page.IsPostBack then
this.lblInfo.Text <- this.lblInfo.Text
+ "<b>This is the second time you've seen this page.</b><br/>"

override this.OnInit e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.Init event handled.<br/>"

override this.OnPreRender e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.PreRender event handled.<br/>"

override this.OnUnload e =
this.lblInfo.Text <- this.lblInfo.Text + "Page.Unload event handled.<br/>"


member this.Button1_Click ((sender:obj), (e:EventArgs)) =
this.Trace.Write("Button1_Click","About to update the label.")
this.lblInfo.Text <- this.lblInfo.Text + "Button.Click event handled.<br/>"
this.Trace.Write("Button1_Click","Label updated.")



end

No comments: