11 Updating a Database Table Textbook Chapter 14.

53
1 1 Updating a Database Table Textbook Chapter 14

Transcript of 11 Updating a Database Table Textbook Chapter 14.

11

Updating a Database Table

Textbook Chapter 14

22

Objectives

You will be able to Write C# code to update a

database table from user input.

3

SQL Injection Attacks

Last class we looked briefly at SQL Injection Attacks.

General defensive measure: scan for single quotes in user input and replace them by pairs of single quotes.

Student Ryan Wheeler informed me of a class of attacks where this measure fails:

SQL Smuggling Attacks

Described in http://www.comsecglobal.com/FrameWork/Upload/SQL_Smuggling.pdf

November 2007

4

SQL Injection Attacks

The "ironclad rule" still applies (all the more so):

Never splice user input into a command string (in ADO.NET).

Use a command parameter instead.

Stored procedures are another effective mechanism applicable to most database systems. Permit the use of parameters. But have some vulnerabilites described in

the SQL Smuggling paper.

5

Overview for Today

We will extend the Address Lookup app from last class to permit the user to update database table entries, delete entries, and add new entries.

6

Getting Started

Download the Address Lookup app from last class:

http://www.cse.usf.edu/~turnerr/Web_Application_Design/Downloads/2012_06_14_In_Class/

Drill down to website folder Rename website folder Address_Update

Open VPN connection if necessary. Open website folder, Address_Update, in Visual

Studio Open web.config and put your own username,

database name, and password into the connection string.

Build and run.

7

Default.aspx

8

App in Action

9

Update

The user can modify the TextBoxes but there is no way to write the updated entries back to the database.

Add an Update button below the table. Initially disabled. Enabled only when something has

been changed.

10

Update Button

11

Update Button Event Handler

Double click on the Update Button to add an event handler.

Fill in a stub.

12

Detect Changes

Double click on one of the result TextBoxes. Visual Studio creates an empty event handler

for TextChanged.

13

Use Same Event Handler for All TextBoxes

Change the name to tbXXX_Text_Changed In Source View add this event handler to all

result TextBoxes. Also set AutoPostBack to True

Set btnUpdate.Enabled to false in btnLookup_Click event handler.

14

Text Changed Event Handlers

Try it!

15

Successful Lookup

Update button is disabled.

Change any textbox.

16

TextBox Changed

What's going on here?

Why did the address disappear?

17

TextBox Changed

There was a postback as soon as we changed an input.

We needed this in order to enable the Update button.

The Page_Load event handler cleared all of the Textboxes.

We wanted this to that results from a previous lookup would not stay on the page after an unsuccessful lookup.

18

Solution

Clear the results in the Lookup button click event handler when the lookup is unsuccessful. Not in Page_Load.

19

New Page_Load

20

New Lookup Button Click Handler

Try again.

21

Zip Code Changed

Click "Update Database"

Modify Zip code.

22

Update Database Clicked

23

Lookup Failure

Try entering address data.

24

Zip Code Modified

Update Database is enabled!

25

A Flaw

26

A Flaw

User should not be able to update the database unless lookup was successful.

Results TextBoxes should be disabled if lookup was unsuccessful. Update Database button should also be

disabled.

27

Updated Lookup Click Handler

28

Disable_Results_TextBoxes

protected void Disable_Results_TextBoxes()

{

tbLastName.Enabled = false;

tbFirstName.Enabled = false;

tbAddress1.Enabled = false;

tbAddress2.Enabled = false;

tbCity.Enabled = false;

tbState.Enabled = false;

tbZipCode.Enabled = false;

}

29

Enable_Results_TextBoxes

protected void Enable_Results_TextBoxes()

{

tbLastName.Enabled = true;

tbFirstName.Enabled = true;

tbAddress1.Enabled = true;

tbAddress2.Enabled = true;

tbCity.Enabled = true;

tbState.Enabled = true;

tbZipCode.Enabled = true;

}

30

Another Flaw

Previous results should be cleared, and the TextBoxes disabled on TextChanged for the Input TextBox. Need AutoPostBack = True

Double click on tbInput to add a TextChanged event handler.

31

tbInput_TextChanged Event Handler

protected void tbInput_TextChanged(object sender, EventArgs e)

{

Clear_Results();

btnUpdate.Enabled = false;

Disable_Results_TextBoxes();

}

Try it!

End of Section

32

Now the Real Work

Add code to class Query to update the database.

Will need a SQL Update command. Recall the Introduction to ADO.NET.

http://www.cse.usf.edu/~turnerr/Web_Application_Design/072_Working_with_MS_SQL_Server.pdf

Slide 46

33

Updating Multiple Fields

http://www.cse.usf.edu/~turnerr/Web_Application_Design/072_Working_with_MS_SQL_Server.pdf

Slide 46

34

A Design Dilemma

Class Address knows nothing about SQL or ADO.NET.

Class Query knows about SQL and ADO.NET Knows no details about class Address

Where should we put the SQL Update function?

Has to know details of both class Address and ADO.NET.

35

SQL Update Command

Let's put the Update function in class Query. Keep class Address pure.

Class Query already depends on class Address. Has function Get_Address. Knows the table name. Knows column Last_Name

Add function Update_Address to class Query. Small increase in dependency on class Address.

36

Function Update_Address

Pass in an updated Address object. Note that the ID cannot change. Everything else can change.

