Showing posts with label web application. Show all posts
Showing posts with label web application. Show all posts

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

Thursday, July 19, 2007

Create a minimalist Apache Struts 2.0 web application with Eclipse

I was recently asked by a colleague what I know about Apache Struts 2.0. I know that Apache Struts 2.0 was heavily redesigned and incorporated many elements of WebWork into it, but I don't have first hand experience with it. So I decided to start looking into it and get some first hand experience with Struts 2.0. This blog entry documents my first attempt at building a minimalist Struts 2.0 web application to be used as blank template for future web applications.

I started out by creating a new dynamic web project in Eclipse

I then copied over the following jar files into <project root>\WebContent\WEB-INF\lib folder (you can find these jar files in the struts blank application) :

  • antlr-2.7.2.jar
  • commons-logging-1.1.jar
  • freemarker-2.3.8.jar
  • ognl-2.6.11.jar
  • struts2-core-2.0.8.jar
  • xwork-2.0.3.jar

I replaced the Eclipse autogenerated web.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" 
 xmlns="http://java.sun.com/xml/ns/j2ee" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>My Sample Strust Web Application </display-name>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

</web-app>

This web.xml file tells the tomcat server to apply the master Struts filter to all resources on the server. The FilterDispatch filter does the following

  • Execute actions
  • Clean up ActionContext (can cause problems with SiteMesh)
  • Serve static content
  • Start XWork's interceptor chain for the request cycle

I created the file struts.xml and put it in the <project root>\src folder with the following content :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />

    <include file="example.xml"/>

    <!-- Add packages here -->

</struts>

The parameter struts.enable.DynamicMethodInvocation is to enable backward compatibility with WebWork 2. I would set this to false for new web applications. If I enable struts.devMode by setting it to true, I get the following:

  • Resource bundles are reloaded on every request. Which means you can change your properties file and see the changes on the next request.
  • Xml configuration files, validations files are reloaded on every request.
  • Exceptions will be thrown to normally ignorable problems.
  • Remember to turn this off in production!

Since I'm testing this out in development mode, I would set it to true. As you have probably noticed in the struts.xml file, I separated the application configuration to the include file example.xml. We'll begin with a basic example of hello world.

I created the file example.xml in the folder into <project root>\src with the following content :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="examples" namespace="/examples" extends="struts-default">

 <!--  Hellow world example -->
        <action name="HelloWorld">
            <result>/examples/helloworld.jsp</result>
        </action>

        <!-- Add actions here -->
    </package>
</struts>

For those of you who had experiences with Struts 1.x, notice how sensible defaults shorten the configuration significantly. If we do not specify the class attribute in the action tag, it defaults automatically to the default ActionSupport class, which always returns success. If we do not explicitly name the results tag, it defaults to "success" automatically. These sensible defaults allows us to write the above minimalist configuration file.


        <action name="HelloWorld">
            <result>/examples/helloworld.jsp</result>
        </action>

Compare the above configuration with an equivalent Struts 1.x configuration:

        <action path="/examples/HelloWorld"
                name="HelloWorld"
                type="examples.HelloWorldAction"
                validate="false"
            <forward name="HelloWorld" path="/examples/helloworld.jsp" />
        </action>

On top of the extra configuration, I would have also needed to implement HelloWorldAction class.

Testing out the code, I get :

Voila! I have my minimalist Struts 2.0 web application.