12. webforms: web-based guis in.net. 2 visual studio.net objectives “drag-and-drop gui...
TRANSCRIPT
2Visual Studio.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
4Visual Studio.NET
Web serverIIS
ISAPI ExtensionManager
ASPNET_ISAPI.DLLASP.NET ISAPI extension
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 (?)
Browser
http://server/page.aspx
HTTP Request
ASPNET_WP.EXEASP.NET worker process
CLR
ASP.NET
5Visual Studio.NET
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…
ASPNET_WP.EXEASP.NET worker process
CLR
AppDomain
ASP.NETBrowser
http://server/AAAPainting/default.aspx
HTTP Request
AppDomain
ASP.NETBrowser
http://server/BooksForYou/default.aspx
HTTP Request
6Visual Studio.NET
Multi-threaded
• Each AppDomain is multi-threaded, to handle multiple clients
ASPNET_WP.EXEASP.NET worker process
CLR
AppDomain
ASP.NET
Browser http://server/AAAPainting/default.aspx
AppDomain
ASP.NET
Browser
.
.
.
Browser
http://server/AAAPainting/default.aspx
http://server/AAAPainting/default.aspx
8Visual Studio.NET
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>
9Visual Studio.NET
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)
10Visual Studio.NET
Abstraction
• Like WinForms, WebForms are based on classes in FCL– separates WebForm app from underlying platform
System.Web.UI.Page
CLR
Windows OS
instance of
FCL classobject
11Visual Studio.NET
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
13Visual Studio.NET
(1) Create ASP.NET Web App project
• Location = name of web site = "http://localhost/AttendeeApp"– virtual directory: AttendeeApp– physical directory: C:\Inetpub\wwwroot\AttendeeApp
14Visual Studio.NET
(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
15Visual Studio.NET
(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
17Visual Studio.NET
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
18Visual Studio.NET
(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 (…)
{ … }
{
19Visual Studio.NET
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;
}
20Visual Studio.NET
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
21Visual Studio.NET
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
22Visual Studio.NET
(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
ASPNET_WP.EXEASP.NET worker process
CLR
AppDomain
ASP.NETBrowserhttp://server/AAAPainting/default.aspx
our DLL
23Visual Studio.NET
(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…
24Visual Studio.NET
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…
25Visual Studio.NET
(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 dbConn = null; // DB connection
IDbCommand dbCmd; // DB sql command, to use above connection
IDataReader dbReader; // DB reader, with results from above command
// try .. Catch … finally block as in the Page_Load() method
}
26Visual Studio.NET
(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[]={' '};
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}';",
fn.Replace("'", "''"), ln.Replace("'", "''"));
// System.Diagnostics.Debug.WriteLine("sql is: " + sql); // for debugging
// create DB connection from connection string
// …
}//try
1.
2.
27Visual Studio.NET
(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(); // read from DB using command
dbReader.Read(); // get a line from DB reader
email = String.valueOf(dbReader.get_Item("Email")); // extract email field
dbReader.Close(); // 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
Create
connection
open, read, c
lose
set displa
y values
29Visual Studio.NET
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
30Visual Studio.NET
#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
31Visual Studio.NET
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; }
. . .
32Visual Studio.NET
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}
33Visual Studio.NET
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!");}
34Visual Studio.NET
#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…
IIS
client
1. initial request is posted
2. HTML rendering of page
3. same page is "posted-back" for event processing4. HTML rendering of page
ASP.NETengine
35Visual Studio.NET
Example
• Every button click is a trip to the server
– watch IE's status bar along the bottom…
36Visual Studio.NET
#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
IIS
client
1. initial request is posted
2. HTML rendering of page
3. same page is "posted-back" for event processing4. HTML rendering of page
ASP.NETengine
37Visual Studio.NET
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"
38Visual Studio.NET
Example 1
• We need to clear error message labels!
private void Page_Load(...){ this.lblErrorMsg.set_Text(" "); // clear prev msg . . .
39Visual Studio.NET
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 .
40Visual Studio.NET
#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)
41Visual Studio.NET
Example
• Set ListBox's AutoPostBack property to True• Code SelectedIndexChanged event to display attendee's info:
• 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
private void ListBox1_SelectedIndexChanged(object sender, System.EventArgs e){ // view attendee's info by executing button click code… this.Button1_Click(sender, e);}
42Visual Studio.NET
#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
43Visual Studio.NET
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…
ASPNET_WP.EXEASP.NET worker process
CLR
AppDomain
ASP.NETBrowserhttp://server/AAAPainting/default.aspx
DLLstatic int i;
44Visual Studio.NET
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)
45Visual Studio.NET
Example: session state• Example:
– for each client, maintain Attendee objects in a hash table…
– Change this.get_Session() to this.get_Application() if you want to store Application state rather than Session state.
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)) }
46Visual Studio.NET
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 . . .
47Visual Studio.NET
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
48Visual Studio.NET
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…