Set up a connection to the database server just as we did for Get_Address.

Set up a command object to do the update. Use ID field to specify table row to be updated. Set all other row items to the Address object

property values, using command parameters.

37

The Update Function

Create a SqlConnection object. Create a SqlCommand object. Set its Connection Property Set its CommandText property to

the string for an UPDATE command. Use parameters for all table values. Use Address ID in the "where" clause.

Invoke the command object's ExecuteNonquery method.

Should affect exactly one row.

38

Function Update_Addresspublic static void Update_Address( Address adr,

out string error_msg)

{

SqlConnection cn = null;

error_msg = "";

try

{

cn = Setup_Connection();

int nr_rows_affected = Perform_Update(cn, adr);

if (nr_rows_affected != 1)

{

error_msg = "ERROR: Nr rows affected was " +

nr_rows_affected;

}

}

...

39

Function Update_Address (continued)

...

catch (Exception ex)

{

error_msg = "ERROR updating table Addresses: " +

ex.Message;

}

finally

{

if (cn != null)

{

cn.Close();

}

}

}

40

Function Perform_Update

private static int Perform_Update(SqlConnection cn,

Address adr)

{

string cmd_str = "UPDATE Addresses " +

"SET Last_Name=@Last_name, " +

"First_Name=@First_name, " +

"Address1=@Address1, " +

"Address2=@Address2, " +

"City=@City, " +

"State=@State, " +

"Zip_Code=@Zip_code " +

"WHERE ID=" + adr.Id;

SqlCommand cmd = new SqlCommand();

cmd.Connection = cn;

cmd.CommandText = cmd_str;

...

41

Function Perform_Update (continued)

cmd.Parameters.AddWithValue("@Last_name", adr.Last_name);

cmd.Parameters.AddWithValue("@First_name", adr.First_name);

cmd.Parameters.AddWithValue("@Address1", adr.Address1);

cmd.Parameters.AddWithValue("@Address2", adr.Address2);

cmd.Parameters.AddWithValue("@City", adr.City);

cmd.Parameters.AddWithValue("@State", adr.State);

cmd.Parameters.AddWithValue("@Zip_code", adr.Zip_code);

int nr_rows_affected = cmd.ExecuteNonQuery();

return nr_rows_affected;

}

Build, but don't run.

(We still don't have a call to Update_Address.)

42

The hardest part is done!

But we have to pass an updated Address object to function Update_Address from the click event handler for btnUpdate.

Where do we get the Address object? Where do we update its values?

43

The Address Object

We might save the original Address object in ViewState. Must mark the class as "Serializable"

Textbook page 259. We DO NOT have to provide the function to

serialize the object.

Update it from the TextBoxes when the user clicks the Update Database button.

44

The Address Object

We have updated values for all of the properties of the Address object in the results TextBoxes. Everything except the ID.

These values are automatically preserved in the ViewState.

We could reconstruct the Address object, with the updated values, from the contents of the TextBoxes.

45

The Address Object

We need a new constructor for class Address.

ID as parameter. Initialize all fields as blank.

Use the public properties to set the fields.

Preserve just the ID as explicit member of ViewState

46

Class Address

New constructor:

public Address(int ID)

{

id = ID;

last_name = "";

first_name = "";

address1 = "";

address2 = "";

city = "";

state = "";

zip_code = "";

}

47

Persist ID in ViewStateIn Default.aspx.cs

protected void btnLookup_Click(object sender, EventArgs e)

{

string error_msg;

Address adr = Query.Get_Address(tbInput.Text,

out error_msg);

if (adr == null)

{

Clear_Results();

Disable_Results_TextBoxes();

ViewState["ID"] = null;

}

else

{

Display_Results(adr);

Enable_Results_TextBoxes();

ViewState["ID"] = adr.Id;

}

lblMessage.Text = error_msg;

btnUpdate.Enabled = false;

}

48

Button Update Click Handlerprotected void btnUpdate_Click(object sender, EventArgs e)

{

string error_msg = "";

int id = (int)ViewState["ID"];

Address adr = new Address(id);

// Update the Address object from the TextBoxes.

adr.Last_name = tbLastName.Text;

adr.First_name = tbFirstName.Text;

adr.Address1 = tbAddress1.Text;

adr.Address2 = tbAddress2.Text;

adr.City = tbCity.Text;

adr.State = tbState.Text;

adr.Zip_code = tbZipCode.Text;

Query.Update_Address(adr, out error_msg);

lblMessage.Text = error_msg;

btnUpdate.Enabled = false;

}

Try it!

49

Successful Lookup

Change Zip Code to 33619.

50

Zip Code Modified

Click Update Database.

51

Check the Database Table

52

Summary

We used ViewState to hold the Addess ID across postbacks. All other information for the current Address

is automatically preserved in ViewState

The user can update any part of the address in a TextBox.

When the user asks to update the database we first reconstruct the Address object from the TextBoxes then pass the updated object to a function that updates the database table.

53

Summary Minimal Coupling

Class Default is responsible for the user interface. Knows nothing about SQL. Knows the public methods of class Query. Knows the public methods and properties of class Address.

Class Query is responsible for SQL operations. Knows the public methods and properties of class Address. Knows nothing about the user interface. Could be used in other apps or PC programs that use table

Addresses.

Class Address provides an object oriented interface to database table Addresses.

Knows nothing about the user interface. Knows how to use a SqlDataReader.