12. WebForms - University of Illinois at Chicago

Download Report

Transcript 12. WebForms - University of Illinois at Chicago

12. WebForms: Web-based
GUIs in .NET
Objectives
“Drag-and-drop GUI construction has long been the norm for
Windows development. With the arrival of ASP.NET and Visual
Studio .NET, the same is now true for web pages with your choice
of .NET language…"
• ASP.NET architecture
• WebForms
• ASP.NET programming model
Visual Studio.NET
2
Part 1
• ASP.NET architecture…
Visual Studio.NET
3
ASP.NET
• ASP.NET is the web-based component of .NET
• ASP.NET is a plug-in for Microsoft's web server IIS
– IIS recognizes extension & routes to ASP.NET for processing
– plug-ins also available for Apache, others (?)
http://server/page.aspx
Browser
HTTP Request
ISAPI Extension
Manager
ASPNET_ISAPI.DLL
ASP.NET ISAPI extension
IIS
Web server
ASP.NET
CLR
ASPNET_WP.EXE
ASP.NET worker process
Visual Studio.NET
4
AppDomains
• Each web app (virtual directory) runs in a separate domain
• An AppDomain is a protection boundary, similar to a process
– this way web apps are isolated from each other…
http://server/AAAPainting/default.aspx
Browser
HTTP Request
ASP.NET
AppDomain
http://server/BooksForYou/default.aspx
Browser
HTTP Request
ASP.NET
AppDomain
CLR
ASPNET_WP.EXE
ASP.NET worker process
Visual Studio.NET
5
Multi-threaded
• Each AppDomain is multi-threaded, to handle multiple clients
Browser
Browser
http://server/AAAPainting/default.aspx
.
.
.
ASP.NET
AppDomain
ASP.NET
Browser
AppDomain
CLR
ASPNET_WP.EXE
ASP.NET worker process
Visual Studio.NET
6
Part 2
• WebForms…
Visual Studio.NET
7
Traditional form-based web apps
• HTML already supports the
creation of form-based apps
<HTML>
<HEAD>
<title>Login</title>
</HEAD>
<BODY>
<h2>Please login:</h2>
<form method="get" action="Main.htm" id="Login">
Username: <INPUT type="text" id="Name"> <BR>
Password: <INPUT type="text" id="pwd"> <BR> <BR>
<INPUT type="submit" value="Login">
</form>
</BODY>
</HTML>
Visual Studio.NET
8
WebForms
• Web-based, form-based .NET apps
• Based on many technologies:
– IIS
– ASP.NET (extension to IIS)
– .NET Framework SDK (CLR, FCL, tools)
– Visual Studio .NET (drag-and-drop creation)
Visual Studio.NET
9
Abstraction
• Like WinForms, WebForms are based on classes in FCL
– separates WebForm app from underlying platform
object
instance of
FCL class
System.Web.UI.Page
CLR
Windows OS
Visual Studio.NET
10
Creating a WebForm app
• Good news: much like creating a WinForm app!
1. create appropriate project in Visual Studio
2. design form(s) via drag-and-drop of controls
3. program events
4. run and test
Visual Studio.NET
11
Example
•
A simple
WebForms
app to view
attendee
info from DB
Visual Studio.NET
12
(1) Create ASP.NET Web App project
• Location = name of web site = "http://localhost/AttendeeApp"
– virtual directory:
AttendeeApp
– physical directory: C:\Inetpub\wwwroot\AttendeeApp
Visual Studio.NET
13
(2) Project layout
• VS .NET configures IIS for you
• VS .NET creates web site for you
– contains 1 form-based web page
– named WebForm1.aspx by default
– web.config allows you to config things
• e.g. debugging
Visual Studio.NET
14
(3) Install application support files
• Manually install needed support files into web app's directory
– in this case "C:\Inetpub\wwwroot\AttendeeApp"
– component DLLs?
– databases?
• Example:
– copy "Attendees.mdb" into root dir
– any custom DLLs in \bin sub-directory
Visual Studio.NET
15
(4) Design WebForm
•
Just like a WinForm
– drag-and-drop from toolbox…
Visual Studio.NET
16
Web controls vs. HTML controls
• Toolbox contains 2 types of controls:
– those under Web Forms
– those under HTML
• Both generate pure HTML on client
– though sometimes with JavaScript!
• Web controls:
– work like WinForm counterparts
• HTML controls:
– mimic standard HTML controls
Visual Studio.NET
17
(5) Implement events
•
WebForms are event-driven, as you would expect:
– standard "code-behind" programming with J#, C#, VB.NET, …
– on Page_Load, fill list box from database
– on Button1_Click, display info about selected attendee
public class WebForm1 extends System.Web.UI.Page
{
private void Page_Load( ...)
{ … }
private void Button1_Click (…)
{ … }
{
Visual Studio.NET
18
Connection String
• Connection String will be used throughout
– Have program ask where the data is located
import System.Data.*;
import System.Data.OleDb.*;
. . .
String get_sConnection()
{
String filename = "Attendees.mdb";
// DB filename
String sConnection = null;
// Find the base directory in which the application is running
String homeDir = System.AppDomain.get_CurrentDomain().get_BaseDirectory();
sConnection = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}{1}",
homeDir, filename);
//System.Diagnostics.Debug.WriteLine(this.sConnection);
// for debugging
return sConnection;
}
Visual Studio.NET
19
Page_Load (part 1)
• Use try-catch to handle errors
private void Page_Load(Object sender, System.EventArgs e)
{
String
sql, fn, ln, name, id;
IDbConnection
dbConn = null;
try
{
// code to connect to database and do read (see next slide…)
}//try
catch(Exception ex)
{
this.lblErrorMsg.set_Text( "Error: " + ex.get_Message() );
}//catch
finally
{
if ((dbConn != null) && (dbConn.get_State() != ConnectionState.Closed))
dbConn.Close();
}//finally
}//load
Visual Studio.NET
20
Page_Load (part 2)
try {
dbConn = new OleDbConnection( get_sConnection() );
dbConn.Open();
sql = "Select * From Attendees Order By LastName Asc, FirstName Asc;";
IDbCommand
dbCmd;
dbCmd = new OleDbCommand(); dbCmd.set_CommandText( sql);
dbCmd.set_Connection( dbConn);
IDataReader dbReader;
dbReader = dbCmd.ExecuteReader();
while (dbReader.Read())
{
id = String.valueOf(dbReader.get_Item("AID"));
fn = String.valueOf(dbReader.get_Item("FirstName"));
ln = String.valueOf(dbReader.get_Item("LastName"));
name = ln + ", " + fn;
// have to add an object, not primitive types
this.ListBox1.get_Items().Add( new ListItem( name, id)); }
}//try
Visual Studio.NET
21
(6) Build
• When you build app, Visual Studio builds a DLL
– recall that ASPNET_WP.EXE is the hosting process
– DLL is placed into bin sub-dir of app's IIS directory
– DLL is loaded into AppDomain upon 1st request
Browser
http://server/AAAPainting/default.aspx
ASP.NET
our DLL
AppDomain
CLR
ASPNET_WP.EXE
ASP.NET worker process
Visual Studio.NET
22
(7) Run!
• You can run from within VS
• You can debug from within VS
• How does it work?
– starts up a session of IE
– attaches debugger to IIS
– displays .aspx page marked as "Start Page" in your project
• right-click on .aspx page you want to start with
• select "Set as Start Page"
– NOTE: to debug, you need administrative rights…
Visual Studio.NET
23
Client-server relationship
• The server contains lots of code
– see physical directory…
– see compiled code in \bin sub-directory…
• But the client sees only HTML!
– "View Source" in browser…
– wow, how does that work?
• Web controls know how to render themselves in HTML…
Visual Studio.NET
24
(8) cmdViewInfo_Click (part 1)
• Ensure an item has been selected from List Box
• Note error handling
private void Button1_Click (Object sender, System.EventArgs e)
{
if (this.ListBox1.get_SelectedItem() == null)
{
// nothing selected
this.lblErrorMsg.set_Text( "Please select an attendee!");
return;
}
String
sql, name, fn, ln, email;
String[]
names;
IDbConnection
IDbCommand
dbConn = null;
dbCmd;
IDataReader dbReader;
// DB connection
// DB sql command, to use above connection
// DB reader, with results from above command
// try .. Catch … finally block as in the Page_Load() method
}
Visual Studio.NET
25
(8) cmdViewInfo_Click (part 2)
1. Retrieve text from Text Box and split into first and last name
2. Use this to build sql query string
try {
// retrieve the Text, not value part
name = (String) this.ListBox1.get_SelectedItem().get_Text();
char delimiter[]={' '};
1.
names = name.Split(delimiter);
// create array of strings from text
ln = names[0];
fn = names[1];
ln = ln.Substring(0, ln.get_Length() - 1);
// remove ',' at end
sql = String.Format("Select Email From Attendees Where FirstName='{0}' and
LastName='{1}';",
2.
fn.Replace("'", "''"), ln.Replace("'", "''"));
// System.Diagnostics.Debug.WriteLine("sql is: " + sql);
// for debugging
// create DB connection from connection string
// …
}//try
Visual Studio.NET
26
(8) cmdViewInfo_Click (part 3)
try {
…
// create DB connection from connection string
dbConn = new OleDbConnection( get_sConnection() );
dbCmd = new OleDbCommand();
// create DB command
dbCmd.set_CommandText( sql);
// set the sql statement for the command
dbCmd.set_Connection( dbConn);
// set the connection to be used for
command
dbConn.Open();
// open the DB connection
dbReader = dbCmd.ExecuteReader();
dbReader.Read();
// read from DB using command
// get a line from DB reader
email = String.valueOf(dbReader.get_Item("Email"));
dbReader.Close();
// extract email field
// close connections
dbConn.Close();
this.TextBox1.set_Text( fn);
// display first name to user
this.TextBox2.set_Text( ln);
// display last name to user
this.TextBox3.set_Text( email);
// display email value from database
}//try
Visual Studio.NET
27
Part 3
• ASP.NET programming model…
Visual Studio.NET
28
ASP.NET programming model
• On the surface WebForms appear like WinForms
• But the programming model is different underneath
– due to ASP.NET
– due to client-server paradigm
Visual Studio.NET
29
#1: Traditional dialog doesn't work
• For example, these do not work:
– MessageBox.Show( )
– form1.Show( )
• Why not?
– think about where form would appear…
• Solutions:
– if you want to tell user something, display via label on page
– if you want to show another page, redirect browser
Visual Studio.NET
30
Web-based dialogs
•
To display a message to user:
private void Button1_Click (...)
{
if (this.ListBox1.SelectedItem == null) { // nothing selected
this.lblErrorMsg.Text = "Please select an attendee!";
return;
}
.
.
.
Visual Studio.NET
31
Web-based exceptions
• Likewise, handle exceptions by displaying messages…
private void Page_Load(...)
{
IDbConnection dbConn = null;
try {
// open connection and access DB, filling list box...
.
.
.
}//try
catch(Exception ex) {
this.lblErrorMsg.set_Text( "Error: " + ex.getMessage());
}//catch
finally {
if ((dbConn != null) && (dbConn.get_State() != ConnectionState.Closed))
dbConn.Close();
}//finally
}
Visual Studio.NET
32
Web-based redirects
• Redirect ASP.NET to a different web page…
private void cmdLogin_Click(...)
{
if (<<valid login>>)
this.get_Response().Redirect("http://...");
else
this.lblErrorMsg.set_Text( "Login failed!");
}
Visual Studio.NET
33
#2: Event ==> round-trip to the server
• There are fewer events to program in WebForms
– primarily Change and Click events only
• Why?
– event code is .NET code, so must be executed by server
– event thus triggers 1 round-trip to server for processing
– an very expensive activity…
1. initial request is posted
2. HTML rendering of page
client
ASP.NET
engine
3. same page is "postedback" for event processing
4. HTML rendering of page
IIS
Visual Studio.NET
34
Example
•
Every button click is a trip to
the server
– watch IE's status bar along
the bottom…
Visual Studio.NET
35
#3: Postbacks
• In general, ASP.NET makes a distinction between:
– first request by client C for web page X
– subsequent "postbacks" of page X by the same client C
1. initial request is posted
2. HTML rendering of page
client
ASP.NET
engine
3. same page is "postedback" for event processing
4. HTML rendering of page
IIS
Visual Studio.NET
36
Interesting side-effects
• Postback concept leads to interesting side-effects…
1. each postback creates a new WebForm object
• why? web apps are stateless…
• example: set breakpoint on Page_Load event
2. yet ASP.NET maintains page state for us
• contents of list box, text boxes, etc.
• example: view source on client, see "__ViewState"
Visual Studio.NET
37
Example 1
• We need to clear error message labels!
private void Page_Load(...)
{
this.lblErrorMsg.set_Text(" ");
.
.
.
Visual Studio.NET
// clear prev msg
38
Example 2
• List box is growing and growing with duplicates!
– click button a few times, look at contents of list box…
• Solution?
– either load list box the first time only, or
– clear and reload list box every time
private void Page_Load(...)
{
this.lblErrorMsg.set_Text(" ");
if (this.get_IsPostBack() ) // list box already loaded!
return;
.
. // first request, load list box from DB
.
Visual Studio.NET
39
#4: AutoPostBack
• Some events aren't posted right away…
– event is "queued" until page is eventually posted back
– example:
• list box doesn't postback when you click on an item
• instead, SelectedIndexChanged event is queued
• to witness, code event to display msg in custom label
• notice that multiple clicks on list box yield one event…
• To force immediate postback?
– set control's AutoPostBack property to true (if it has one)
Visual Studio.NET
40
Example
•
•
Set ListBox's AutoPostBack property to True
Code SelectedIndexChanged event to display attendee's info:
private void ListBox1_SelectedIndexChanged(object sender,
System.EventArgs e)
{
// view attendee's info by executing button click code…
this.Button1_Click(sender, e);
}
•
Note: cleaner solution is to route event directly to Button1_Click()
– click on list box in design mode
– view properties
– click yellow lightning bolt icon to see events
– click on drop-down for SelectedIndexChanged event
– select Button1_Click
Visual Studio.NET
41
#5: Statelessness
• Web apps are stateless, kind of…
• Each page request is a self-contained operation:
• connection is opened
• request is posted
• result is returned
• connection is closed
Visual Studio.NET
42
Implications
• Implications?
– new WebForm object every time, so objects don't have state
– however, UI object state *is* maintained for us by ASP.NET
– static fields in our code still work for duration of AppDomain…
Browser
http://server/AAAPainting/default.aspx
ASP.NET
DLL
static int i;
AppDomain
CLR
ASPNET_WP.EXE
ASP.NET worker process
Visual Studio.NET
43
Solutions?
• Don't try to maintain state, recreate each time
• Use a database
• Ask ASP.NET to do it for you…
– will maintain session state for you (state per client)
– will maintain application state for you (global state)
Visual Studio.NET
44
Example: session state
•
Example:
– for each client, maintain Attendee objects in a hash table…
private void Page_Load(...)
{
if (this.get_IsPostBack() ) return;
Hashtable attendees = new Hashtable(); // create table
this.get_Session().Add( "attendees", attendees); // save ref to table
while (dbReader.Read())
{
.
.
.
attendees[name] = new Attendee(id, name, email);
this.ListBox1.get_Items().Add( new ListItem( name, id))
}
– Change this.get_Session() to this.get_Application() if you
want to store Application state rather than Session state.
Visual Studio.NET
45
Example (cont'd)
• When state is needed, just pull it out of ASP.NET's cache…
private void ListBox1_SelectedIndexChanged(...)
{
Hashtable attendees;
Attendee
a;
name = (String) this.ListBox1.get_SelectedItem().get_Text();
attendees = (Hashtable) this.get_Session().get_Item ("attendees");
// then extract attendee that matches with name
.
.
.
Visual Studio.NET
46
Caveats for stateful apps
• Web apps are stateless for a reason
• Caveats to a stateful design:
– too much state will overload server
– state should be recoverable in case of network/server crash
• ASP.NET will keep state in a database if you ask it to via web.config file
– web farms (n > 1 servers) require special handling
• need to config ASP.NET via web.config file
Visual Studio.NET
47
Summary
• ASP.NET and WebForms are a huge improvement
– compiled, type-checked languages (no more scripting)
– drag-and-drop page creation (no more HTML programming)
– full power of FCL available with IntelliSense
• But it is a different programming model
– yet another adjustment you have to make…
Visual Studio.NET
48
References
• Books:
– J. Sharp et al., Visual J#.NET
– F. Onion, "Essential ASP.NET" (both C# and VB editions)
– D. Sussman et al., "Beginning ASP.NET 1.0 with C#"
– B. Gaster et al., "Fast Track ASP.NET" (C# edition)
• Web sites:
– http://www.asp.net/
– http://www.asp.net/webmatrix/
Visual Studio.NET
49