(This article is cross-posted from
[link:tomasp.net]
)As I mentioned earlier, I spent three months as an intern in Microsoft Research in Cambridge last year and I was working with Don Syme and James Margetson from the F# team. Most of the time I was working on the F# Web Toolkit, which I introduced on the blog some time ago [
1], but I also worked on a few additions that are now part of the F# release. Probably the most useful addition is a new implementation of the CodeDOM provider for the F# language which makes it possible to use ASP.NET smoothly from F# (but it can be used in some other scenarios as well) together with two ASP.NET sample applications that you can explore and use as a basis for your web sites. This was actually a part of the distribution for a few months now (I of course wanted to write this article much earlier...), so you may have already noticed, but anyway, I'd still like to write down a short description of these ASP.NET samples and also a few tips for those who're interested in writing web applications in F#.
F# and ASP.NET
Let's start by looking at the ASP.NET examples. You can find them in the
samples directory in your F# installation under the
Web/ASP.NET path. The directory also contains
html files with description of the projects and a guide to configuring them, but I'll describe both of these topics in this post. The distribution contains two sample projects:
- AspNetIntro - this project is (almost) the simples possible F# web site, so it can be used as a template for your web sites. It shows how to configure the CodeDOM provider, how to write a simple page with code-behind and how to use the
App_Code directory and data-binding.
- PersonalWebSite - this is a more complex web site ported from the C# sample called Personal Web Site Starter Kit [2]. It demonstrates many of the standard ASP.NET 2.0 techniques including data access controls, master pages, membership and custom HTTP handlers.
ASP.NET Introduction using F#
To start playing with ASP.NET you'll need to open the project (I recommend copying it to your working directory first). If you're using Visual Studio, you can select
File - Open - Web Site... in the menu and select the directory with your project as demonstrated at Figure 1 below. The organization of ASP.NET projects is different than organization of ordinary F# projects - in ASP.NET the project is just a directory and it contains all the files in the directory (this is also the reason why you have to open it using a different command). The Figure 2 shows how the files of the ASP.NET Introduction project are organized in the Solution Explorer:
Figure 1: Open Web Site
Figure 2: Solution Explorer
As you can see, there are 6 files in the project. The
Default.aspx.fs and
Default.aspx together form one web page and the
DataBinding.aspx.fs with
DataBinding.aspx form the second web page. The
App_Code directory contains application logic that can be used from other pages in the project and in our sample project it contains only one file (
logic.fs). Finally, the
web.config file contains configuration of the whole application.
Before we look at the pages you may want to check the
web.config file, because it needs to contain the correct reference to the CodeDOM provider implementation including a version of the current F# installation. At the time of writing this article, the latest version is
1.9.3.14, but if you're not sure what version you are using, you can just start the
fsi.exe from the F# installation which prints the version number. The
web.config file is an
xml file and it should contain the following content (with the right version number). The samples in the distribution should contain the correct version number, but the incorrect configuration is a common issue when working with ASP.NET in F#, so it is useful to know what the configuration should look like:
<?xml version="1.0"?>
<configuration><system.web>
<compilation debug="true">
<compilers>
<compiler
language="F#;f#;fs;fsharp" extension=".fs"
type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider,
FSharp.Compiler.CodeDom, Version=<strong style="color:red;">1.9.3.14</b>,
Culture=neutral, PublicKeyToken=a19089b1c74d0809"/>
</compilers>
</compilation></system.web>
</configuration>
Now, let's look at the
Default.aspx and
Default.aspx.fs files that together represent a simple page. The page contains one button and one label (a control that can display some text) and when the user clicks on the button, the result of some calculation is displayed in the label (the calculation is executed on the server-side). The following code is a (slightly simplified) content of the
Default.aspx file, which defines the HTML markup together with the ASP.NET controls that are on the page:
<%@ Page Language="F#"
CodeFile="Default.aspx.fs" Inherits="FSharpWeb.Default" %>
<html>
<body><form runat="server">
<asp:Button
ID="btnTest" RunAt="server" Text="Click me!"
OnClick="ButtonClicked" />
<asp:Label ID="lblResult" RunAt="server" />
</form></body>
</html>
You can easily identify two server-side controls, because these are written using prefix
asp and also contain the
RunAt="server" attribute, which means that the control is processed on the server-side. You can use standard HTML notation for setting attributes of the controls. We set the
ID attribute to both of the controls, which is important because it allows us to use them in the code-behind code. The
OnClick attribute of the button sets an event handler - a member of the
FSharpWeb.Default type from the code-behind file that will be called on the server-side, when a user clicks on the button (which submits the HTML form and causes a page reload, so the event can be processed on the server). The file also contains the first special line, which tells the ASP.NET engine that the page is written in F# and it also tells what source file contains the code-behind code and what is the name of type declared in that file. The code-behind file (
Default.aspx.fs) has the following content:
#light
namespace FSharpWeb
open System
open System.Web
open System.Web.UI.WebControls
type Default() =
inherit Page()
[<DefaultValue>]
val mutable btnTest : Button
[<DefaultValue>]
val mutable lblResult : Label
member this.ButtonClicked(sender, e) =
this.lblResult.Text <-
(sprintf "Factorial of 5 is: %d"
(FSharpWeb.Logic.factorial 5))
As we can see, the file contains an F# object type (named
Default), inherited from the base ASP.NET
Page type. Thanks to the recent improvements in F# it is possible to write the type using the new implicit class syntax (note the parentheses after the type name), which means that you can place additional initialization code to the type declaration directly (following the
inherit clause and F# will treat this as a constructor.
The class contains a mutable field for every control declared in the declarative markup with the name same as the
ID attribute in the markup file (
btnTest and
lblResult). The ASP.NET initializes these controls automatically when it creates the page (that's why the fields are marked using
mutable), so we don't need to initialize these fields in our code - F# doesn't usually allow uninitialized fields, but if you place the
DefaultValue before the field declaration, it will be initialized to the default value (
null), which is correct, because the field will be later initialized by the ASP.NET runtime. Finally, the type contains a member called
ButtonClicked, which is a same name we used in the markup for the
OnClick attribute of the button control. This is an event handler that will be called when user clicks on the button, it performs some calculation (the
factorial function is declared in the
logic.fs file) and sets a property of the other control that we have on the page.
Personal Web Site in F#

Figure 3: Personal Web Site
The second sample ASP.NET project is a port of quite a complex ASP.NET web site which also uses MS SQL database. The database can be created manually as described in
Welcome.html in the
PersonalWebSite directory, but I also uploaded the database to my web, so you can just download it and attach it in the SQL server (this is described below and the files for download can be found at the end of the article). The
PWS_AspNetDb is a database managed by ASP.NET that contains user information - the database below already contains the required role (called
Administrators) and one user (
admin with password
admin123!). The second database file (
PWS_WebPersonal) contains the application data, mainly information about photos and galleries (as you can see from the screenshot in Figure 3).
The application uses many advanced ASP.NET features including the following:
- Master Pages - the overall structure of the web site is stored in a master page (
Default.master) and the other pages use the asp:Content control to fill the place holders in the master page.
- Site Maps - the map of the web site is defined in the
web.sitemap file and is used for generating the menu in the Default.master file.
- Themes - the design of the page including CSS files and images are managed using ASP.NET Themes - there are two standard themes in the
App_Themes directory.
- Membership - the web uses standard ASP.NET technology for managing user accounts including the controls for manipulating with users (e.g.
asp:CreateUserWizard control is used in Register.aspx file).
- Data Controls - ASP.NET data-access controls are used for reading the data from the application logic layer (implemented as a module in F#)
Configuring the databases
To configure the databases required by the demo, you can either follow the steps described in the
Welcome.html file (which is part of the sample project), or if you already have some version of SQL Server installed on your machine, you can download the sample databases below (a bunch of MDF and LDF files) and attach them to the SQL Server. I'll explain how to do this using full version of SQL Server, but the steps needed with Express edition are very similar.
Once you downloaded the files, you'll need to launch SQL Server Management Studio and connect to the server instance. After doing that you should see an "Object Explorer" window, where you can right click on the "Databases" group and select "Attach..." from the pop-up menu. In the opened dialog window, you can add the databases (by selecting the MDF file) and click the "OK" button to attach the databases. Finally, you'll need to modify the
web.config file in the Personal WebSite sample to include the following section:
<connectionStrings>
<add name="Personal" providerName="System.Data.SqlClient" connectionString=
"Data Source=.;Integrated Security=True;Database=PWS_WebPersonal" />
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer" connectionString=
"Data Source=.;Integrated Security=True;Database=PWS_AspNetDb" />
</connectionStrings>
The
Data Source parameter in the connection string specifies the instance of the SQL Server, where the databases are attached. By default this is the name of your computer (which can be written shortly using dot "."). When using the SQL Express the default instance name is ".\SQLExpress". The
Database parameter specifies the name of the database, which you can see in the "Object Explorer" in the SQL Server Management Studio. After following these steps, you should be able to run the demo application.
Data-access in F#
Most of the ASP.NET technologies used in the web site are used in almost the same way as in C#, so I will not discuss them in larger details, but the last item in the list - the use of ASP.NET data controls together with F# is I believe quite interesting, so I'll write a few notes about it. Let's look for example at the
Photos.aspx file, which displays a list of photos in a gallery. The most important parts of the file related to data access are shown in the following code snippet:
<asp:DataList RunAt="server" DataSourceID="photoSource" EnableViewState="false">
<ItemTemplate>
<!-- ... -->
<a href='Details.aspx?AlbumID=<%# base.Eval("PhotoAlbumID") %>'>
<img src="Handler.ashx?PhotoID=<%# base.Eval("PhotoID") %>&Size=S"
class="photo_198" style="border:4px solid white"
alt='Thumbnail of Photo Number <%# base.Eval("PhotoID") %>' />
</a>
<!-- ... -->
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="photoSource" RunAt="server"
TypeName="PersonalWebSite.PhotoManager"
SelectMethod="GetPhotos">
<SelectParameters>
<asp:QueryStringParameter Name="AlbumID" Type="Int32"
QueryStringField="albumID" DefaultValue="0"/>
</SelectParameters>
</asp:ObjectDataSource>
The first ASP.NET control used in the code is
asp:DataList, which is a control that simply displays a collection of some items and uses a specified
ItemTemplate for displaying every single item. In our case we're working with collection of records and the record has several members (including
PhotoID and
PhotoAlbumID). To display a value of a record member in the ASP.NET page we have to use ASP.NET
Eval method as you can see in the sample. The
Eval method reads the specified member of the item in collection and writing the code in
<%# ... %> tells ASP.NET that we want to render the result of the expression as a part of the item template. The record that we're using in this example is very simple and has the following structure:
type Photo =
{ PhotoID:int;
PhotoAlbumID:int;
PhotoCaption:string; }
This is actually one of the places where the F# version is shorter, because in C# version you have to write this as a class with properties, which makes the code quite longer.
The second server-side control (
asp:ObjectDataSource) in the first code snippet isn't visual, which means that it will not produce any HTML output. It serves just as a declarative data-source for the data list and the properties of this control specify how the content for the data list should be loaded. There are various other data-source controls in ASP.NET (e.g.
asp:SqlDataSource which loads data directly from the database), but the one that we're using in the example uses a specified .NET/F# type and calls a method of the given object when it needs to retrieve the data. In F# this is even easier, because we can use a name of the module and the code that retrieves the data can be a function in the module.
As you can see the property
TypeName is set to
PersonalWebSite.PhotoManager, which can be treated as a module called
PhotoManager in a namespace
PersonalWebSite and the
SelectMethod property, which specifies a name of the function that will be called when loading the data is set to
GetPhotos. Finally, the
SelectParameters specifies that the function expects one argument called
AlbumID and that the value of this argument should be retrieved from the query string (that is from the URL of form
photo.aspx?albumIdD=42).
Now it is pretty easy to implement the module that matches this specifications and can be used as a data source (we could of course use FLinq for loading the data, but I wanted to keep things simple for now, so we're using standard
SqlDataReader object from .NET):
namespace PersonalWebSite
// ...
module PhotoManager =
// Function will be called by ASP.NET when loading data
// for the asp:DataList control in the 'Photos.aspx' page
let GetPhotos (albumID:int) =
// Open connection & create command
use conn = new SqlConnection(" ... ")
use cmd = new SqlCommand("GetPhotos", conn)
// Can the user see 'private' photos?
let usr = HttpContext.Current.User
let filter = not (usr.IsInRole("Friends") || usr.IsInRole("Administrators"))
cmd.CommandType <- CommandType.StoredProcedure)
cmd.Parameters.Add(SqlParameter("@AlbumID", albumID)) |> ignore
command.Parameters.Add(SqlParameter("@IsPublic", filter)) |> ignore
conn.Open()
// Read all photos into a .NET ResizeArray type
let list = new ResizeArray<_>()
use reader = command.ExecuteReader()
while (reader.Read()) do
list.Add({ PhotoID = unbox (reader.get_Item("PhotoID"))
PhotoAlbumID = unbox (reader.get_Item("AlbumID"))
PhotoCaption = unbox (reader.get_Item("Caption")) })
// Return the created collection
list
I hope this article explained some of the interesting things that you may find in the ASP.NET samples provided with the F# distribution and I think that the Personal WebSite Sample shows that F# can be used for writing quite complicated web applications as well. Of course, my initial motivation for writing web applications in F# is the possibility of using meta-programming to develop client-side code (the code that runs on the client as a JavaScript) in F# too, which makes development of modern "Ajax"-style applications easier, so if you're interested in this project you may want to look at F# Web Tools [
1].
Downloads & References
(This article is cross-posted from [link:tomasp.net] )
As I mentioned earlier, I spent three months as an intern in Microsoft Research in Cambridge last year and I was working with Don Syme and James Margetson from the F# team. Most of the time I was working on the F# Web Toolkit, which I introduced on the blog some time ago [1], but I also worked on a few additions that are now part of the F# release. Probably the most useful addition is a new implementation of the CodeDOM provider for the F# language which makes it possible to use ASP.NET smoothly from F# (but it can be used in some other scenarios as well) together with two ASP.NET sample applications that you can explore and use as a basis for your web sites. This was actually a part of the distribution for a few months now (I of course wanted to write this article much earlier...), so you may have already noticed, but anyway, I'd still like to write down a short description of these ASP.NET samples and also a few tips for those who're interested in writing web applications in F#.
F# and ASP.NET
Let's start by looking at the ASP.NET examples. You can find them in the
samplesdirectory in your F# installation under theWeb/ASP.NETpath. The directory also containshtmlfiles with description of the projects and a guide to configuring them, but I'll describe both of these topics in this post. The distribution contains two sample projects:App_Codedirectory and data-binding.ASP.NET Introduction using F#
To start playing with ASP.NET you'll need to open the project (I recommend copying it to your working directory first). If you're using Visual Studio, you can select
File - Open - Web Site...in the menu and select the directory with your project as demonstrated at Figure 1 below. The organization of ASP.NET projects is different than organization of ordinary F# projects - in ASP.NET the project is just a directory and it contains all the files in the directory (this is also the reason why you have to open it using a different command). The Figure 2 shows how the files of the ASP.NET Introduction project are organized in the Solution Explorer:Figure 1: Open Web Site
Figure 2: Solution Explorer
As you can see, there are 6 files in the project. The
Default.aspx.fsandDefault.aspxtogether form one web page and theDataBinding.aspx.fswithDataBinding.aspxform the second web page. TheApp_Codedirectory contains application logic that can be used from other pages in the project and in our sample project it contains only one file (logic.fs). Finally, theweb.configfile contains configuration of the whole application.Before we look at the pages you may want to check the
web.configfile, because it needs to contain the correct reference to the CodeDOM provider implementation including a version of the current F# installation. At the time of writing this article, the latest version is1.9.3.14, but if you're not sure what version you are using, you can just start thefsi.exefrom the F# installation which prints the version number. Theweb.configfile is anxmlfile and it should contain the following content (with the right version number). The samples in the distribution should contain the correct version number, but the incorrect configuration is a common issue when working with ASP.NET in F#, so it is useful to know what the configuration should look like:<?xml version="1.0"?> <configuration><system.web> <compilation debug="true"> <compilers> <compiler language="F#;f#;fs;fsharp" extension=".fs" type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider, FSharp.Compiler.CodeDom, Version=<strong style="color:red;">1.9.3.14</b>, Culture=neutral, PublicKeyToken=a19089b1c74d0809"/> </compilers> </compilation></system.web> </configuration>Now, let's look at the
Default.aspxandDefault.aspx.fsfiles that together represent a simple page. The page contains one button and one label (a control that can display some text) and when the user clicks on the button, the result of some calculation is displayed in the label (the calculation is executed on the server-side). The following code is a (slightly simplified) content of theDefault.aspxfile, which defines the HTML markup together with the ASP.NET controls that are on the page:<%@ Page Language="F#" CodeFile="Default.aspx.fs" Inherits="FSharpWeb.Default" %> <html> <body><form runat="server"> <asp:Button ID="btnTest" RunAt="server" Text="Click me!" OnClick="ButtonClicked" /> <asp:Label ID="lblResult" RunAt="server" /> </form></body> </html>You can easily identify two server-side controls, because these are written using prefix
aspand also contain theRunAt="server"attribute, which means that the control is processed on the server-side. You can use standard HTML notation for setting attributes of the controls. We set theIDattribute to both of the controls, which is important because it allows us to use them in the code-behind code. TheOnClickattribute of the button sets an event handler - a member of theFSharpWeb.Defaulttype from the code-behind file that will be called on the server-side, when a user clicks on the button (which submits the HTML form and causes a page reload, so the event can be processed on the server). The file also contains the first special line, which tells the ASP.NET engine that the page is written in F# and it also tells what source file contains the code-behind code and what is the name of type declared in that file. The code-behind file (Default.aspx.fs) has the following content:#light namespace FSharpWeb open System open System.Web open System.Web.UI.WebControls type Default() = inherit Page() [<DefaultValue>] val mutable btnTest : Button [<DefaultValue>] val mutable lblResult : Label member this.ButtonClicked(sender, e) = this.lblResult.Text <- (sprintf "Factorial of 5 is: %d" (FSharpWeb.Logic.factorial 5))As we can see, the file contains an F# object type (named
Default), inherited from the base ASP.NETPagetype. Thanks to the recent improvements in F# it is possible to write the type using the new implicit class syntax (note the parentheses after the type name), which means that you can place additional initialization code to the type declaration directly (following theinheritclause and F# will treat this as a constructor.The class contains a mutable field for every control declared in the declarative markup with the name same as the
IDattribute in the markup file (btnTestandlblResult). The ASP.NET initializes these controls automatically when it creates the page (that's why the fields are marked usingmutable), so we don't need to initialize these fields in our code - F# doesn't usually allow uninitialized fields, but if you place theDefaultValuebefore the field declaration, it will be initialized to the default value (null), which is correct, because the field will be later initialized by the ASP.NET runtime. Finally, the type contains a member calledButtonClicked, which is a same name we used in the markup for theOnClickattribute of the button control. This is an event handler that will be called when user clicks on the button, it performs some calculation (thefactorialfunction is declared in thelogic.fsfile) and sets a property of the other control that we have on the page.Personal Web Site in F#
Figure 3: Personal Web Site
The second sample ASP.NET project is a port of quite a complex ASP.NET web site which also uses MS SQL database. The database can be created manually as described in
Welcome.htmlin thePersonalWebSitedirectory, but I also uploaded the database to my web, so you can just download it and attach it in the SQL server (this is described below and the files for download can be found at the end of the article). ThePWS_AspNetDbis a database managed by ASP.NET that contains user information - the database below already contains the required role (calledAdministrators) and one user (adminwith passwordadmin123!). The second database file (PWS_WebPersonal) contains the application data, mainly information about photos and galleries (as you can see from the screenshot in Figure 3).The application uses many advanced ASP.NET features including the following:
Default.master) and the other pages use theasp:Contentcontrol to fill the place holders in the master page.web.sitemapfile and is used for generating the menu in theDefault.masterfile.App_Themesdirectory.asp:CreateUserWizardcontrol is used inRegister.aspxfile).Configuring the databases
To configure the databases required by the demo, you can either follow the steps described in the Welcome.html file (which is part of the sample project), or if you already have some version of SQL Server installed on your machine, you can download the sample databases below (a bunch of MDF and LDF files) and attach them to the SQL Server. I'll explain how to do this using full version of SQL Server, but the steps needed with Express edition are very similar.
Once you downloaded the files, you'll need to launch SQL Server Management Studio and connect to the server instance. After doing that you should see an "Object Explorer" window, where you can right click on the "Databases" group and select "Attach..." from the pop-up menu. In the opened dialog window, you can add the databases (by selecting the MDF file) and click the "OK" button to attach the databases. Finally, you'll need to modify the
web.configfile in the Personal WebSite sample to include the following section:<connectionStrings> <add name="Personal" providerName="System.Data.SqlClient" connectionString= "Data Source=.;Integrated Security=True;Database=PWS_WebPersonal" /> <remove name="LocalSqlServer"/> <add name="LocalSqlServer" connectionString= "Data Source=.;Integrated Security=True;Database=PWS_AspNetDb" /> </connectionStrings>The
Data Sourceparameter in the connection string specifies the instance of the SQL Server, where the databases are attached. By default this is the name of your computer (which can be written shortly using dot "."). When using the SQL Express the default instance name is ".\SQLExpress". TheDatabaseparameter specifies the name of the database, which you can see in the "Object Explorer" in the SQL Server Management Studio. After following these steps, you should be able to run the demo application.Data-access in F#
Most of the ASP.NET technologies used in the web site are used in almost the same way as in C#, so I will not discuss them in larger details, but the last item in the list - the use of ASP.NET data controls together with F# is I believe quite interesting, so I'll write a few notes about it. Let's look for example at the
Photos.aspxfile, which displays a list of photos in a gallery. The most important parts of the file related to data access are shown in the following code snippet:<asp:DataList RunAt="server" DataSourceID="photoSource" EnableViewState="false"> <ItemTemplate> <!-- ... --> <a href='Details.aspx?AlbumID=<%# base.Eval("PhotoAlbumID") %>'> <img src="Handler.ashx?PhotoID=<%# base.Eval("PhotoID") %>&Size=S" class="photo_198" style="border:4px solid white" alt='Thumbnail of Photo Number <%# base.Eval("PhotoID") %>' /> </a> <!-- ... --> </ItemTemplate> </asp:DataList> <asp:ObjectDataSource ID="photoSource" RunAt="server" TypeName="PersonalWebSite.PhotoManager" SelectMethod="GetPhotos"> <SelectParameters> <asp:QueryStringParameter Name="AlbumID" Type="Int32" QueryStringField="albumID" DefaultValue="0"/> </SelectParameters> </asp:ObjectDataSource>The first ASP.NET control used in the code is
asp:DataList, which is a control that simply displays a collection of some items and uses a specifiedItemTemplatefor displaying every single item. In our case we're working with collection of records and the record has several members (includingPhotoIDandPhotoAlbumID). To display a value of a record member in the ASP.NET page we have to use ASP.NETEvalmethod as you can see in the sample. TheEvalmethod reads the specified member of the item in collection and writing the code in<%# ... %>tells ASP.NET that we want to render the result of the expression as a part of the item template. The record that we're using in this example is very simple and has the following structure:type Photo = { PhotoID:int; PhotoAlbumID:int; PhotoCaption:string; }This is actually one of the places where the F# version is shorter, because in C# version you have to write this as a class with properties, which makes the code quite longer.
The second server-side control (
asp:ObjectDataSource) in the first code snippet isn't visual, which means that it will not produce any HTML output. It serves just as a declarative data-source for the data list and the properties of this control specify how the content for the data list should be loaded. There are various other data-source controls in ASP.NET (e.g.asp:SqlDataSourcewhich loads data directly from the database), but the one that we're using in the example uses a specified .NET/F# type and calls a method of the given object when it needs to retrieve the data. In F# this is even easier, because we can use a name of the module and the code that retrieves the data can be a function in the module.As you can see the property
TypeNameis set toPersonalWebSite.PhotoManager, which can be treated as a module calledPhotoManagerin a namespacePersonalWebSiteand theSelectMethodproperty, which specifies a name of the function that will be called when loading the data is set toGetPhotos. Finally, theSelectParametersspecifies that the function expects one argument calledAlbumIDand that the value of this argument should be retrieved from the query string (that is from the URL of formphoto.aspx?albumIdD=42).Now it is pretty easy to implement the module that matches this specifications and can be used as a data source (we could of course use FLinq for loading the data, but I wanted to keep things simple for now, so we're using standard
SqlDataReaderobject from .NET):namespace PersonalWebSite // ... module PhotoManager = // Function will be called by ASP.NET when loading data // for the asp:DataList control in the 'Photos.aspx' page let GetPhotos (albumID:int) = // Open connection & create command use conn = new SqlConnection(" ... ") use cmd = new SqlCommand("GetPhotos", conn) // Can the user see 'private' photos? let usr = HttpContext.Current.User let filter = not (usr.IsInRole("Friends") || usr.IsInRole("Administrators")) cmd.CommandType <- CommandType.StoredProcedure) cmd.Parameters.Add(SqlParameter("@AlbumID", albumID)) |> ignore command.Parameters.Add(SqlParameter("@IsPublic", filter)) |> ignore conn.Open() // Read all photos into a .NET ResizeArray type let list = new ResizeArray<_>() use reader = command.ExecuteReader() while (reader.Read()) do list.Add({ PhotoID = unbox (reader.get_Item("PhotoID")) PhotoAlbumID = unbox (reader.get_Item("AlbumID")) PhotoCaption = unbox (reader.get_Item("Caption")) }) // Return the created collection listI hope this article explained some of the interesting things that you may find in the ASP.NET samples provided with the F# distribution and I think that the Personal WebSite Sample shows that F# can be used for writing quite complicated web applications as well. Of course, my initial motivation for writing web applications in F# is the possibility of using meta-programming to develop client-side code (the code that runs on the client as a JavaScript) in F# too, which makes development of modern "Ajax"-style applications easier, so if you're interested in this project you may want to look at F# Web Tools [1].
Downloads & References