This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Add a New Record: | ")) Else me.Controls.Add(new LiteralControl("Edit Record: | ")) End if me.Controls.Add(new LiteralControl("||
")) me.Controls.Add(new LiteralControl(c.ToString)) me.Controls.Add(new LiteralControl(" | ")) 'Wert me.Controls.Add(new LiteralControl("")) Dim Box As New TextBox Benutzerdefinierte Kontrollen 7 Box.Text = r(c).ToString Box.ID = c.ToString me.Controls.Add(box) me.Controls.Add(new LiteralControl(" | ")) end if FieldsCount = FieldsCount + 1 Next c Next r Else ' Insert Mode For Each c in t.Columns IF vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField then Else me.Controls.Add(new LiteralControl("||
")) me.Controls.Add(new LiteralControl(c.ToString)) me.Controls.Add(new LiteralControl(" | ")) 'Wert me.Controls.Add(new LiteralControl("")) Dim Box As New TextBox Box.ID = c.ToString me.Controls.Add(box) me.Controls.Add(new LiteralControl(" | ")) End if FieldsCount = FieldsCount + 1 Next c End If me.Controls.Add(new LiteralControl("
) eingeschlossen. Die Markierungen der Benutzerdefinierte Kontrollen 7 Tabellen (
Benutzerdefinierte Kontrollen 7 Dim vdisplay As string vDisplay = Display + "000000000000000000000000000000000000000" FieldsCount = 0 s = "Execute " + procedure + "" If mode = "update" then For Each r in t.Rows For Each c in t.Columns IF vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField then Else Dim tb As TextBox tb = me.FindControl(c.ToString) column = c.ToString Value = tb.text If c.DataType.ToString = "System.String" Then s = s + " @" + column + "='" + value + "', " Else s = s + " @" + column + "=" + value + ", " End If End IF FieldsCount = FieldsCount + 1 Next c Next r s = s + "@" + KeyField + "=" + KeyValue me.Controls.Add(new LiteralControl(s)) RunSql(s) Else For Each c in t.Columns IF vdisplay.chars(FieldsCount) = "0" or c.ToString = KeyField then Else Dim tb As TextBox tb = me.FindControl(c.ToString) column = c.ToString Value = tb.text If c.DataType.ToString = "System.String" Then s = s + " @" + column + "='" + value + "', " Else 205 ASP.NET 206 7 s = s + " @" + column + "=" + value + ", " End If End IF FieldsCount = FieldsCount + 1 Next c s = s + "@" + KeyField + "=NULL" me.Controls.Add(new LiteralControl(s)) RunSql(s) End if End Sub Sub RunSql(vSql as string) try Dim s As string Dim myConnection As OleDbConnection myConnection = New OleDbConnection(ConnStr) Dim mycommand As New OleDbCommand(vsql,myConnection) myconnection.Open() myCommand.ExecuteNonQuery() myconnection.Close() Catch ex As OleDbException 'SQL-Fehler Dim errItem As OleDbError Dim errString As String Dim s As string For Each errItem In ex.Errors errString += ex.Message + "" Next s = "SQL Error.Details follow:" & errString me.Controls.Add(new LiteralControl(s)) Catch myException as Exception me.Controls.Add(new LiteralControl("Exception: " + myException.ToString())) End try End Sub End Class End Namespace Benutzerdefinierte Kontrollen 7 Benutzung der benutzerdefinierten GenEditAdd-Kontrolle In diesem Abschnitt erkläre ich Ihnen, wie Sie die GenEditAddKontrolle an ein Datengitter (DataGrid) anhängen und zum Hinzufügen, Editieren oder Löschen von Datensätzen in der Masters-Tabelle (Haupttabelle) benutzen können. Den Code zu diesen Erläuterungen finden Sie auf der CD des Buches. Jedes DataGrid, das diese Kontrolle benutzt, benötigt eine Konfigurationsdatei (config-Datei). In diesem Beispiel wird hierzu die bereits früher im Kapitel diskutierte config_masters.aspx-Datei verwendet. Das DataGrid der Webpage masters.aspx benötigt zwei Hyperlinkspalten für den Add- und den Edit-Modus (Hinzufügen und Editieren). Die Hyperlinks navigieren zur Konfigurationsdatei und geben im Fall des Add-Modus einen Codewert von 0 oder einen gültigen primären Schlüssel im Fall des Editiermodus weiter: Listing 7.12: Masters.aspx Hier die komplette Codeliste der Masters.aspx-Datei: Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet 207 ASP.NET 208 7 Dim ConnStr As String Dim SQL As String Sub Page_Load(Source As Object, E As EventArgs) ConnStr = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;" myConnection = New OleDbConnection(ConnStr) if NOT (isPostBack) rebind end if End Sub Sub ReBind() 'DataSet-Befehl SQL = "select m.*, g.code_display as category " SQL = SQL + "from masters m, groups g " SQL = SQL + " where m.code_category = g.code_value" myCommand = New OleDbDataAdapter(SQL, myConnection) 'Benutzen der Fill-Methode des DataSetCommand, um einen Datensatz zu füllen myCommand.Fill(ds, "masters") 'Bindung eines Datengitters Grid1.DataSource=ds.Tables("masters").DefaultView Grid1.DataBind() End Sub Sub RunSql(sql as string) ' Control Validator-Fehler finden if not page.isvalid then response.write("Stored Procedure did not execute") rebind exit sub end if try Dim mycommand2 As New OleDbCommand(sql,myConnection) myconnection.Open() myCommand2.ExecuteNonQuery() myconnection.Close() 'Editiermodus deaktivieren Grid1.EditItemIndex = -1 Catch ex As OleDbException 'SQL-Fehler Dim errItem As OleDbError Benutzerdefinierte Kontrollen 7 Dim errString As String For Each errItem In ex.Errors errString += ex.Message + "" Next Response.write( "SQL Error.Details follow:" & errString) Catch myException as Exception Response.Write("Exception: " + myException.ToString()) End try rebind End Sub Sub Grid1_delete(sender As Object, e As DataGridCommandEventArgs) Dim code_value As string = Grid1.DataKeys.Item(E.Item.ItemIndex).ToString Dim sql As string sql = "Delete from masters where code_value = " + cstr(code_value) RunSql(sql) End Sub Masters DataGrid 1 Chart of Accounts: Benutzerdefinierte Kontrollen 7 Zusammenfassung Die in diesem Kapitel erstellte GenEditAdd-Komponente ermöglicht es Ihnen, einem DataGrid Editier- und Eingabe-Funktionalität zu verleihen und damit eine Lücke im Datengitter zu füllen. Diese Kontrolle ersetzt auch den Editiermodus des DataGrid (der nicht automatisiert war und die Programmierung einer Reihe von Events erforderlich machte). Während der Erstellung der Kontrolle wurde die Theorie der Entwicklung benutzerdefinierter Kontrollen erläutert. 211 Business-Objekte Eine einfache Komponente in C# 218 Aufteilung von Diensten zwischen Webformularen und Komponenten 219 Eine Datenbank-Klasse 221 Zusammenfassung 233 ASP.NET 214 8 Business-Objekte sind eine Bibliothek von Funktionen und Klassen, die in jedem beliebigen Projekt benutzt werden können. Allgemein verwendeter Code wird in einem Business-Objekt eingeschlossen. Dieses Objekt dient als Service-Klasse für ein anderes Objekt. Es wird je nach Bedarf integriert und zerstört, wenn es nicht mehr gebraucht wird. Ein Business-Objekt hat keine Benutzeroberfläche. Das bin-Verzeichnis Wenn Sie in der Vergangenheit bereits COM-Objekte entwickelt haben, wissen Sie, wie schwer die Registrierung der Komponenten ist. Eine Komponente musste mit Hilfe der regsvr32.exe-Utility registriert werden. Wenn die Komponente modifiziert wurde, musste der ganze Webserver angehalten werden, um die Komponente zu registrieren. ASP.NET hat diesen Prozess vereinfacht. Die Komponenten werden einfach kopiert und in das bin-Verzeichnis eingefügt. Registryupdates sind nicht erforderlich, und um die Komponente zu entfernen, genügt es, diese aus dem bin-Verzeichnis zu löschen. Die ursprünglichen Komponenten können sogar ersetzt werden, während der Webserver in Betrieb ist. ASP.NET ermöglicht es, alle existierenden Anfragen zu komplettieren und alle neuen Anfragen an die neue Komponente weiterzuleiten. Namensfelder und Zusammensetzungen Entwickler haben die Möglichkeit, interne Codekomponenten zu Namensfeldern (Namespaces) zu gruppieren (Klassen und Benutzeroberflächen). Durch diese logische Organisation wird eine Kollision mit von anderen Entwicklern geschriebenen Klassen verhindert. Ein Namensfeld enthält eine Abkürzung als Bezug zu einem längeren Klassennamen. Die Imports-Direktive (in Visual Basic.NET) und der using-Befehl (in C#) sind Kürzel, die es Ihnen erlauben, Namensfelder zu benutzen, ohne einen kompletten Pfad eingeben zu müssen. Die Metadaten (metadata) eines Objekts zeichnen alle für dessen Verwendung benötigten Informationen auf. Im Allgemeinen enthalten diese Informationen den Namen des Objekts sowie die Namen aller seiner Felder, deren Typ und Details zu allen eingeschlossenen Funktionen einschließlich Art und Name der Parameter. Business-Objekte 8 Eine Zusammensetzung (Assembly) ermöglicht es, Anwendungen in einer umfassenden Einheit zu bündeln. Der vom .NETCompiler kompilierte Code wird in eine Zwischenform namens IL (Intermediate Language) gebracht. Eine Zusammensetzung enthält alle IL, die Metadaten und andere benötigte Dateien. Jede Zusammensetzung (Assembly) beinhaltet ein Register, das alle Informationen bezüglich seiner Identität (Name und Versionsinformation) und weiterer enthaltener Dateien bietet. Ein einfaches Business-Objekt in Visual Basic Im Folgenden wird nun ein einfaches Objekt mit einer Eigenschaft und einer Methode erstellt. Der Benutzer spezifiziert die Message-Eigenschaft und die Test-Methode gibt diese an das aufrufende Formular zurück. Der Quellcode für dieses Beispiel befindet sich auf der CD des Buches 1 Erstellung der Komponente Imports System Imports System.Text Imports Microsoft.VisualBasic Namespace BasicObjVb Public Class BasicVb Private ls_message as string Public Sub New() MyBase.New() ls_message = "" End Sub Public Property message as string Get Return ls_message End Get Set ls_message = value End Set End Property Public Function test() as string Dim SB As StringBuilder SB = New StringBuilder(ls_message) SB = SB.Append("..returned from function test") test = SB.ToString() 215 ASP.NET 216 8 End Function End Class End Namespace Dies Klasse wird BasicVb genannt und befindet sich im Namensfeld BasicObjVb. Sie hat eine Eigenschaft namens Message, die gewöhnlich die Methoden Set und Get sowie eine lokale Variable Is_message enthält. In einer Eigenschaftssyntax wird die Get-Methode verwendet, um die in der lokalen Variablen gespeicherten Werte an das aufrufende Objekt zurückzugeben, während das aufrufende Objekt mit der Set-Methode an diese Eigenschaft sendet. Zu dem Objekt gehört ein Constructor-Event. Dies ist die Subfunktion new(). Das Constructor-Event wird ausgelöst, wenn das Objekt erstellt wird. Die lokale Variable Is_message wird in diesem Event an einem einzigen Platz initiiert. Hinzu kommt noch eine Test-Funktion, die einen String zurückgibt. Ich benutze die StringBuilder-Klasse, um den zurückgegebenen String zu erstellen. Diese Klasse bietet verschiedene Methoden zur Manipulation des Strings. Einige dieser Methoden sind Append, Replace, Remove und ToString (Anhängen, Ersetzen, Entfernen, ToString). Ich weise dem StringBuilder die MessageEigenschaft zu und benutze dann dessen Append-Methode (Anhängen), um einen weiteren String hinzuzufügen. 2 Kompilieren des Objekts Dies geschieht durch Ausführen des folgenden DOSBefehls: vbc /t:library /out:g:\aspnetsamples\bin\BasicObjVb.dll BasicObj.vb 3 Erstellen eines Webformulars Erstellen Sie nun ein Webformular, um die Komponente zu testen. Abbildung 8.1 zeigt das Ergebnis: Business-Objekte 8 217 Listing 8.1: BasicObj.aspx Sub Page_Load(Sender As Object, E As EventArgs) Dim s As string Dim Comp As BasicVb Comp = New BasicVb() Comp.Message = "Hello World" s = Comp.test() response.write(s) End Sub In diesem Webformular wird das BasicObjVb-Namensfeld mit der Import-Direktive importiert. Dann wird eine Komponente des Typs BasicVb deklariert und Hello World der zugehörigen Message-Eigenschaft zugewiesen. Ich rufe die Test-Funktion auf und erhalte einen String, den ich in der lokalen Variable s speichere. Zum Schluss benutze ich response.write, um den String für den Browser zu rendern. Ein einfaches BusinessObjekt Abb. 8.1 ASP.NET 218 8 Eine einfache Komponente in C# Als Nächstes werden Sie lernen, das gleiche Objekt in C# zu erstellen. Der Quellcode für dieses Beispiel befindet sich im Unterverzeichnis ..\basic\c auf der CD des Buches. 1 Erstellen der Komponente Listing 8.2: BasicObjC.cs namespace BasicObjC { using System; using System.Text; public class BasicC{ private String ls_message; public BasicC() { //constructor ls_message = null; } public string message { get { return ls_message; } set { ls_message = value; } } public String test() { StringBuilder SB = new StringBuilder(ls_message); SB.Append(" From test function..."); return SB.ToString(); } } //class } //namespace Abgesehen von der geänderten Syntax ähnelt die Programmierung eines Objekts in C# dem gleichen Vorgang in Visual Basic. Beachten Sie, dass in diesem Fall Business-Objekte 8 die öffentliche Methode (public) BasicC() der Constructor ist. Diese öffentliche Methode trägt den gleichen Namen wie die Klasse. 2 Kompilieren des Objekts Führen Sie die bat-Datei BasicObjC.bat aus, die die folgenden DOS-Befehle enthält: csc /t:library /out:g:\aspnetsamples\bin\BasicObjC.dll BasicObjC.cs Hierdurch wird die DLL-Datei im bin-Ordner platziert. 3 Erstellen des Webformulars Erstellen Sie nun ein aspx-Formular, um die Kontrolle zu testen. Listing 8.3: BasicObjC.aspx public void Page_Load(Object sender, EventArgs E) { BasicC comp = new BasicC(); comp.message = "Hello World"; String s = comp.test(); display.InnerHtml = s; } A Simple C# Component Object Output: Aufteilung von Diensten zwischen Webformularen und Komponenten Die typische Aufgabe eines Webformulars besteht darin, HTML- oder XML-Seiten für den Browser zu rendern. Könnte man die Webformulare vielleicht als Business-Objekte bezeichnen, da sie sich auf dem Server befinden? In einer Umge- 219 ASP.NET 220 8 bung aus Komponenten wäre die Antwort sicherlich negativ. Ein Webformular enthält die Präsentations- und Business-Logik auf der gleichen Seite. Ein Business-Objekt jedoch besitzt keine Präsentationselemente. Man könnte es als ein Objekt betrachten, das Dienstleistungen an ein anderes Formular liefert. Als guter Dienstleister wird es immer dann aufgerufen, wenn es benötigt wird, und anschließend wieder deaktiviert. Diese Service-Analogie ist auch der Grund dafür, dass Business-Objekte als Service-Klassen eingestuft werden. Die Anwendung von Business-Objekten bietet eine Reihe von Vorteilen. Einige davon sind im folgenden Abschnitt aufgeführt: Unterstützt Verkapselung: Sie schließen häufig genutzte Funktionen in ein Objekt ein und zeigen nur die Eigenschaften und Methoden an. Die meisten Webformulare erfordern beispielsweise einen Datenbankzugang und Verarbeitungsroutinen. Anstatt in jeder Seite ein Skript für die Datenbank-Verbindungsroutinen zu schreiben, können Sie ein Business-Objekt erstellen, das Ihnen diese Arbeit abnimmt. Das Objekt zeigt die Eigenschaften und Methoden an und der Benutzer muss nichts über die inneren Arbeitsweisen erfahren. Einfache Wartung: Ein in einem Business-Objekt verkapselter Code ist einfacher zu warten als ein Code, der über mehrere Seiten verteilt ist. Bei Änderungen müssen Sie lediglich das Business-Objekt modifizieren, während der Konsument des Objekts ähnlich wie bei kaskadenartigen Style-Sheets überhaupt nichts tun muss. Wenn Sie beispielsweise die Definition eines H1Tags (Vorzeichen) ändern wollen, müssen Sie dies lediglich an einer Stelle erledigen, da die Änderung anschließend kaskadenartig auf alle Seiten übergeht, die dieses Vorzeichen benutzen. Verbesserung durch wiederholten Gebrauch: Einer der fundamentalsten Vorteile besteht darin, dass der Code durch häufigen Gebrauch und Verfeinerung verbessert wird. Je mehr Benutzer das Objekt testen, desto öfter wird der Debug-Prozess (Fehlererkennung und Behebung) durchlaufen und der Code immer weiter verbessert. Durch die wiederholte Nutzung des Codes Business-Objekte 8 sind Entwickler in der Lage, sich eine Bibliothek von getesteten und bewährten Funktionen aufzubauen, die sie mit anderen Entwicklern teilen können. Eine Datenbank-Klasse In diesem Abschnitt werden Sie lernen, wie man eine Datenbank-Klasse erstellt. Die Klasse enthält häufig genutze Funktionen für die Arbeit mit einer Datenbank. Sie enthält Eigenschaften zur Definition eines Datenbank-Verbindungsstrings und gibt dem Objekt ein SQL-Statement, das auf die Datenbank angewendet wird. Das SQL-Statement kann Daten zurückgeben (wie in einem SELECT-Statement) oder Aktionsabfragen wie Aktualisieren, Einfügen und Löschen ausführen und gespeicherte Prozeduren aufrufen, die keine Daten zurückgeben. Die erste Methode gibt eine Datenansicht (DataView) zurück, die zur Bindung einer Kontrolle genutzt werden kann. Die zweite Methode ist eine generische Funktion zur Anwendung von Aktions-SQL-Statements auf Datenbanken. Sie werden lernen, die Klasse zunächst in Visual Basic.NET und dann in C# zu erstellen. Die Datenbank-Klasse in Visual Basic.NET Beginnen Sie mit der Erstellung der Komponente in Visual Basic.NET. Der Quellcode für dieses Beispiel befindet sich im Unterverzeichnis ...\SQLClass\SqlClassvb auf der CD des Buches. 1 Die SQL-Eigenschaft: Dies ist der SQL-String, der vom Benutzer an dieses Objekt weitergegeben wird. Der String kann aus jedem gültigen SQL-Statement bestehen. Er wird durch die Set- und die Get-Methode definiert und besitzt eine zugewiesene lokale Variable Is_sql. Private ls_sql as string Public Property SQL as string Get Return ls_sql End Get Set ls_sql = value 221 ASP.NET 222 8 End Set End Property 2 Die ConnStr-Eigenschaft: Diese Eigenschaft wird vom Benutzer an den Verbindungs-String weitergegeben. Er wird mit Hilfe der Set- und Get-Methoden und einer lokalen Variablen Is_connstr implementiert. Private ls_ConnStr as string Public Property ConnStr as string Get Return ls_ConnStr End Get Set ls_ConnStr = value End Set End Property 3 Die Funktion Populate: Diese Funktion gibt eine Datenansicht (DataView) zurück, die zur Bindung einer Kontrolle genutzt werden kann. Public Function Populate() As DataView Dim dv As DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "vTable") Populate = ds.Tables("vTable").DefaultView End Function 4 Funktion RunSQL: Diese Funktion haben Sie bereits in einem früheren Kapitel kennen gelernt. Es handelt sich hierbei um eine generische Funktion, die zur Anwendung einer Aktionsabfrage an eine Datenbank genutzt werden kann. Aktionsanfragen geben keine Daten zurück. Sie können diese Funktion auch zur Ausführung gespeicherter Prozeduren, die keine Daten zurückgeben, verwenden, indem Sie diese mit dem execute-Statement aufrufen (execute = ausführen). So Business-Objekte 8 führt zum Beispiel das Statement Execute p_masters parameter a, parameter b, etc die gespeicherte Prozedur p_masters aus. p_masters könnte zum Beispiel eine Prozedur sein, die eine Zeile in die Haupttabelle einfügt. Function RunSql(vsql as string) as String Dim Message As string try Dim myConnection As OleDbConnection myConnection = New OleDbConnection(ConnStr) Dim mycommand As New OleDbCommand(vsql,myConnection) myconnection.Open() myCommand.ExecuteNonQuery() myconnection.Close() Catch ex As OleDbException Dim errItem As OleDbError Dim errString As String For Each errItem In ex.Errors errString += ex.Message + " " Next Message = "SQL Error.Details follow:" & errString Catch myException as Exception message = "Exception: " + myException.ToString() End try RunSql = message End Function 5 Die Contructor-Funktion: Die Contructor-Funktion wird bei jeder Initiierung eines Objekts gestartet. Zwei Eigenschaften werden in die freien Felder der Funktion eingefügt. Public Sub New() MyBase.New() ls_sql = "" ls_ConnStr = "" End Sub Hier kommt die komplette Codeliste der Datenbank-Klasse: 223 ASP.NET 224 8 Listing 8.4: SQLClass.vb Imports System Imports System.Data Imports System.Data.OleDb Imports System.Text Namespace SQLNameSpace Public Class SQLClass Private ls_sql as string Private ls_ConnStr as string Public Sub New() MyBase.New() ls_sql = "" ls_ConnStr = "" End Sub Public Property SQL as string Get Return ls_sql End Get Set ls_sql = value End Set End Property Public Property ConnStr as string Get Return ls_ConnStr End Get Set ls_ConnStr = value End Set End Property Public Function Populate() As DataView Dim dv as DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "vTable") Populate = ds.Tables("vTable").DefaultView End Function Public Function test() as string Business-Objekte 8 Dim SB As StringBuilder SB = New StringBuilder(ls_sql) SB = SB.Append("..returned from function test") test = SB.ToString() End Function Function RunSql(vsql as string) as String Dim Message As string try Dim myConnection As OleDbConnection myConnection = New OleDbConnection(ConnStr) Dim mycommand As New OleDbCommand(vsql,myConnection) myconnection.Open() myCommand.ExecuteNonQuery() myconnection.Close() Catch ex As OleDbException Dim errItem As OleDbError Dim errString As String For Each errItem In ex.Errors errString += ex.Message + " " Next Message = "SQL Error.Details follow:" & errString Catch myException as Exception message = "Exception: " + myException.ToString() End try RunSql = message End Function End Class End Namespace Kompilieren der Datenbank-Klasse Zur Kompilierung der Datenbank-Klasse in eine DLL steht Ihnen eine bat-Datei zur Verfügung. Die Codeliste der Datei SQLClass.bat sieht folgendermaßen aus: set outdir=g:\aspnetsamples\bin\SQLClass.dll set assemblies=System.dll,System.Web.dll,System.Data.dll,Sys tem.XML.dll vbc /t:library /out:%outdir% /r:%assemblies% SQLClass.vb pause 225 ASP.NET 226 8 Diese Datei kompiliert die SQLClass.dll und platziert diese im bin-Ordner. Testen der Datenbank-Klasse Das vorgegebene Webformular dient zum Testen der Funktionalität der Datenbank-Klasse. Abbildung 8.2 zeigt das Ergebnis. Test der DatenbankKlasse Abb. 8.2 Der dazugehörige Code sieht folgendermaßen aus: Listing 8.5: TestVbClass.aspx Dim Comp As SQLClass Dim ConnStr As String Dim SQL As String Sub Page_Load(Source As Object, E As EventArgs) Comp = New SQLClass() Comp.ConnStr = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) rebind end if Business-Objekte 8 End Sub Sub Show_Click(Sender As Object, E As EventArgs) Message.Text = "Masters Table Displayed... " ReBind End Sub Sub Insert_click(Sender As Object, E As EventArgs) sql = "Insert into Masters(code_display,code_category,type)" sql = sql + "Values ('test',701,'E')" Comp.RunSql(sql) rebind Message.Text = "Inserted test record... " End Sub Sub Delete_click(Sender As Object, E As EventArgs) sql = "delete from masters where code_display = 'test'" Comp.RunSql(sql) rebind Message.Text = "Deleted all test records..." End Sub Sub Update_Click(Sender As Object, E As EventArgs) sql = "UPDATE Masters Set Opening = 90 WHERE code_display = 'test'" Comp.RunSQL(sql) rebind Message.Text = "Updated all test records: Set closing balance = 90...! " End Sub Sub ReBind() Comp.SQL = "select * from Masters" DataGrid1.DataSource=Comp.populate() DataGrid1.DataBind() End Sub A DataBase Class in Visual Basic 1 Initiierung des Objekts: Das Objekt wird im page_load- Event des Webformulars initiiert. Der folgende Verbindungsstring wird an das Objekt weitergegeben: Sub Page_Load(Source As Object, E As EventArgs) Comp = New SQLClass() Comp.ConnStr = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) rebind end if End Sub 2 Die ReBind-Funktion gibt eine SQL-Anfrage an das Objekt weiter und bindet ein DataGrid an die vom Objekt auf folgende Weise zurückgegebene Datenansicht (DataView): Sub ReBind() Comp.SQL = "select * from Masters" DataGrid1.DataSource=Comp.populate() DataGrid1.DataBind() End Sub 3 Das Insert_click-Event führt ein Eingabe-Statement (Insert) in der Datenbank mit Hilfe der RunSQL-Funktion aus. Sub Insert_click(Sender As Object, E As EventArgs) sql = "Insert into Masters(code_display,code_category,type)" sql = sql + "Values ('test',701,'E')" Business-Objekte 8 Comp.RunSql(sql) ReBind Message.Text = "Inserted test record... End Sub 4 " Das Update_Click-Event führt ein Update-Statement (Aktualisieren) in der Datenbank mit Hilfe der RunSQLFunktion aus. Sub Update_Click(Sender As Object, E As EventArgs) sql = "UPDATE Masters Set Opening = 90 WHERE code_display = 'test'" Comp.RunSQL(sql) ReBind Message.Text = "Updated all test records: Set closing balance = 90...! " End Sub 5 Das Delete_click-Event führt ein Lösch-Statement (delete) mit Hilfe der RunSQL-Funktion aus. Sub Delete_click(Sender As Object, E As EventArgs) sql = "delete from masters where code_display = 'test'" Comp.RunSql(sql) ReBind Message.Text = "Deleted all test records..." End Su Die Datenbank-Klasse in C# Der folgende Abschnitt enthält eine komplette Codeliste der Datenbank-Klasse in C#. Abgesehen von der geänderten Syntax gleicht die Klasse der im vorigen Abschnitt beschriebenen Klasse in Visual Basic.NET, so dass der Code hier nicht noch einmal ausführlich erläutert werden muss. Der Quellcode für dieses Beispiel befindet sich im Unterverzeichnis ...\Sql\Class\SqlClassC auf der CD des Buches. 229 ASP.NET 230 8 Listing 8.6: SQLClassC.cs namespace SQLNameSpaceC { using System; using System.Data; using System.Data.OleDb; using System.Text; public class SQLClassC { private String ls_connStr; private String ls_sql; public String ConnStr { get { return ls_connStr; } set { ls_connStr = value; } } public String SQL { get { return ls_sql; } set { ls_sql = value; } } public DataView Populate() { //for queries that return data //and for binding controls OleDbConnection myConnection = new OleDbConnection(ConnStr); OleDbDataAdapter myCommand = new Business-Objekte 8 OleDbDataAdapter(SQL, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "vTable"); return ds.Tables["vTable"].DefaultView; } public String RunSQL( string vsql) { try { OleDbConnection myConnection = new OleDbConnection(ConnStr); OleDbCommand mycommand = new OleDbCommand(vsql, myConnection); myConnection.Open(); mycommand.ExecuteNonQuery(); myConnection.Close(); } catch(Exception e) { string ret = "Exception: " + e.ToString() ; } return("OK"); } public String test() { StringBuilder SB = new StringBuilder(ls_connStr); SB.Append(" ," + ls_sql); return SB.ToString(); } } } Kompilieren der C#-Klasse Die Datenbank wird auf folgende Weise zu einer DLL kompiliert und im bin-Ordner platziert: 231 ASP.NET 232 8 Listing 8.7: SQLClassC.bat set outdir=g:\aspnetsamples\bin\SqlClassC.dll set assemblies=System.dll,System.data.dll csc /t:library /out:%outdir% /r:%assemblies% SqlClassC.cs pause Testen der C#-Klasse Dieses Webformular testet die Methoden Populate und RunSQL der Datenbank-Klasse. Listing 8.8: TestcClass.aspx SQLClassC comp = new SQLClassC(); public void Page_Load(Object sender, EventArgs E) { comp.SQL = "Select * From Masters"; comp.ConnStr = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;"; bind(); string sql = "Insert into Masters(code_display,code_category,type)"; sql = sql + "Values ('test',701,'E')"; comp.RunSQL(sql); } public void Insert_Click(Object sender, EventArgs E) { string sql = "Insert into Masters(code_display,code_category,type)"; sql = sql + " Values ('test',701,'E')"; comp.RunSQL(sql); bind(); } public void Update_Click(Object sender, EventArgs E) { string sql = "UPDATE Masters Set Opening = 90 WHERE code_display = 'test'"; comp.RunSQL(sql); Business-Objekte 8 bind(); } public void Delete_Click(Object sender, EventArgs E) { string sql = "delete from masters where code_display = 'test'"; comp.RunSQL(sql); bind(); } public void bind() { DataGrid1.DataSource=comp.Populate(); DataGrid1.DataBind(); } SQL Class in C# Zusammenfassung Die Entwicklung von Business-Objekten ist ein wichtiges Thema. Ein gut eingebundener Code ist leicht zu warten, verbessert sich bei wiederholter Anwendung und kann ganz leicht von verschiedenen Entwicklern gemeinsam genutzt werden. Daher sind Business-Objekte ein praktischer Weg zur Trennung von Präsentation und Code. Funktionen zur Manipulation von Datenbanken sind hervorragend für die Einbindung in Business-Objekte geeignet. In diesem Kapitel wurden generische Funktionen zur Anwendung von SQL-Statements und Anfragen in Datenbanken entwickelt. Diese Funktionen sind in der Lage, Daten zurückzugeben, 233 ASP.NET 234 8 Aktionsanfragen wie Eingabe, Update und Löschen (Insert, Update und Delete) anzuwenden und gespeicherte Prozeduren auszuführen. Arbeiten mit ASP.NET Webdiensten Erstellen eines einfachen Webservice 238 Erstellen eines Webservice mit Visual Studio 252 Aufruf des Webservice aus einem Webformular 258 Nutzung des Webservice-Verhaltens zur Erstellung von Funktionsaufrufen 262 Zusammenfassung 268 ASP.NET 236 9 Entwicklung von Anwendungen bedeutet heute: Entwicklung für das Web. Das Ziel ist die Entwicklung von Serveranwendungen, die auf jedem Betriebsystem, das HTTP-Anwendungen verarbeiten kann, laufen. Hierfür sind zwei Technologien immer wichtiger geworden: SOAP und XML. Die Funktionalität eines Business-Objekts kann mit einem SOAP-Protokoll genutzt und als XML-Daten ausgetauscht werden. Die Webservices machen all dies möglich. Einen Webservice kann man am einfachsten als eine Bibliothek nützlicher Funktion, die in einem Business-Objekt eingeschlossen sind, beschreiben. Auf diese Funktionen kann mit SOAP und XML zugegriffen werden. Auch HTTP, Get und Post können zur Datenübertragung genutzt werden, jedoch sind diese Funktionen auf das Senden und Empfangen von Daten/Werte-Paaren oder Namen beschränkt. SOAP dagegen kann zur Serialisierung von komplexen Strukturen wie ASP.NET-Datensätzen, komplexen Arrays, benutzerdefinierten Typen und XML-Knoten verwendet werden. SOAP ist der Standard für Funktionsaufrufe zwischen Maschinen in XML. Der Austausch von Informationen in XML ermöglicht es einer Benutzeranwendung, ungeachtet des Betriebssystems, des Komponentenmodells, das von beiden unterstützt wird, oder der Sprache, in der die Anwendung programmiert wurde, eine Serverfunktion aufzurufen. Der Grund dafür ist, dass XML im Grunde nur eine Textdatei ist, die von allen Maschinen verstanden wird, und dass SOAP HTTP, das am weitesten verbreitete Internet-Übertragungsprotokoll, welches im Wesentlichen von allen Browsern benutzt wird, verwendet. Die Kommunikation zwischen verschiedenen Anwendungen ist keine wirklich neue Idee. Es gibt bereits Technologien wie DCOM, RPC und MSMQ (Microsoft Message Queue Service), die diese Art der Kommunikation unterstützen. Die Haupteinschränkung dieser Technologien besteht darin, dass nur Kommunikation zwischen gleichen Systemen unterstützt wird. Ein DCOM-System arbeitet recht gut in reinen Microsoft-Systemen und benötigt einen DCOM-Server sowie einen DCOM-Client. Diese Technologien erfordern die Anschaffung einer bestimmten Architektur sowie die Bindung an dieselbe. Ein weiterer Nachteil besteht darin, dass diese Technologien Probleme haben, die Firewall-Programme anderer Unternehmen zu überwinden. SOAP jedoch benutzt HTTP und kann diese Programme daher umgehen. Arbeiten mit ASP.NET Webdiensten 9 Webservices sind ein leicht verständliches Konzept. Ein Business-Objekt wird als Service bezeichnet. Es handelt sich hierbei um ein nicht sichtbares Objekt, das eine Reihe von nach einer logischen Klassifizierung gruppierten Funktionen enthält. Die Bezeichnung Service wurde gewählt, weil dieses Objekt versucht, einem anderen Objekt zu dienen. Dieses andere Objekt kann ein HTML-Formular, ein Webformular oder jede andere Funktion sein, die das Service-Objekt initialisieren kann. Als guter Dienstleister bleibt es so lange aktiv, wie es von einem aufrufenden Objekt benötigt wird, und wird dann wieder deaktiviert. In ASP.NET programmieren Sie einen Webservice wie ein normales Business-Objekt, mit dem einzigen Unterschied, dass hierbei den Funktionen ein spezielles -Attribut vorangestellt wird, das diese als Webservice kennzeichnet. Webservices können eine Bibliothek mit Anwendungen für Dritte sein, die über das Internet aufgerufen werden können. Beispiel hierfür sind die Verfolgung von Transporten (ähnlich der auf der FedEx-Site verfügbaren Funktionalität), Kreditkartenüberprüfung oder Kontrolle der richtigen Schreibweise. Webservices eröffnen einige aufregende Möglichkeiten gegenüber der traditionellen Art der Anwendungsentwicklung. Mit Hilfe von ASP.NET und Webservices können Sie Anwendungen entwickeln, die Daten über das Internet und HTTP senden und empfangen können. Denken Sie nur an Buchhaltungsanwendungen. Traditionelle Anwendungen dieser Art wurden auf der Basis des Client/Server-Modells entwickelt. Die Module (Finanzbuchhaltung, Inventur, Fakturierung usw.) teilen sich eine gemeinsame Datenbank und sind über eine Art Netzwerkprotokoll miteinander verbunden. Bei der Benutzung von Webdiensten müssen die einzelnen Module nicht mehr miteinander verkabelt sein. Nehmen Sie als Beispiel ein Produktionsunternehmen, dessen Lager und Finanzabteilung sich in unterschiedlichen Bundesländern befinden. Da die Daten des Bestands und der Finanzbuchhaltung integriert werden müssen, wird eine zentrale Datenbank benutzt. In einer traditionellen Client/Server-Umgebung wären die Inventur- und die Finanzbuchhaltungs-Software sowie die zentrale Datenbank über eine Art Satellitenverbindung aneinander gekoppelt. Im WebserviceModell jedoch wird das Internet (HTTP) als Verbindung ge- 237 ASP.NET 238 9 nutzt. Daten würden über das Internet (HTTP) durch das XMLoder das SOAP-Protokoll ausgetauscht. Beide Module könnten in verschiedenen Programmiersprachen geschrieben werden und auf unterschiedlichen Betriebssystemen laufen. Da beide Module XML und SOAP verstehen, könnten sie auf eine zentrale Sammlung von Funktionen zugreifen, die dann mit der Datenbank interagieren. Erstellen eines einfachen Webservice Zur Demonstration der damit verbundenen Technologien habe ich einen Webservice mit zwei einfachen Funktionen namens TestFunction() und add() erstellt. Die Funktion TestFunction() gibt einen auf der an ihn weitergegebenen BooleanVariablen basierenden Nachrichtenstring zurück. Die Funktion add() gibt die Summe zweier an sie weitergegebener ganzer Zahlen zurück. Um den Service zu erstellen, habe ich einen einfachen Text-Editor benutzt und die Datei mit der Erweiterung .asmx gespeichert. Die Quelldatei BasicService.asmx findet sich im Unterverzeichnis ...\Basic\getPost des Musterordners für dieses Kapitel. Listing 9.1: BasicService.asmx Imports System Imports System.Web.Services Public Class TestService: Inherits WebService Public Function TestFunction (vInput as Boolean) As String If (vInput = TRUE) Then TestFunction = "It is the truth..." Else TestFunction = "False!False!False" End if End Function Public Function add( a as integer, b as integer) as string add = cstr(a+b) End function End Class Das WebService-Attribut weist ASP.NET an, den Code als Webservice darzustellen und die Sprachdirektive wählt Visual Arbeiten mit ASP.NET Webdiensten 9 Basic.NET als Kompiliersprache. Das Klassenattribut spezifiziert die Klasse, welche die eingehenden Funktionsaufrufe bearbeitet. In diesem Fall handelt es sich dabei um die TestService-Klasse. Die Namensfelder (Namespaces) System und System.Web enthalten vorgefertigte Optionen, die im Webservice benötigt werden. Diese werden daher mit der Import-Direktive importiert. Die TestService-Klasse entsteht aus der WebService-Klasse. Eine solche inhärente Klasse kann die Funktionaliät der Klasse, aus der sie entstanden ist, übersteuern bzw. erweitern. Wenn Sie ein Namensfeld (Namespace) importieren, können Sie, im Gegensatz zur Arbeit mit inhärenten Namensfeldern, die Funktionalität der importierten Klasse nicht erweitern. Der neuen Klasse TestService werden nun zwei Funktionen (TestFunction und Add) hinzugefügt. Der Prozess der Funktionsdefinition unterscheidet sich nicht von der entsprechenden normalen Visual Basic Syntax. Dennoch wird hier den Methoden, die dem Webservice zur Verfügung gestellt werden sollen, ein neues Attribut hinzugefügt. ASP.NET stellt alle Methoden mit diesem Attribut als Webservices dar. Testen des Service ASP.NET bietet eine vorgefertigte Unterstützung für den Test der Funktionalität des Webservice. Wenn Sie die Datei TestService.asmx in Ihren Browser mit IIS öffnen (ein vollständiger URL, der über einen Localhost läuft), sehen Sie die Seite so, wie sie in Abbildung 9.1 gezeigt wird. Diese Seite liest die asmx-Datei und bietet die Möglichkeit, alle als WebMethods gekennzeichneten Funktionen zu testen. Um die TestFunction- oder die Add-Methode zu testen, müssen Sie lediglich die geforderten Parameter eingeben. Das Ergebnis der Funktion wird dann als XML über das GET-Protokoll angezeigt. Der WDSL-Vertrag Der Web Services Description Language-Vertrag (Contract) (oder kurz WDSL) ist eine XML-basierte Datei mit der kompletten Beschreibung eines Webservice. Er entspricht der Typenbibliothek eines COM-Objekts. Eine Typenbibliothek enthält Informationen bezüglich der spezifischen Kennzeichnung einer Komponente (CLSID), der von ihr implementierten Benut- 239 ASP.NET 240 9 zeroberflächen sowie deren Methodensignatur. Auf ähnliche Weise zeigt die WSDL-Datei (oder der Vertrag/Contract) alle in einem Webservice enthaltenen Methoden, die von diesen erwarteten Parameter und die unterstützten Protokolle an. Eine Typenbibliothek kann nur in Microsoft-Systemen verwendet werden, während der WSDL-Vertrag (Contract) als XML-Datei auch in anderen Systemen benutzt werden kann. Der Service im Test Abb. 9.1 Diese Datei ist ein Vertrag mit der Außenwelt, der spezifiziert, welche Fähigkeiten der Webservice hat. Wenn Sie sich die Datei TestService.asmx mit IIS anschauen, können Sie auf den Hyperlink Service Description klicken, um die XML-Datei zu betrachten, die den Vertrag enthält. Den gleichen Effekt erzielen Sie, wenn Sie einen ?WSDL-String an den kompletten URL der asmxDatei anhängen (Beispiel: http://localhost/TestService.asmx? WSDL). Die WSDL-Datei bestimmt, welche Protokolle dem aufrufenden Client zur Verfügung gestellt werden, und liefert Informationen darüber, wie die Funktion aufgerufen werden soll. Die WSDL-Datei für die Methoden TestFunction und Add beinhaltet Abschnitte für den Zugriff auf einen Webservice mit SOAP-, HTTP Post- oder HTTP Get-Protokollen. Des Weiteren bestimmt die Datei, wie eine Funktion aufgerufen wird und welche Parameter hierfür eingegeben werden müssen. Arbeiten mit ASP.NET Webdiensten 9 Obwohl eine detaillierte Kenntnis des WSDL-Vertrags nicht erforderlich ist, sollen hier doch die wichtigen Elementmarkierungen (tags) analysiert werden. Jede Methode des Webservice ist gleichzeitig auch eine Operation desselben. Dies gilt auch für die Methoden Add und TestFunction. Entsprechend der WSDL-Spezifikation ist eine Operation eine abstrakte Beschreibung einer vom Service unterstützten Aktion. Dies ist das Grundelement des WSDL-Dokuments. Alle anderen Elemente befinden sich innerhalb seiner Markierungen (tags). Seine Attribute bestimmen das Zielnamensfeld und andere Definitionen desselben. Diese Elementmarkierung (element tag) bestimmt den Namen des Webservice, den der WSDL-Vertrag beschreibt. Der hier gerade erstellte Webservice befindet sich in der TestService-Klasse. Das -Attribut für diesen Webservice ist der Klassenname, wie im folgenden Auszug aus dem WSDL-Vertrag zu erkennen ist: Innerhalb der -Elementmarkierung (Element tag) spezifiziert der WSDL-Vertrag verschiedenen Ports, über die auf den Webservice zugegriffen werden kann. Die Adresse des Webservice wird hier als vollständiger URL angegeben. Die Position des Webservice auf der lokalen Maschine wird folgendermaßen angegeben: http://localhost/AspNetSamples/9_Samples/Basic/GetPost/B asicService.asmx 241 ASP.NET 242 9 Der relevante Auszug aus dem WSDL-Vertrag für das SOAPProtokoll sieht folgendermaßen aus: Der Webservice kann durch mehrere Ports zugänglich gemacht werden. Auf diesen Webserver kann über SOAP, HTTP GET und HTTP Post zugegriffen werden. Wenn Sie sich den WSDL-Vertrag anschauen, werden Sie feststellen, dass die Elementmarkierung (Element tag) der oben aufgeführten Elementmarkierung ähnelt. Auf dem Rechner sieht der Code so aus: Die Kommunikation mit einem Webserver beinhaltet auch das Erstellen einer Anfrage (function call/Funktionsaufruf) und den Erhalt einer entsprechenden Antwort. Aus diesem Grund verfügt jede der im WSDL-Vertrag beschriebenen Funktionen für jedes Protokoll die Elementmarkierungen In (Anfrage) und Out (Antwort). So hat die Add-Methode (Hinzufügen) insgesamt sechs Elementmarkierungen (Element tags) (je zwei Markierungen für SOAP, HTTP GET und HTTP Post). Die Elementmarkierung entspricht dem Parameter oder dem von dem Fernprozeduraufruf zurückgegebenen Wert. Der folgende Auszug zeigt die von der Add-Methode (Hinzufügen) bei Verwendung des HTTP GET-Protokolls erwarteten Parameter: Arbeiten mit ASP.NET Webdiensten 9 Die Elementmarkierung benötigt die Elementmarkierung , um die Eingabe- und Ausgabemeldungen zu identifizieren: Zum guten Schluss muss der WSDL-Vertrag bestimmen, in welchem Code der Webservice die Daten erwartet. So erfordert zum Beispiel die TestFunction einen Boolean-Parameter (vInput) der als -1, 1 oder True dargestellt werden kann. Die Elementmarkierung legt fest, dass die SOAP-Spezifikationen, welche die folgenden vordefinierten Regeln für solche Situationen enthalten, beachtet werden müssen: Service-Aufruf mit HTTP GET In diesem Abschnitt werden Sie das HTTP GET-Protokoll benutzen, um den Webservice aufzurufen. Betrachten Sie den WSDL-Teil, der das HTTP GET-Protokoll für die Funktion TestFunction beschreibt. Hier ist der entsprechende Auszug: 243 ASP.NET 244 9 Listing 9.2: WSDL-Auszug für HTTP Get Die Testfunktion benötigt einen einzigen Parameter namens vInput. Während die Anfrage als String erfolgen muss, wird die Antwort in XML zurückgegeben. Die Anfrage wird erstellt, indem man dem vollständigen Namen des Webservice ein Fragezeichen und den Funktionsnamen zusammen mit den erforderlichen Parametern anhängt: http://localhost/path name/basicservice.asmx/TestFunction?vInput=TRUE Der Quellcode für dieses Beispiel (basicHTTPGet.html) findet sich im Beispielordner ...\basic\GetPost für dieses Kapitel. Abbildung 9.2 zeigt einen Musteraufruf an die TestFunction-Methode. Anfrage an einen Webservice mit dem HTTP GET«-Protokoll Abb. 9.2 Arbeiten mit ASP.NET Webdiensten 9 Listing 9.3: basicHTTPGet.html HTTP GET Example WSDL Contract TestFunction?vInput=TRUE TestFunction?vInput=False Ein Klick auf einen der Funktionslinks ruft die TestFunction auf und gibt den entsprechenden Eingabeparameter weiter. Klicken Sie beispielsweise auf den Link vInput="True", wird True an die TestFunction weitergegeben. Der Webservice gibt die folgende Antwort in XML zurück: It is the truth... Service-Aufruf mit HTTP Post Dieser Abschnitt beschreibt den Aufruf eines Webservice mit dem HTTP Post-Protokoll. Betrachten Sie den WSDL-Teil, der das HTTP Post-Protokoll für die Funktion TestFunction beschreibt. Hier ist der entsprechende Auszug: Listing 9.4: WSDL-Auszug für HTTP Post 245 ASP.NET 246 9 Um die TestFunction mit dem HTTP Post-Protokoll aufzurufen, müssen Sie den Parameter vInput über eine Eingabe-Kontrolle (input control), die sich innerhalb der Formularmarkierungen (form tags) befindet, weitergeben. Abbildung 9.3 zeigt ein Beispiel-Webformular, das diese Anfrage ausführt. Den entsprechenden Code finden Sie im Anschluss an die Abbildung. Beachten Sie, dass das -Attribut der -Markierung so modifiziert werden muss, dass es auf Ihren Anwendungsordner gerichtet ist. Der Quellcode befindet sich im Unterverzeichnis ...\basic\GetPost im Beispielordner für dieses Kapitel. Aufruf des Webservice mit dem HTTP PostProtokoll Abb. 9.3 Listing 9.5: basicHTTPPost.html HTTP Post Example True False Service-Aufruf mit SOAP SOAP ist das wichtigste Übertragungsprotokoll. Sie werden festgestellt haben, dass die Get- und Post-Protokolle auf das Empfangen und Senden von Daten- oder Namenspaaren beschränkt sind. SOAP ist wichtig, weil es Ihnen die Möglichkeit gibt, komplexe Strukturen wie DataSets, komplexe Arrays, benutzerdefinierte Typen und XML-Knoten zu serialisieren. Ein Clientaufruf an SOAP erfolgt durch das Senden einer Nachricht in der XML-Sprache von SOAP als HTTP-Übertragung. Die äußere Hülle dieser Nachricht beinhaltet eine Kopfzeile und einen Hauptteil. Der Hauptteil beinhaltet den Funktionsnamen und die an die Funktion weiterzugebenden Parameter. Jedem dieser Elemente ist ein XML-Namensfeld (Namespace) vorangestellt (http://schemas.xmlsoap.org/soap/envelope). Eine SOAP-Anfrage an die TestFunction-Funktion könnte folgendermaßen aussehen: True 247 ASP.NET 248 9 Die SOAP-Anfrage wird an einen SOAP Listener auf dem Server geschickt. Dieser Zuhörer ist im Allgemeinen das Webformular. Die Kommunikation zwischen Client und Server erfolgt über HTTP, obwohl auch Transfermechanismen wie etwa Steckdosen, Message Queuing oder E-Mail verwendet werden könnten. Der SOAP Listener führt die aufgerufenen Funktion aus und gibt die Antwort in XML zurück. Eine erfolgreiche Antwort ist in einer Elementmarkierung eingeschlossen, die den Originalnamen der Methode trägt und der die Antwort angehängt ist. Die Antwort an die TestFunction-Funktion wäre daher in der Elementmarkierung TestFunctionResponse eingeschlossen. Der SOAP-Hauptteil der Antwort könnte folgendermaßen aussehen: it is the truth Glücklicherweise müssen Sie sich nicht mit all den Einzelheiten der Erstellung einer Kommunikationsinfrastruktur für SOAP und XML befassen. ASP.NET nimmt sich dieser Aufgabe an. Sie generieren lediglich ein Proxy Ihres Webservice unter Zuhilfenahme der wsdl.exe-Utility, die in ASP.NET enthalten ist. Dieses Tool liest die WSDL-Datei und generiert einen Proxy, der eine Sprache nach Ihrer Wahl einsetzt. Wann immer ein Client eine Prozedur aufruft, generiert der Proxy eine HTTP-Anfrage und sendet diese an den Server. Anschließend sendet er die erhaltene Antwort zurück an den Client. Sie werden nun lernen, das SOAP-Protokoll in ASP.NET zu implementieren. Das Muster für dieses Beispiel befindet sich im Unterverzeichnis ..../basic/soap des Beispielordners auf der CD des Buches. Arbeiten mit ASP.NET Webdiensten 9 1 Erstellen Sie die Webservice-Datei. Ich habe bereits die Datei BasicService.asmx erstellt und kopiere sie nur noch in den Ordner. 2 Erstellen Sie die WSDL-Datei. Öffnen Sie BasicService.asmx über IIS (Beispiel: http://localhost/yourvirtual directory/BasicService.asmx). Klicken Sie auf den Hyperlink Service Description. Speichern Sie die daraus resultierende Datei als basicService.wsdl ab. Sie können das gleiche Ergebnis erreichen, wenn Sie zu http://localhost/your virtual directory/BasicService. asmx?wsdl browsen. ACHTUNG Sie müssen die WSDL-Datei neu erstellen, auch wenn diese Datei bereits im Beispielordner existiert. Diese Datei bezieht sich auf den Anwendungsordner auf meinem Rechner. Sie müssen diese Datei daher durch eine neue WSDL-Datei, die sich auf Ihren Anwendungsordner bezieht, ersetzen. 3 Starten Sie die Datei mbasicService.bat. Diese batDatei hat zwei Aufgaben. Zunächst bringt sie einen Proxy dazu, die Befehlszeilen-Utility (Command-line Utility) wsdl.exe zu nutzen, die in NETSDK enthalten ist. Sie liest die Beschreibung des Webservice aus der WSDL-Datei und erstellt eine Proxy-Klasse mit der Erweiterung .vb (da Sie mit Visual Basic arbeiten). Der Name dieser Klasse ist in der asmx-Datei spezifiziert. Daher heißt diese Proxy-Klasse TestService.vb. Kompilieren Sie dann diese Proxy-Klasse und speichern Sie die daraus resultierende DLL (BasicService.dll) im binOrdner. Wenn Sie alles richtig gemacht haben, sollten jetzt zwei neue Dateien erstellt worden sein: die Proxy-Datei TestService.vb (im lokalen Ordner) und die Datei BasicService.dll (im bin-Ordner). Visual Studio automatisiert die Erstellung des Proxy. Später in diesem Kapitel werden Sie mehr über die Erstellung eines 249 ASP.NET 250 9 Webservice mit Visual Studio erfahren. Abbildung 9.4 zeigt das Ergebnis zu diesem Zeitpunkt der Entwicklung: Listing 9.6: mbasicService.bat REM ---------Make Proxy---------------wsdl.exe /l:VB /n:NameSpaceHersh /out:TestService.vb BasicService.Wsdl REM -----------Compile Proxy-------------Rem Remember to change outdir variable to point to your bin folder set outdir=g:\AspNetSamples\bin\BasicService.dll set assemblies=System.dll,System.Web.dll,System.Data. dll, System.Web.Services.dll,System.Xml.dll vbc /t:library /out:%outdir% /r:%assemblies% TestService.vb Kompilieren des Proxy Abb. 9.4 4 Testen Sie den Service. Hierzu steht Ihnen ein einfaches Webformular zur Verfügung. Dieses Formular ruft die TestFunction-Funktion auf und gibt den Parameter true an den Webservice. Der zurückgegebene Wert der Funktion wird auf dem Bildschirm angezeigt, wie in Abbildung 9.5 zu sehen ist. Arbeiten mit ASP.NET Webdiensten 9 Test mit dem SOAPProtokoll Abb. 9.5 Listing 9.7: basicSoap.aspx Protected Sub Page_Load(Src As Object, E As EventArgs) Dim t As New NameSpaceHersh.Testservice Dim s As string s = t.testfunction(true) message.text = "Return from function : " + s End Sub Testing Soap Proxy 251 ASP.NET 252 9 Erstellen eines Webservice mit Visual Studio Die Erstellung eines Webservice mit Visual Studio.NET (kurz VS.NET) beinhaltet die Erstellung eines neuen Webservice-Projekts und die Hinzufügung von Methoden und Eigenschaften zum Formular einer Webservice-Klasse (z.B. ein asmx-Formular). In diesem Abschnitt werden Sie einen Webservice mit Visual Studio.NET erstellen und den Gebrauch des intergrierten VS-Fehlerbehebungsprogramms (Debugger) erlernen. Im Anschluss daran werden Sie ein Visual Studio.NET-Projekt entwickeln, um den hier erstellten Webservice zu benutzen. Der Quellcode für dieses Beispiel befindet sich im VSServiceUnterverzeichnis des Beispielordners für dieses Kapitel. Um die Dateien auf Ihrem System zu installieren, erstellen Sie ein neues Webservice-Projekt und importieren die Beispieldateien dort hinein. Hierdurch ensteht der virtuelle Anwendungsordner auf Ihrem Computer. Neues Projekt Abb. 9.6 1 Starten Sie Visual Studio.NET. 2 Wählen Sie Datei/Neu/Projekt (File/New/Project) wie in Abbildung 9.6 gezeigt. Arbeiten mit ASP.NET Webdiensten 9 3 Wählen Sie Visual Basic Projects aus der linken Leiste und Web Services aus der rechten Leiste. Abbildung 9.7 zeigt das Ergebnis Neuer Webservice Abb. 9.7 4 Geben Sie VSService als Name ein. Unter Umständen wird Ihnen eine Dialogbox Web Access Failed (Webzugang fehlgeschlagen) wie in Abbildung 9.8 angezeigt. Klicken Sie auf OK. Visual Studio.NET nutzt den Dateizugang, um die Lösung (Solution) zu öffnen. 5 Visual Studio.NET generiert eine neue Solution (Lösung), die einen Referenzordner und vier Dateien enthält. Die Datei web.config ist eine XML-Datei, die verschiedene Konfigurationsoptionen (beispielsweise Session timeout interval) enthält und den Webservice während des gesamten Ablaufs überwacht. Die Datei .disco ist eine XML-Datei, die vom Client zur dynamischen Entdeckung von Webdiensten genutzt wird. Wenn Sie diesen Service in einem anderen Projekt nutzen möchten, navigieren Sie zu dieser Datei und VS.NET fügt ihr eine Referenz bezüglich des Service hinzu. 253 ASP.NET 254 9 6 Klicken Sie mit der rechten Maustaste auf Service1. asmx und wählen Sie Öffnen (Open). Wenn Sie die Datei mit Notepad öffnen, werden Sie bemerken, dass diese Datei einen Code aufruft, der sich in einer anderen Datei befindet (Service1.vb): Die Web Access FailedDialogbox Abb. 9.8 Die Solution-Leiste mit den vier vorinstallierten Dateien Abb. 9.9 Fügen Sie die zwei Funktionen TestFunction() und add() innerhalb des Klassenmoduls wie folgt hinzu: Public Function TestFunction (vInput as Boolean) As String If (vInput = TRUE) Then TestFunction = "It is the truth..." Else TestFunction = "False!False!False" End if End Function Public Function add( a as integer, b as Arbeiten mit ASP.NET Webdiensten 9 255 integer) as string add = cstr(a+b) End Function Abbildung 9.10 zeigt, wie die Codeansicht von VS.NET zu diesem Zeitpunkt aussieht. Erstellen des Webservice Abb. 9.10 Erstellen der Lösung Abb. 9.11 ASP.NET 256 9 7 Klicken Sie mit der rechten Maustaste auf die Lösung (Solution) VSService und wählen Sie Erstellen (Build), wie in Abbildung 9.11 gezeigt. (Sie können auch die Taste % drücken.) 8 Testen Sie den Service durch einen Rechtsklick auf Service1.asmx und wählen Sie View in Browser (Im Browser öffnen). Sie sehen die in Abbildung 9.12 gezeigte voreingestellte Testseite, deren Funktionen Sie jetzt durch Eingabe der geforderten Parameter testen können. 9 Visual Studio.NET enthält ein effektives Fehlerbehebungsprogramm (Debugger). Sie können Break-Punkte setzen und sich durch Drücken der Taste ( durch den Code bewegen. Um das Fehlerbehebungsprogramm zu nutzen, öffnen Sie die Datei Service1.asmx und setzen Sie einen Break-Punkt durch Doppelklick auf die graue Leiste auf der linken Seite außerhalb des Codebereichs. Ein roter Punkt erscheint an dieser Stelle, wie Sie in Abbildung 9.13 sehen können. Starten Sie den Fehlerbehebungsmodus (Debug-Mode) durch Drücken der Taste %. Wenn Sie nach einem Debug-Ordner gefragt werden, wählen Sie irgendeinen Ordner, der sich nicht in wwwroot befindet (z.B. c:\test). Die voreingestellte Testseite wird nun angezeigt. Geben Sie die Parameter der Funktion ein, die Sie nach Fehlern durchsuchen möchten. Der Debugger bringt Sie zurück zu der Linie des Break-Punktes. Wenn Sie den Mauszeiger auf einen Parameter ziehen und dort für eine Sekunde halten, sehen Sie, wie der Parameter weitergegeben wird, wie in Abbildung 9.14 zu erkennen ist. Drücken Sie die Taste (, um sich schrittweise durch den Code zu bewegen. Arbeiten mit ASP.NET Webdiensten 9 257 Testen der Funktionen Abb. 9.12 Setzen eines Break-Punktes Abb. 9.13 10 Browsen Sie zum bin-Ordner im VSService-Ordner. Hier finden Sie eine kompilierte DLL namens VSService.dll. Visual Studio.NET hat den Proxy erstellt und für Sie kompiliert. ASP.NET 258 9 Benutzen des Debuggers Abb. 9.14 Aufruf des Webservice aus einem Webformular In diesem Abschnitt werden Sie eine Clientanwendung erstellen, die den im vorigen Abschnitt erstellten Webservice nutzt. Es handelt sich dabei um eine VS-Webanwendung, deren Erstellung in den folgenden Schritten erklärt wird. 1 Starten Sie Visual Studio.NET 2 Wählen Sie Datei/Neu/Projekt (File/New/Project). 3 Wählen Sie Visual Basic Projects aus der linken Leiste und Asp.NET Web Application aus der rechten Leiste, wie in Abbildung 9.15 gezeigt. Geben Sie VSClient als Projektnamen ein. 4 Ziehen Sie drei Textboxen, drei Label und einen Button in das Formular. Klicken Sie mit der rechten Maustaste auf einen freien Bereich des Formulars und wählen Sie Eigenschaften (Properties). Vergewissern Sie sich, dass die Page Layout-Eigenschaft auf GridLayout eingestellt ist. Mit GridLayout können Sie die Kontrollen verschie- Arbeiten mit ASP.NET Webdiensten 9 259 ben und sichtbar auf dem Formular platzieren. Ändern Sie die Text-Eigenschaften von drei Labeln auf das Lesen von Parameter A und B respektive auf das Ergebnis (Result). Stellen Sie die ID-Eigenschaften der drei Textboxen auf das Lesen der Parameter 1 und 2 respektive auf Ergebnis hinzufügen (ResultAdd). Das Formular sollte jetzt der Abbildung 9.16 entsprechen. Die neue Projektleiste Abb. 9.15 Design des Webformulars Abb. 9.16 ASP.NET 260 9 5 Hinzufügen einer Webreferenz Abb. 9.17 Sie müssen nun noch einen Bezug zum VSService herstellen, um diesen in der Anwendung nutzen zu können. Wählen Sie hierzu Project/Add Web Reference aus dem Hauptmenü oder klicken Sie mit der rechten Maustaste auf den Projektnamen (VSClient) im Solution-Fenster und wählen Sie Add Web Reference. Klicken Sie auf der linken Seite des Fensters auf den Hyperlink Web Reference on Local Web server. Sie sehen nun alle Entdeckungs-Dateien (*.disco oder *.vsdisco), aus denen Sie VSService.vsdisco auswählen können. Unter Umständen wird die Meldung Directory Listing Denied angezeigt. Geben Sie in diesem Fall den vollständigen IISPfad der Datei VSService.vsdisco an und drücken Sie die Eingabetaste. Nun sehen Sie das in Abbildung 9.17 gezeigte Add Web Reference-Fenster. Visual Studio.NET entdeckt den Webservice und zeigt die Ergebnisse, wie in Abbildung 9.18 gezeigt, an. Klicken Sie nun auf den Hyperlink VSService.vsdisco anschließend auf den Add Reference-Button (Referenz hinzufügen). Dem Solutions-Explorer wird nun, wie in Abbildung 9.19 gezeigt, ein Bezug zu dem Webservice hinzugefügt. Arbeiten mit ASP.NET Webdiensten 9 261 Entdeckung eines Webservice Abb. 9.18 Referenz zu einem Webservice im SolutionExplorer Abb. 9.19 6 Fügen Sie den folgenden Code hinter dem Click-Event des Buttons ein: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim s As String Dim t As New localhost.Service1() s = t.add(CInt(Param1.Text), CInt(Param2.Text)) ResultAdd.Text = s End Sub ASP.NET 262 9 Testen der Add-Funktion Abb. 9.20 7 Erstellen Sie nun die Anwendung und drücken Sie die Taste %, um diese im Browser zu betrachten. Abbildung 9.20 zeigt das Formular. Geben Sie die Eingabewerte der beiden Textboxen Param1 und Param2 ein und klicken Sie auf den Button. Das Click-Event dieses Buttons ruft nun die Add-Methode des Webservice auf, der daraufhin das Ergebnis der Addition zurückgibt, das in der ResultAdd-Textbox angezeigt wird. Nutzung des Webservice-Verhaltens zur Erstellung von Funktionsaufrufen Sie können Funktionen auch mit einer anderen, von Microsoft bereitgestellten Methode aufrufen, dem Web Service Behavior (Verhalten). Erinnern Sie sich daran, dass SOAP ein Protokoll und ASP.NET nur ein Werkzeug zu dessen Implementierung ist. SOAP dient hauptsächlich der Versendung und dem Empfang von XML-Paketen über HTTP. Sie brauchen jedoch kein Werkzeug, um SOAP zu starten. Dennoch ist es hilfreich, Zugang zu einer Sammlung vorgefertigter Funktionen zu haben, da Sie so das Rad nicht neu erfinden müssen. Die ASP.NET-Implementierung von SOAP erfordert die Existenz eines Proxy, worauf WebService Behavior verzichten kann. Beide Technolo- Arbeiten mit ASP.NET Webdiensten 9 gien sind effektiv und fundiert; daher geht es bei der Präsentation von WebService Behavior lediglich um die Erweiterung Ihres Werkzeugsatzes und darum, Ihnen eine andere Art der Anwendung von SOAP zu zeigen. WebService Behavior wird mit einer einfachen HTML-Komponentendatei (HTC) als ein zusätzliches Verhaltensmuster implementiert, das im Internet Explorer 5.0 oder höher genutzt werden kann. Die Datei WebServices.HTC kann von der Microsoft-Website unter http://msdn.microsoft.com/workshop/ author/webservice/webservice.htc heruntergeladen werden. Die Datei wird im Ordner der Website gespeichert, die das Verhaltensmuster nutzt. Die Webservices können mit JavaScript auf der Clientseite aufgerufen werden. Zum Testen dieser Technik steht Ihnen ein Beispiel-Webservice zur Verfügung (behavior.asmx). Diese Datei befindet sich zusammen mit der HTC-Datei WebService.htc und zwei HTMLDateien (populate.html und add.html Unterverzeichnis behavior des Beispielordners für dieses Kapitel. Der Webservice enthält zwei einfache Funktionen. Die AddFunktion kennen Sie schon aus den vorigen Abschnitten. Die zweite Funktion Populate ist schon ein wenig interessanter. Wie bereits früher erwähnt, kann ein Webservice, der SOAP nutzt, verwendet werden, um ein ASP.NET-DataSet zu serialisieren, was hier demonstriert werden soll. Die Populate-Funktion bekommt als Eingabeparameter einen Verbindungsstring und einen SQL Select-Anfragestring. Sie gibt einen Datensatz mit Reihen aus der Datenbank nach Ausführen der SQL-Anfrage zurück, wie der folgende Auszug aus dem Code dieser Funktion zeigt: Public Function Populate(ConnStr as string, SQL as string) As DataSet Dim dv As DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "vTable") Populate = ds End Function 263 ASP.NET 264 9 Hier die komplette Codeliste des Webservice: Listing 9.8: Behavior.asmx Imports System Imports System.Web.Services Imports System.Data Imports System.Data.OleDb Imports System.Text Public Class Behavior: Inherits WebService Public Function TestFunction (vInput as Boolean) As String If (vInput = TRUE) Then TestFunction = "It is the truth..." Else TestFunction = "False!False!False" End if End Function Public Function add( a as integer, b as integer) as string add = cstr(a+b) End Function Public Function Populate(ConnStr as string, SQL as string) As DataSet Dim dv As DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "vTable") Populate = ds End Function End Class Das HTML-Formular, welches die Populate-Methode des Webservice aufruft, hat den Namen Populate.html. Innerhalb dieses Formulars wird die Populate-Funktion durch Weitergabe des Verbindungsstrings und der SQL-Anfrage (Select * from Groups) als Eingabeparameter aufgerufen. Die Methode gibt alle Datensätze aus der Groups-Tabelle im XML-Format zurück. Arbeiten mit ASP.NET Webdiensten 9 265 Sie können das XSL-Stylesheet zum Rendern der zurückgegebenen XML-Daten verwenden. Abbildung 9.21 zeigt das Ergebnis des Aufrufs der Populate-Methode. Aufrufen der PopulateFunktion mit der Behavior-Methode Abb. 9.21 Dies ist die Codeliste von Populate.html: Listing 9.9: Populate.html var idCall = null; function init() { WebServices.useService("behavior.asmx?WSDL","myService") ; var vcn= "Provider=SQLOLEDB; Data Source=(local);" ; vcn= vcn + "Initial Catalog=ASPNET;User ID=sa;"; var vSQL = "select * from Groups" ; idCall = WebServices.myService.callService("Populate",vcn, vSQL); } function WebServices_OnResult() { if (idCall == event.result.id) if (!event.result.error) txtResult.value = event.result.value.xml ; else txtResult.value = event.result.errorDetail.string; } ASP.NET 266 9 Result: WebService Behavior wird mit dem Style-Attribut an ein Element gebunden. Es erhält eine WebServices-ID, damit sich das Skript darauf beziehen kann. Die Use-Methode des Webservice legt den Webservice-URL auf den Namen myservice. Dieser Name kann im Code wie im folgenden Beispiel als Bezug auf den Webservice verwendet werden: WebServices.useService("SQLService.asmx?SDL","myService") . Die Populate-Funktion des SQLService.asmx erwartet zwei Parameter: den Verbindungsstring und den SQL-String. Diese werden in den Variablen vcn und vSQL gespeichert und folgendermaßen an die Funktion weitergegeben: idCall = WebServices.myService.callService("Populate",vcn, vSQL) Die callService-Methode initiiert eine asynchrone Kommunikation zwischen WebService Behavior und dem Webservice. Das OnResult-Event wird bei Erhalt der Ergebnisse als XML-Datenpaket des Aufrufs ausgelöst. Der folgende Code enthält dann das Ergebnis und zeigt es im Textfeld auf Ihrem Bildschirm an: Function WebServices_OnResult() { If (idCall == event.result.id) If (!event.result.error) txtResult.value = event.result.value.xml ; Arbeiten mit ASP.NET Webdiensten 9 Else txtResult.value = event.result.errorDetail.string; } Die Add()-Methode des Webservice akzeptiert zwei ganze Zahlen als Eingabeparameter und gibt die Addition der Werte wie unten aufgeführt als Ergebnis zurück: Public Function add( a as integer, b as integer) as string add = cstr(a+b) End Function Die Datei AddFunction.html zeigt Ihnen, wie die Add()-Funktion des Webservice aufgerufen werden kann. Hier die Codeliste der Datei: Listing 9.10: AddFunction.html var idCall = null; function init() { WebServices.useService("behavior.asmx?WSDL","myService") ; var vcn= "Provider=SQLOLEDB; Data Source=(local);" ; vcn= vcn + "Initial Catalog=ASPNET;User ID=sa;"; var vSQL = "select * from Groups" ; idCall = WebServices.myService.callService("add",5,16); } function WebServices_OnResult() { if (idCall == event.result.id) if (!event.result.error) txtResult.value = event.result.value ; else txtResult.value = event.result.errorDetail.string; } 267 ASP.NET 268 9 Result: Der Aufruf gleicht dem Aufruf der Populate-Funktion mit dem Unterschied, dass das Event-Ergebnis ein Wert und kein XMLCode ist. Zugriff auf Datenquellen anderer Domains Ein häufiges von XML/SOAP-Benutzern moniertes Problem sind die Zugangsverweigerungen im Internet Explorer beim Versuch, den Webservice einer anderen Domain aufzurufen. Um auf einen solchen Webservice zugreifen zu können, muss die Option Access data sources across domains des Internet Explorer entweder auf Enabled oder auf Prompted gesetzt werden. Wählen Sie hierzu Tools/Internet-Optionen. Wählen Sie dann das Security-Register. Achten Sie bei den Interneteinstellungen darauf, dass die Option Access data sources across domains des Internet Explorer entweder auf Enabled oder auf Prompted gesetzt ist, wie in Abbildung 9.22 gezeigt. Zusammenfassung Dieses Kapitel behandelte eines der wichtigsten Themen in ASP.NET-Webservices. Technologien zur Kommunikation zwischen verschiedenen Anwendungen wie etwa DCOM, RPC und MSMQ existieren zwar bereits; sie sind bisher nicht sehr erfolgreich gewesen, da der Benutzer hier immer an eine bestimmte Technik gebunden war. Webservices jedoch basieren auf SOAP und XML, die beide von allen Maschinen und Betriebssystemen verstanden werden. In diesem Kapitel haben Sie gelernt, Webservices sowohl mit einem simplen Text-Editor als auch mit Visual Studio 7 zu nutzen. Sie haben auch gelernt, Webservices mit Web Service Behaviors aufzurufen. Arbeiten mit ASP.NET Webdiensten 9 269 Die Option Enable Access data sources across domains des Internet Explorers Abb. 9.22 ASP.NET-Anwendungen Erstellung eines virtuellen Verzeichnisses 272 Die Global.asax-Datei 275 Global.asax und Anwendungsstatus 280 Sitzungsstatus 283 Die Konfigurationsdatei 291 Zusammenfassung 302 ASP.NET 272 10 Eine ASP.NET-Anwendung entspricht einem virtuellen Verzeichnis. Alle ASP.NET-Objekte im gleichen virtuellen Verzeichnis bilden eine ASP.NET-Anwendung. Diese Objekte können Seiten, Webservices, Konfigurationsdateien, globale Anwendungsdateien, Zusammensetzungen und Anwendungs-Services wie etwa Sicherheitsprogramme sein. Erstellung eines virtuellen Verzeichnisses Um ein neues virtuelles Verzeichnis in IIS unter Windows NT zu erstellen, starten Sie den Internet Service Manager. Klicken Sie mit der rechten Maustaste auf ein bestehendes Verzeichnis und wählen Sie Neu/Virtuelles Verzeichnis (New/Virtual Directory – siehe Abbildung 10.1): Ein neues virtuelles Verzeichnis in IIS Abb. 10.1 ASP.NET-Anwendungen 10 Umwandeln eines bestehenden Ordners in ein virtuelles Verzeichnis Sie können einem bestehenden Verzeichnis den Status eines virtuellen Verzeichnisses verleihen: 1 Klicken Sie mit der rechten Maustaste auf den Ordner, den Sie in ein virtuelles Verzeichnis umwandeln wollen. 2 Wählen Sie Anwendungs-Einstellungen (Application Settings) und klicken Sie auf den Button Erstellen (Create) direkt neben der deaktivierten Default Application-Textbox (siehe Abbildung 10.2). 3 Der Button Erstellen (Create) trägt nun die Bezeichnung Entfernen (Remove) und das Namensfeld (Name) ist aktiviert. Das virtuelle Verzeichnis ist bereit (siehe Abbildung 10.3). Erstellen eines neuen virtuellen Verzeichnisses in einem persönlichen Webserver unter Windows 2000 Um ein virtuelles Verzeichnis in einem persönlichen Webserver unter Windows 2000 zu erstellen, führen Sie die folgenden Schritte aus: 1 Starten Sie den Personal Web Server und klicken Sie auf den Button Erweitert (Advanced / siehe Abbildung 10.4). 2 Klicken Sie auf Hinzufügen (Add), browsen Sie zum Ordner und geben Sie ihm einen Namen in der AliasBox. 273 ASP.NET 274 10 Der Create-Button Abb. 10.2 Der Remove-Button Abb. 10.3 ASP.NET-Anwendungen 10 275 Neues virtuelles Verzeichnis im Personal Web Server Abb. 10.4 Die Global.asax-Datei Die Global.asax-Datei ähnelt dem Konzept der Global.asa-Datei. Ebenso wie die Global.asa-Datei verarbeitet auch die Global.asax-Datei Anwendungslogik durch Anwendungs-Events, wie etwa Application Start, Application End, Session Start und Session End, um nur einige zu nennen. Diese Datei wird dynamisch gegliedert und in eine .NET-Framework-Klasse kompiliert, sobald irgendeine Ressource innerhalb des Namensfeldes der Anwendung zum ersten Mal angefordert wird. Die Datei kann nicht direkt von Benutzern angefordert werden, da ihr Inhalt geschützt ist. Die Global.asax- und die Global.asa-Datei können nebeneinander im gleichen virtuellen Verzeichnis existieren. Hierdurch wird den ASP-Entwicklern eine Rückwärtskompatibilität geboten – ASP-Anwendungen benutzen weiterhin die Global.asa-Dateien, während die Global.asax von den ASP.NET-Anwendungen genutzt werden. Die beiden Dateien können sich jedoch keine Anwendungen oder Variablen des Sitzungsstatus (Session state variables) teilen. Wenn Sie die Global.asax-Datei verändern, erkennt das ASP.NET-Framework diese Veränderungen, komplettiert alle offenen Anfragen, startet das Application OnEvent-Event und bootet die Anwendung erneut, wodurch alle bestehenden Sta- ASP.NET 276 10 tusinformationen gelöscht werden. Dieser Prozess ist für den Benutzer unsichtbar, der hierdurch keine Verzögerungen in der Übertragung erfährt. Die Global.asax-Datei hat zwei Events, die bei jeder Anfrage oder Rücksendung eines Formulars gestartet werden. Hierbei handelt es sich um die Events Application BeginRequest und Application EndRequest. Code, der am Anfang der Seite ausgeführt werden muss, kann in der Anwendung Application BeginRequest platziert werden. Abbildung 10.5 zeigt eine Beispielanwendung, welche die Global.asax-Datei verwendet. Der Code befindet sich im Beispielordner (Samples) im Unterverzeichnis Events. Achten Sie darauf, die Global.asax-Datei im Ursprungsverzeichnis (Root directory) des virtuellen Verzeichnisses zu platzieren. Listing 10.1: Global.asax Sub Application_Start(Sender As Object, E As EventArgs) 'Code zum Start der Anwendung hier einfügen End Sub Sub Application_End(Sender As Object, E As EventArgs) 'Anwendungsressourcen bereinigen End Sub Sub Session_Start(Sender As Object, E As EventArgs) Response.Write("Session Start Fired...") End Sub Sub Session_End(Sender As Object, E As EventArgs) 'Sitzungsressourcen bereinigen End Sub Sub Application_BeginRequest(Sender As Object, E As EventArgs) Response.Write(" Global.asax Demo") Response.Write("Begin Request Fired...") ASP.NET-Anwendungen 10 End Sub Sub Application_EndRequest(Sender As Object, E As EventArgs) Response.Write("End Request Fired...") End Sub Die folgende Website ruft diese Datei auf: Listing 10.2: GlobalTest.aspx Sub Page_Load(Sender As Object, E As EventArgs) Response.Write("Page.Load Fired...") End Sub Sub Session_End(Sender As Object, E As EventArgs) Session.Abandon() Response.Redirect("GlobalTest.aspx") End Sub Wenn die Seite angefordert wird, tritt die folgende Event-Sequenz auf: 1 Application BeginRequest 2 Session Start 3 Page Load 4 Application EndRequest 277 ASP.NET 278 10 Abbildung 10.5 zeigt das Ergebnis: Die erste Anfrage Abb. 10.5 Wenn die Seite erneuert wird, tritt die folgende Event-Sequenz auf: 1 Application_BeginRequest 2 Page Load 3 Application_EndRequest Abbildung 10.6 zeigt das Ergebnis: Wenn die Internetsitzung beendet wird, tritt die folgende Event-Sequenz auf: 1 Application_BeginRequest 2 Session_Start 3 Page Load 4 Application_EndRequest Bei Abbruch einer Sitzung wird eine neue Internetsitzung generiert und das Session_Start-Event wird gestartet, wie die Abbildung 10.7 zeigt: ASP.NET-Anwendungen 10 279 Erneuerung der Seite Abb. 10.6 Abbruch der Sitzung Abb. 10.7 Die Methoden Locking und Unlocking dienen als Sicherung gegen Datenkorruption, wenn mehrere Benutzer gleichzeitig versuchen, dieselbe Variable zu aktualisieren. Die Syntax ist geradlinig, wie das folgende Beispiel zeigt: ASP.NET 280 10 Wenn die Ausführung einer Seite beendet ist, die Übertragung zu lange dauert oder ein unbearbeiteter Fehler auftritt, wird das Anwendungs-Objekt automatisch entriegelt. Bei der Speicherung von Daten in Anwendungs-Objekten ist Vorsicht geboten, da wichtige Ressourcen, die besser an einem anderen Ort gespeichert werden sollten, absorbiert werden können. Das Anwendungsobjekt kann in einer Webfarm oder einem Webgarden nicht aufrecht erhalten werden, was eine Einschränkung dieser Technologie bedeutet. Anwendungen oder sitzungsbezogene Objekte Sie können .NET-Framework-Klassen oder klassische COMKomponenten entweder mit einer Anwendungsinstanz (Appinstance), einer Sitzung oder einem Anwendungsbereich definieren und hierbei die Objektmarkierungen nutzen. Die Anwendungsinstanz impliziert, dass das Objekt spezifisch für eine HTTP-Anwendung ist und nicht gemeinsam genutzt wird. Global.asax und Anwendungsstatus Sie können anwendungsbezogene Variablen in der Global.asax-Datei speichern. Das folgende Beispiel zeigt Ihnen, wie Sie eine Datenansicht (DataView) in einer Anwendungsvariablen speichern können, die dann von der gesamten Anwendung genutzt werden kann. Der Code für dieses Beispiel befindet sich im Unterverzeichnis ...samples\Application auf der CD des Buches. ASP.NET-Anwendungen 10 Programmieren Sie zunächst das Application_Start-Event wie hier beschrieben: Listing 10.3: Global.asax Sub Application_Start(Sender As Object, E As EventArgs) 'Code zum Start der Anwendung hier einfügen Dim dv As DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet Dim ConnStr As String Dim SQL As String ConnStr = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;" myConnection = New OleDbConnection(ConnStr) SQL = "select * from groups " myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "groups") dv = new DataView(ds.Tables("groups")) Application("Source") = dv End Sub Ich habe Datensätze aus der Groups-Tabelle extrahiert und eine Datenansicht (DataView) mit den Ergebnissen gefüllt. Dann habe ich diese Datenansicht in einer Anwendungsvariablen namens Source gespeichert. Da ich mit der Datenbank interagieren muss, war es notwendig, die Namensfelder (Namespaces) System.Data und System.ADO zu importieren. Ich kann nun die Source-Anwendungsvariable benutzen, um das DataGrid in einem Webformular zu füllen: 281 ASP.NET 282 10 Listing 10.4: ApplicationState.aspx Sub Page_Load(Src As Object, E As EventArgs) Dim Source As DataView = Application("Source") vSpan.InnerHtml = Source.Table.TableName vGrid.DataSource = Source vGrid.DataBind() End Sub DataSource in Application_OnStart Table: Abbildung 10.8 zeigt das Ergebnis: ASP.NET-Anwendungen 10 283 Der Anwendungs-Status Abb. 10.8 Sitzungsstatus Im Gegensatz zum Anwendungs-Objekt, das sich nur wenig von den früheren ASP-Versionen unterscheidet, hat das Session-Objekt (Sitzungs-Objekt) einige größere Veränderungen erfahren. Eine Sitzungsvariable ist ein Schlüsselwertpaar, das für die Dauer einer Internetsitzung eines Benutzers festgelegt und gelesen werden kann. Sie können beispielsweise auf folgende Weise einen Wert in einer Sitzungsvariablen (Session variable) speichern: Session("Name") = "Hersh Bhasin" Auf diese Sitzungsvariable kann auf einer Website folgendermaßen zugegriffen werden: Dim ls_name As string ls_name = Session("Name") Jeder Sitzung wird ein individueller Schlüssel zugewiesen, der in einem HTTP-Cookie gespeichert und bei jeder Anfrage an den Server gesendet wird. Der Server liest den Schlüssel und stellt den Serverstatus wieder her. Das Problem dieser Implementierung besteht darin, dass Benutzer diese Cookies aus Angst um ihre Privatsphäre möglicherweise ablehnen, wo- ASP.NET 284 10 durch ein Statusmanagement unmöglich gemacht wird. Ein weiteres Problem besteht darin, dass dieses Statusmanagement mit dem Webserver verbunden ist, so dass bei einer Erneuerung oder einer Fehlfunktion des Servers die Statusinformationen verloren gehen. Der dritte Nachteil besteht darin, dass jeder ASP-Server seinen eigenen Status aufrecht erhält und der Benutzerstatus verloren geht, wenn der Benutzer nicht wieder zu demselben Server zurückkehrt. Dies ist immer dort der Fall, wo ISPs Proxy load balancing-Lösungen einsetzen. ASP.NET löst dieses Problem. Der ASP.NET-Sitzungsstatus ist prozessunabhängig. Das bedeutet, dass selbst bei einem Ausfall oder Neustart des Servers der Status aufrecht erhalten wird. Der Sitzungsinhalt kann in der Datenbank eines SQL-Servers fortgesetzt und die Statusinformationen nach einem Server-Fehler wieder neu geladen werden. Die Benutzung von Sitzungsvariablen war häufig ein Problem in Webfarmen, wo mehrere Server Benutzeranfragen bearbeiten. Dieses Problem gibt es nicht mehr. Durch das prozessunabhängige Modell ermöglicht es ASP.NET den Benutzern in einer Webfarm den Prozess des Sitzungsstatus gemeinsam zu nutzen. Die Konfiguration des Sitzungsstatus wird von den Einstellungen in der web.config-Datei vorgenommen. Diese Datei wird später im Kapitel noch sehr ausführlich erläutert. Die voreingestellte Datei (machine.config) befindet sich im Verzeichnis ...\Frameworkl\[Version]\ des Windows-Ordners (z.B. WinNT\Framework\[Version]). Jede Anwendung kann über eine eigene web.config-Datei verfügen, wobei die darin enthaltenen Einstellungen die machine.config-Datei überschreiben. Die folgenden sechs Einstellungen können zur Konfiguration des Sitzungsstatus () vorgenommen werden: Mode: Inproc, SQLServer, und StateServer. InProc steht für In-Process und ist die traditionelle Einstellung im ASP-Statusmanagement. Es gibt zwei Arten von prozessunabhängigen Modi: speicherbasiert (State-Server) und SQL-Server-basiert (SQL-Server). Diese Arten werden später noch genauer erklärt. Cookieless: Entweder wahr oder falsch (true oder false). Die Grundeinstellung ist false. True impliziert, dass der Modus aktiviert ist. ASP.NET-Anwendungen 10 Timeout: Dauer, für die eine Sitzung als gültig angese- hen wird. SqlConnectionString: Wird im SQL-Server-Modus verwendet. Spezifiziert den Verbindungs-String zur Datenbank für das ASP.NET-Statusmanagement. StateConnectionString: Wird im State-Servermodus verwendet. Identifiziert die TCP/IP-Adresse und den Port des Windows NT-Service, der das Statusmanagement liefert. Ich habe ein Test-Webformular erstellt, das ich für meine Erläuterungen verwende. Das Formular hat zwei einfache Funktionen zur Bestimmung der Sitzungsvariablen und zum Wiederfinden des Wertes dieser Variablen, wie Sie in der folgenden Codeliste erkennen können: Listing 10.5: Session.aspx Sub AddSession(sender As Object, e As EventArgs) Session("MySession") = text1.Value message.text = "Session Variable stored as : " +Session("MySession").ToString() End Sub Sub CheckVariable(sender As Object, e As EventArgs) If Session("MySession") = "" Then message.text = "Session Data has been erased" Else message.text = "Stored Session Variable is : " + Session("MySession").ToString() End If End Sub Session State 285 ASP.NET 286 10 Prozessabhängiger Modus Dies ist der traditionelle Modus, in dem ASP das Statusmanagement gehandhabt hat. Der Status wird innerhalb des Prozesses verwaltet und geht verloren, sobald der Prozess erneuert wird. Vielleicht fragen Sie nach dem Sinn dieses Modus, da es doch auch den viel effizienteren, prozessunabhängigen Modus gibt. Der Grund hierfür ist die Leistung. Prozessunabhängige Modi verursachen zusätzliche Kosten, da die Daten ständig zwischen Prozessen oder SQL-Servern hin- und hertransportiert werden müssen. Zur Erstellung eines Statusmanagements in diesem Modus führen Sie die folgenden Schritte durch: 1 Setzen Sie das mode-Attribut des sessionState in der web.config-Datei auf InProc (die Grundeinstellung). Wenn diese Einstellung gewählt wurde, sind Timeout und Cookieless die einzigen anderen web.config-Einstellungen. 2 Starten Sie Session.aspx. Speichern Sie einen Wert des Sitzungsstatus. Stoppen Sie die IIS und starten Sie diese erneut mit Hilfe der Befehlszeilen-Utility iisreset, die in IIS5 enthalten ist: C:\iisreset [computername] /RESTART (or simply issue the command iisreset from the command prompt) ASP.NET-Anwendungen 10 3 Klicken Sie auf den Button Check Session Variable (Sitzungsvariable überprüfen). Sie werden sehen, dass die Sitzungsvariable verloren ging. Der Code für dieses Beispiel befindet sich im Unterverzeichnis ...\samples\sessionstate\inprocess für dieses Kapitel auf der CD dieses Buches. Prozessunabhängiger Modus Der prozessunabhängige Modus hält den Status in einem separaten Prozess aufrecht. Dieser Modus vereint die Verlässlichkeit eines separaten Prozesses mit dem Leistungsvorteil des Lesens und Schreibens aus einem Speicher. Dieser Modus sollte verwendet werden, wenn Leistung ein wichtiger Punkt ist, Sie aber nicht voraussagen können, welchen Server ein Benutzer zur Anforderung einer Anwendung verwendet. Beachten Sie die folgenden Schritte zur Einstellung dieses Modus: 1 Setzen Sie das Mode-Attribut von SessionState in der web.config-Datei auf StateServer. Hierdurch wird ASP.NET angewiesen, auf dem Server nach dem ASP.NET-Status-Service und in der web.config-Datei, die in diesem Fall der lokale Server ist, nach den spezifizierten Server- und Port-Einstellungen zu suchen. 2 Das ASP.NET SDK beinhaltet einen Windows NT Service namens aspnet_state, der von ASP.NET zur prozessunabhängigen Statusverwaltung genutzt wird. 287 ASP.NET 288 10 Starten Sie diesen Service durch Eingabe der folgenden Befehlszeile: net start aspnet_state Abbildung 10.9 zeigt das Ergebnis. Starten des ASPStateService Abb. 10.9 3 Starten Sie Session.aspx. Speichern Sie einen Wert des Sitzungsstatus. Stoppen Sie die IIS und starten Sie diese erneut mit Hilfe der Befehlszeilen-Utility iisreset, die in IIS5 enthalten ist: 4 Klicken Sie auf den Button Check Session Variable. Sie werden sehen, dass der Status beibehalten wurde. Der Code für dieses Beispiel befindet sich im Unterverzeichnis ...\samples\sessionstate\Outofprocess für dieses Kapitel auf der CD dieses Buches. SQL-Server-Modus Dieser Modus sollte gewählt werden, wenn Zuverlässigkeit Ihr oberstes Gebot ist. Die Datenbank kann gruppiert werden, um Server-Fehler zu bearbeiten. Der Nachteil dieses Modus ist die schlechtere Leistung. Dieser Modus kann folgendermaßen eingestellt werden: ASP.NET-Anwendungen 10 1 Erstellen Sie die ASPState-Datenbank mit Hilfe der in ASP.NET im Ordner ...\Microsoft.NET\Framework\[Version]\ enthaltenen Datei InstallSqlState.sql und der osql.exe-utility: osql -S [server name] -U [user] -P [password] < InstallSqlState.sql Sie können die Datei auch direkt im SQL Query Analyzer-Tool des Microsoft SQL-Servers öffnen und ausführen. (Diese Methode ist vorteilhaft, weil Sie sich keine Passwörter, Server-Namen oder Ähnliches merken müssen. Sie können sich mit der SystemadministratorBerechtigung einloggen und das Skript ausführen.) Dieser Prozess erstellt eine Datenbank namens ASPState, die 16 gespeicherte Prozeduren und 2 Tabellen in temp.db enthält. Die Tabellen sind AspStateTempSessions und AspStateTempApplications. Starten Sie den SQL-Server neu, da einige Startprozeduren erstellt wurden, die nun ausgeführt werden müssen. Ein Skript zur Deinstallation der ASPState-Datenbank ist ebenfalls enthalten. Das Skript hat den Namen UninstallSqlState.sql. 2 Setzen Sie das Mode-Attribut von SessionState in der Konfigurations-Datei auf SQL-Server. 289 ASP.NET 290 10 3 Starten Sie Session.aspx. Speichern Sie einen Wert des Sitzungsstatus. Stoppen Sie die IIS und starten Sie diese erneut mit Hilfe der Befehlszeilen-Utility iisreset, die in IIS5 enthalten ist: 4 Klicken Sie auf den Button Check Session Variable. Sie werden sehen, dass der Status beibehalten wurde. 5 Stellen Sie eine Verbindung mit der Tempdb-Datenbank her und führen Sie die folgenden Anfragen aus: Beibehaltener Status im SQL-Server Abb. 10.10 select * from AspStateTempSessions select * from AspStateTempApplications Die Daten werden in den Tabellen AspStateTempSessions und AspStateTempApplications des SQL-Servers gespeichert. Eine individuelle Sitzungs-ID wird in der Datenbank gespeichert. Abbildung 10.10 zeigt das Ergebnis. Sie könnten die Zuverlässigkeit beim Speichern des Sitzungsstatus noch weiter erhöhen, wenn Sie die SQL-Server gruppieren, so dass bei einem Ausfall eines Servers ein anderer den Status repliziert und einspringt. ASP.NET-Anwendungen 10 Cookiefreier Status Dieses Feature des ASP.NET-Sitzungsstatus ermöglicht Clients, den Cookie abzuschalten und trotzdem die Vorzüge von ASP.NET zu genießen. In diesem Modus wird die Sitzungs-ID in den URL gequetscht: http://localhost/( hmxz0d5554l1bt45faqudj55)/Application/Sessione.aspx Um diesen Status zu aktivieren, müssen Sie lediglich das Cookieless-Attribut auf True setzen: Cookiefreie Sitzungen werden von allen Modi unterstützt. Die Konfigurationsdatei ASP.NET kann mit Hilfe zweier Konfigurationsdateien (machine.config und web.config) konfiguriert werden. Jeder Rechner verfügt über eine einzelne machine.config-Datei, in der Informationen zur Grundkonfiguration enthalten sind. Jede Anwendungsdatei kann optional eine eigene web.config-Datei haben. Wenn eine solche Datei existiert, so übersteuert sie die machine.config-Datei im Ordner WinNt\Framework\[Version]\. Die lokale web.config-.Datei kann nur die Bereiche beinhalten, die sie benötigt. Diese Bereiche übersteuern dann die voreingestellte machine.config-Datei. Die nicht in der lokalen web.config-Datei spezifizierten Bereiche werden dann von der machine.config-Datei gelesen. Diese Konfigurationsdateien sind XML-basierte Textdateien. Hier ein Beispiel für eine Konfigurationsdatei mit zwei Einstellungen: 291 ASP.NET 292 10 Diese Dateien sind nicht direkt über einen Browser zugänglich. Das vorige Beispiel zeigt eine Datei mit zwei Konfigurationsbereichen: und . Da der sessionStateBereich bereits beschrieben wurde, folgen hier nun Erläuterungen zu einigen anderen Bereichen dieser Datei. Dies ist das Ur-Element. Alle Konfigurationsbereiche müssen zwischen den Configuration-Markierungen enthalten sein. Der appSettings-Bereich ermöglicht es Ihnen, die web.configDatei als ini-Datei zu benutzen. Sie können hierin anwendungsweite Einstellungen speichern, wie etwa den DSN-Namen, der dann für alle Seiten in der Anwendung verfügbar ist: Nehmen Sie in der web.config-Datei folgende Einstellung vor: Add ist das einzige Subelement dieses Bereiches. Das Subelement Add unterstützt zwei Attribute: Key und Value. Key ist der Name der Variablen, die im Value-Attribut gespeichert wird. Sie können so viele Add-Subelemente haben, wie Sie benötigen. ASP.NET-Anwendungen 10 Auf einer Website werden Sie den gespeicherten Wert mit Visual Basic.NET folgendermaßen extrahieren: Listing 10.6: AppSettingVb.aspx Sub Page_Load(Src As Object, E As EventArgs) Dim dsn As String = ConfigurationSettings.AppSettings("dsn") response.write(dsn) End Sub Dieser Code befindet sich im Ordner ...\samples\configFile\configAppSettings auf der CD des Buches. Hier ist der gleiche Code in C#: Listing 10.7: AppSettingC.aspx public void Page_Load(Object sender, EventArgs e) { String s = ConfigurationSettings.AppSettings["dsn"]; dsn.InnerHtml =s; } Der DSN-Eintrag in der web-config-Datei ist: Diese Sektion hat ein Attribut (debug) und zwei Unterbereiche ( und ). Das Debug-Attribut ist eine Boolean-Einstellung, die auf True oder False gesetzt werden kann. Bei True wird die Datei im Debug-Modus (Fehlersuche) kompiliert. Das dauert ein wenig länger und daher sollte diese Option in Produktionsseiten (production sites) abgeschaltet werden. 293 ASP.NET 294 10 Im Compiler-Bereich stellen Sie die Sprache und die Erweiterungsattribute für jede Sprache, die Sie verwenden, ein. Wenn Sie beispielsweise die Sprache Visuals Basic mit der Erweiterung vb versehen, werden alle Webformulare mit dieser Erweiterung Visual Basic als voreingestellte Skriptsprache haben, so dass Sie diese nicht noch einmal in der Seitendirektive oder den Skriptmarkierungen definieren müssen. Der Unterbereich ermöglicht Ihnen zu spezifizieren, welche Zusammensetzungen (Assemblies) Sie in die Kompilierung einer Ressource integrieren möchten. Sie werden sich erinnern, dass Sie bei der Erstellung von Business-Objekten (Kapitel 8) und benutzerdefinierten Kontrollen (Kapitel 7) verschiedene Zusammensetzungen in die bat-Dateien, welche die von Ihnen erstellten Objekte kompilieren, integrieren mussten. Hier können wir die Zusammensetzungen spezifizieren. Sie müssen diese Zusammensetzungen aber immer noch mit Hilfe der Seitendirektive in die Website importieren. Das -Unterelement hat drei Subelemente: Add, Remove und Clear. Das Add-Unterelement fügt Zusammensetzungen hinzu. Sie können * benutzen, um alle Zusammensetzungen im bin-Verzeichnis hinzuzufügen. Remove entfernt den Bezug zu einer Zusammensetzung und Clear entfernt alle Bezüge, die in der Datei config.web enthalten oder aus ihr entstanden sind. ASP.NET-Anwendungen 10 ASP.NET bietet eine ganze Reihe nützlicher Informationen bei Auftreten eines Fehlers. Dies mag für Entwickler ganz nützlich sein, wird die Benutzer der Site aber möglicherweise erschrecken. Die Custom Error-Einstellung ermöglicht es Ihnen, eine benutzerdefinierte Fehlerseite zu erstellen, die benutzerdefinierte Fehlermeldungen anzeigt. Sie können auch bestimmte Fehler (z.B. Fehlercode 404 oder 500) zu separaten, benutzerdefinierten Fehlerseiten zurückleiten. Der benutzerdefinierte Fehlerbereich hat zwei Attribute: defaultRedirect: Spezifizieren Sie hier Ihre benutzerdefinierte Fehlerseite. Mode: On, Off oder RemoteOnly. Der On-Modus leitet alle Fehler zur benutzerdefinierten Fehlerseite zurück. Der Off-Modus schaltet benutzerdefinierte Fehler aus und der RemoteOnly-Modus schaltet die benutzerdefinierten Fehler nur für Fernabfragen ein – wenn Sie sich auf dem gleichen Server befinden und einen Fehler verursachen, sehen Sie dessen komplette Details, während die Benutzer der Site nur die benutzerdefinierte Fehlermeldung sehen. Diese Option kann recht hilfreich sein, da der Entwickler mit allen Fehlerinformationen versorgt wird. Sie werden nun lernen, eine benutzerdefinierte Fehlerseite zu erstellen (custom error page). Der Code zu diesem Beispiel befindet sich im Unterverzeichnis ...\samples\configFile\ CustomErrors auf der CD des Buches. Listing 10.8: web.config für benutzerdefinierte Fehler 295 ASP.NET 296 10 Ich habe die Datei als HandleError.aspx spezifiziert: Listing 10.9: HandleError.aspx body {font-family:Tahoma,Arial,sans-serif; fontsize:10pt} Default Custom Error Page There was an error in the page Return to the previous page Ich habe eine Testseite erstellt und versuche zu einer nicht in dieser Datei existierenden Seite zu navigieren und verursache so einen Fehler. Hier ist die Codeliste dazu: Listing 10.10: ErrorTest.aspx Sub cause_error(Source As Object, E As EventArgs) Response.Redirect("NonExistantPage.aspx") End Sub Der Bereich unterstützt einen Unterbereich: Das Subelement . Sie können Subelemente verwenden, um bestimmte Fehlernummern zu Ihrer eigenen benutzerdefinierten Fehlerseite zurückzuleiten, wie das folgende Beispiel zeigt: ASP.NET-Anwendungen 10 Alle Fehler mit dem dem Status-Code 500 werden hierdurch zu der benutzerdefinierten Fehlerseite 500Error.aspx zurückgeleitet. Der Unterbereich Globalization hat die folgenden fünf Attribute: requestEncoding: Dies ist die voreingestellte Codierung für alle Anfragen. responseEncoding: Dies ist die voreingestellte Codierung für alle Antworten. FileEncoding: Dies ist die voreingestellte Codierung für alle aspx-, asmx- und aspc-Dateien. Culture: Dies ist die voreingestellte Kultur für die Bearbeitung von Anfragen. Sie enthält Informationen bezüglich Sprache, Kalender und Schreibsystem wie beispielsweise English = en. Informationen hierzu finden Sie im Namensfeld System.Globalization in der CultureInfo-Klasse. uiCulture: Dies ist die voreingestellte Kultur für das Suchen nach Ressourcen, die einen CultureInfo-Wert wie etwa en erwartet. Hier ein Beispiel: 297 ASP.NET 298 10 httpHandlers ermöglicht es Ihnen, eingehende Anfragen an NET Framework-Klassen weiterzuleiten, die diese Anfragen bearbeiten können. Zum Beispiel: Diese Einstellung sagt dem Framework, dass alle Anfragen an die Datei mit der Erweiterung aspx von der NET FrameworkKlasse System.Web.UI.PageHandlerFactory bearbeitet werden sollen. Dieser Bereich hat die folgenden drei Attribute: verb: Dieses Attribut befiehlt dem .NET-Runtimemodul die Anfrage mit GET, POST oder PUT zu verarbeiten oder alle drei zu verwenden und durch ein Komma zu trennen (ein * impliziert das Gleiche). path: Der Pfad zu einer Datei (oder zu mehreren Dateien mit der gleichen Erweiterung), die verarbeitet werden soll. type: Der Name der Zusammensetzung oder Klasse, welche die Anfrage bearbeitet. Sie können Ihre eigenen httpHandler programmieren. Wenn Sie zum Beispiel den Zugang zu Webformularen mit der Bezeichnung default.aspx verweigern wollen, müssen Sie eine einfache Klasse programmieren und Anfragen an dieses Formular folgendermaßen bearbeiten: Listing 10.11: handler.vb Imports System.Web Namespace Hersh Public Class CustomHandlerVB : Implements IHttpHandler Public Sub ProcessRequest(Context As HttpContext) Implements IHttpHandler.ProcessRequest Context.Response.Write("Sorry! Access to ASP.NET-Anwendungen 10 this resource is Denied...") End Sub Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable Get Return true End Get End Property End Class End Namespace Mit dem IhttpHandler-Interface können Sie einen benutzerdefinierten HTTP Handler erstellen. Dieses Interface enthält nur zwei Methoden: IsResuable und ProcessRequest. Die IsReusableMethode sagt der Http-Factory, ob dieselbe Instanz zur Bearbeitung mehrerer Anfragen benutzt werden kann. ProcessRequest nimmt die HttpContext-Instanz als Parameter, wodurch die Antwort und die Anfrage inhärent zugänglich sind. Im vorigen Beispiel wurden die Anfragedaten ignoriert und ein String als Antwort zurückgegeben. Kompilieren Sie die Klasse jetzt folgendermaßen: Listing 10.12: make.bat set outdir=g:\aspNetSamples\bin\CustomHandlerVB.dll set assemblies=System.Web.dll vbc /t:library /out:%outdir% /r:%assemblies% handler.vb pause Vergewissern Sie sich, dass der outdir-Parameter auf Ihr lokales bin-Verzeichnis gerichtet ist. Fügen Sie der web.config-Datei den folgenden Abschnitt hinzu: 299 ASP.NET 300 10 Versuchen Sie nun, eine Datei namens default.aspx mit IIS zu öffnen. Sie werden eine Meldung erhalten, dass Ihnen der Zugriff auf diese Ressource verweigert wurde. Den kompletten Code für dieses Beispiel finden Sie im Unterverzeichnis ...\samples\configfile\httpHandler auf der CD des Buches. Dieser Bereich ermöglicht Ihnen die Konfiguration von HTTPModulen für Ihre Anwendungen. Die meisten Klassen und Zusammensetzungen, die Sie benötigen, sind bereits in der Grundeinstellung enthalten. Sie können diesen Bereich verwenden, um Ihre eigenen Handler hinzuzufügen. In diesem Bereich können Sie das Prozessmodell Ihrer Webanwendung konfigurieren. Hierzu stehen Ihnen eine Reihe von Einstellungsmöglichkeiten zur Verfügung: Die Attribute haben folgende Bedeutung: enable: Diese Boolean-Variable bestimmt, ob das Element aktiviert ist. Timeout: Die Dauer, nach der ein neuer IIS-Arbeitsprozess gestartet wird, um den alten Prozess zu ersetzen. IdleTimeout: Die maximale Leerlaufzeit eines Arbeitsprozesses. ShutDownTimeout: Die Dauer, nach der ein Arbeitsprozess automatisch beendet wird. RequestLimit: Die Anzahl der Anfragen, die ein Arbeitsprozess bearbeiten kann, bevor er beendet und durch einen neuen Prozess ersetzt wird. RequestQueueLimit: Die Anzahl der Anfragen, die sich ansammeln können, bevor ein Prozess wegen Überlastung beendet und durch einen neuen Prozess ersetzt wird. CpuMask: Kontrolliert die Anzahl der Arbeitsprozesse in Webgärten. WebGarden: Kontrolliert die Prozessoraffinität in Webgärten. Vielleicht möchten Sie auch mit den Einstellungen des memoryLimit experimentieren, um zu versuchen, die Leistung der Seite zu erhöhen. Ein Server mit geringem Speicher würde die Voreinstellung von MemoryLimit (40%) sehr schnell erreichen, wodurch der Prozess in einer Schleife neu gestartet und wieder beendet würde. 301 ASP.NET 302 10 Zusammenfassung In diesem Kapitel haben Sie einiges über die Konzepte von Anwendungen in ASP.NET erfahren. Sie haben auch die Global.asax und ihre Bedeutung für die Beibehaltung von Variablen im Anwendungsbereich kennen gelernt. Die Beibehaltung von Variablen in einem Sitzungsstatus hat, wie Sie gelernt haben, in ASP.NET eine radikale Änderung erfahren. Zu guter Letzt wurden in diesem Kapitel noch die web.config und ihre Unterbereiche erklärt. Zwei wichtige Unterbereiche der web.Config-Datei werden in separaten Kapiteln noch ausführlich erläutert. Es handelt sich hierbei um die Themen Tracing (Kapitel 12) und Sicherheit (Kapitel 13). Caching Output Caching 305 Page Data Caching 307 Datei- und Schlüsselabhängigkeit 308 Zusammenfassung 312 ASP.NET 304 11 Caching ist eine wichtige Technik beim Aufbau schneller und effizienter Websites. Die Theorie, die hinter Caching steht, besagt, dass einige Objekte der Website bei der Erstellung hohe Kosten verursachen. Solche Objekte sollten daher nur einmal erstellt und dann für einen festen Zeitraum oder bis zu ihrer Modifizierung gespeichert werden. Aufrufe erzeugen in diesem Fall dann keine neue Ressource, sondern finden diese im Cachespeicher. Im Allgemeinen handelt es sich hierbei um Ressourcen, die für einen längeren Zeitraum unverändert bleiben – beispielsweise Einkaufslisten und Preislisten. Das ASP.NETFramework selbst benutzt diese Cachespeicher. Wenn der erste Aufruf an eine ASP-Seite erfolgt, wird diese als Instanz der Seiten-Klasse kompiliert und im Cache des Servers gespeichert. Nachfolgende Anfragen an die Seite laden diese dann aus dem Cachespeicher, bis die Seite modifiziert wird oder die Speicherperiode ausläuft. Zu diesem Zeitpunkt wird der Cachespeicher aktualisiert. ASP.NET unterstützt zwei Cachearten: Output Caching Data Caching Output Caching bezeichnet das Speichern einer kompletten Seite. Diese Technik ist sehr nützlich bei stark frequentierten Seiten. Damit das Caching funktioniert, muss die von verschiedenen Benutzern angeforderte Seite in allen Aspekten identisch sein. Wenn die Anfragen nicht an identische Seiten gehen, können diese nicht aus dem Cachespeicher gezogen werden, sondern müssen bei jeder Anfrage neu generiert werden. Aus diesem Grund arbeitet das Output Caching mit GETAnfragen (und Anfragestrings), jedoch nicht mit POST. Bei einer GET-Anfrage kann das ASP-Runtime-Modul den Anfragestring betrachten und allen Anfragen mit identischem String die Cacheversion der Ressource zurückgeben. Data Caching beinhaltet die Identifizierung von Objekten oder Daten auf einer Seite, deren Konstruktion hohe Kosten verursacht, um nur diese Daten und Objekte zu speichern. Caching 11 Output Caching Output Caching wird durch eine einfache Direktive am Anfang der Seite durchgeführt: Diese Direktive besagt, dass die Seite für 10 Sekunden in Erinnerung bleibt. Die erste Anfrage an die Seite speichert diese im Cachespeicher. Für eine Dauer von 10 Sekunden wird nun allen Benutzern mit einer Anfrage an diese Seite die Cacheversion zurückgegeben. Hierdurch wird die Leistungsfähigkeit der Seite drastisch erhöht. Hier ein Beispiel: Listing 11.1: MastersGrid.aspx Masters Table Sub Page_Load(Source As Object, E As EventArgs) Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet Dim ConnStr As String Dim SQL As String 'Verbindungssyntax ConnStr = "Provider=SQLOLEDB; Data Source=(local);" ConnStr = ConnStr + " Initial Catalog=ASPNET; User ID=sa" myConnection = New OleDbConnection(ConnStr) 'DataSetCommand SQL = "select * from Masters" myCommand = New OleDbDataAdapter(SQL, myConnection) 'Benutze die Fill-Methode des DataSetCommand, um einen Datensatz zu füllen myCommand.Fill(ds, "Masters") 'Bindung eines Datengitters DataGrid1.DataSource=ds.Tables("Masters").DefaultView 305 ASP.NET 306 11 DataGrid1.DataBind() Anzeigen der Erstellungszeit TimeMsg.Text = DateTime.Now.ToString() End Sub Last generated on: Das Webformular bindet ein DataGrid an ein DataSet, das aus der Datenbank heraus gefüllt wird. Alle folgenden Anfragen der nächsten 60 Sekunden werden aus dem Cachespeicher bedient. Die last generated-Zeit zeigt Ihnen an, wann die Seite erstmalig generiert wurde. Für die nächsten 60 Sekunden wird bei der Aktualisierung des Browsers die gleiche Zeit angezeigt, wodurch erkennbar ist, dass die Seite aus dem Cachespeicher zurückgegeben wird. Wenn ein Anfragestring in allen Aspekten übereinstimmt, wird die Seite aus dem Cachespeicher gerendert. In allen anderen Fällen wird die Seite wie im folgenden Beispiel neu generiert: Listing 11.2: querystring.aspx Sub Page_Load(Src As Object, E As EventArgs) Dim querystring As String querystring = Request.QueryString("name") nameMsg.text = querystring TimeMsg.Text = DateTime.Now.ToString() End Sub QueryString & the Output Cache Caching 11 style="background-color:#AAAADD; border-color:black;bordercolor:black;width:700px;border-collapse:collapse;"> | ||||||||||||||||||||
Hersh | Bhasin | John | Smith | Bob |
User Name: | ||
Password: | ||
Persistent Cookie: |
Der Hauptteil des Formulars enthält zwei Textboxen: UserName und UserPassword sowie eine Checkbox PersistCookie. Wenn diese Checkbox markiert ist, bleibt der Cookie bestehen, das heißt, dass die Information nicht verloren geht, wenn der Browser geschlossen wird.
Sicherheit 13 Wenn der Benutzer auf den Login-Button klickt, wird das login_click-Event ausgelöst. Dieses erste Event benutzt die Authenticate-Methode der FormsAuthentication-Klasse, um die Daten des Benutzers zu authentifizieren. Wenn der Benutzer authentifiziert ist, wird die RedirectFromLoginPage-Methode verwendet, um den Cookie zu speichern (und um ihn beizubehalten, wenn die PersistCookie-Checkbox markiert wurde) und um den Benutzer zu der ursprünglich von ihm angeforderten Seite weiterzuleiten. Das default.aspx-Formular beinhaltet das Formular, welches der Benutzer ursprünglich angefordert hat und das ihm nach dem Login-Prozess angezeigt wird. Hier ist die entsprechende Codeliste: Listing 13.4: default.aspx Sub Page_Load(Src As Object, E As EventArgs) msg.Text = "Welcome, " + User.Identity.Name End Sub Sub Signout_Click(Src As Object, E As EventArgs) CookieAuthentication.SignOut() Response.Redirect("login.aspx") End Sub Using Cookie Authentication
Im page_load-Event dieser Seite wird mit der User-Klasse auf den Benutzernamen zugegriffen: msg.Text = "Welcome, " + User.Identity.Name
329
ASP.NET 330
13 Die User-Klasse ist aus einer Website heraus verfügbar und hat drei Methoden: IsAuthenticated, Name und Type. Die IsAuthenticated-Methode gibt einen Boolean-Wert zurück, der definiert, ob ein Benutzer authentifiziert wurde. Die NameMethode gibt den Benutzernamen zurück und die Type-Methode zeigt die Art der Authentifizierung an: Sub Signout_Click(Src As Object, E As EventArgs) CookieAuthentication.SignOut() Response.Redirect("login.aspx") End Sub
Abbildung 13.1 zeigt einen Screenshot der Login-Seite.
Die Login-Seite Abb. 13.1
Abbildung 13.2 zeigt einen Screenshot des erfolgreichen Logins.
Sicherheit 13
331
Ein erfolgreicher Login Abb. 13.2
Speicherung eines Passworts in einer Datenbank In diesem Beispiel werden Sie lernen, die formularbasierte Authentifizierung mit Passwörtern, die mit einer Datenbank verglichen werden, zu benutzen. Ich speichere die Passwörter in einer Zugriffsdatenbank namens security.mdb. Die Implementierung besteht aus drei Dateien: web.config, default.aspx und login.aspx. Diese Dateien befinden sich im Advanced-Verzeichnis des Beispielordners für dieses Kapitel auf der CD des Buches. Die web.config- und die default.aspx-Datei sind mit den bereits beschriebenen Dateien gleichen Namens identisch. Der einzige Unterschied besteht darin, dass in dieser web.configDatei keine Benutzerdaten gespeichert werden. Die einzige unterschiedliche Datei heißt login.aspx, deren Code hier aufgelistet ist: Listing 13.5: login.aspx (database version)
ASP.NET 332
13 Sub Login_Click(Src As Object, E As EventArgs) Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet Dim ConnStr As String Dim SQL As String Dim dv As DataView ConnStr = "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" & server.mappath("security.mdb") myConnection = New OleDbConnection(ConnStr) 'DataSet-Befehl SQL = "select * from passwords" myCommand = New OleDbDataAdapter(SQL, myConnection) 'Benutze Fill-Methode des DataSetCommand, um einen Datensatz zu füllen myCommand.Fill(ds, "passwords") dv = new DataView(ds.Tables("passwords")) dv.Sort = "UserName" dv.RowFilter = "UserName = '" + UserName.Value + "' and password = '" + UserPass.Value +"'" if dv.count >=1 then FormsAuthentication.RedirectFromLoginPage(UserName.Value , PersistCookie.Checked) Else Msg.Text = "Sorry Invalid username or password : Please try again" End if End Sub Login Page
User Name: | ||
Password: | ||
Persistent Cookie: |
In diesem Beispiel wird ein DataSet mit Reihen aus der Passwort-Tabelle der Datei security.mdb gefüllt. Anschließend wird die voreingestellte Ansicht des DataSet einem DataView zugeordnet und der Benutzername und das Passwort herausgefiltert: dv.Sort = "UserName" dv.RowFilter = "UserName = '" + UserName.Value + "' and password = '" + UserPass.Value +"'"
Anschließend wird die Anzahl der Reihen mit der count-Eigenschaft der Datenansicht (DataView) überprüft. Ist der Wert dieser Eigenschaft größer als 1, wird dem Benutzer der Zugang gewährt. In jedem anderen Fall werden die Daten zurückgewiesen: if dv.count >=1 then FormsAuthentication.RedirectFromLoginPage(UserName.Value , PersistCookie.Checked)
333
ASP.NET 334
13 Else Msg.Text = "Sorry Invalid username or password : Please try again" End if
Der Authentifizierungs-Provider Passport Der Authentifizierungs-Provider Passport ist ein zentraler Authentifizierungs-Service, der von Microsoft angeboten wird. Er enthält single sign-in- und core-profile-Services für Mitgliederseiten. Wenn Sie einen Hotmail-Account besitzen, wird Passport verwendet, um Sie zu authentifizieren. Gerade zu diesem Zeitpunkt hat Microsoft neue Informationen und ein Weißbuch bezüglich Hailstorm veröffentlicht. Das Produkt ist eine wichtige Technologiekomponente von Microsofts .NET-Vision und wird Webversionen von Hotmail, MSN Messenger und dem Authentifizierungsprodukt Passport enthalten. Passport wird als eine Art Personalausweis für das Internet dienen. Ihre kritischen persönlichen Daten werden an einem zentralen Ort gespeichert. Sie haben zu jedem Zeitpunkt die volle Kontrolle über diese Daten. Dadurch können Sie für alle Partner-Websites den gleichen Benutzernamen und das gleiche Passwort benutzen. Das Gleiche gilt für Ihre Adressbücher und Ihre Bookmarks. Diese sind dann von jedem Computer der Welt aus über das Web zugänglich und würden nur einmal erstellt. Der allgemeine Implementierungsprozess der Passport-Authentifizierung läuft folgendermaßen ab: 1
Laden Sie Passport SDK von der Site http://www .passport.com/business herunter und installieren Sie das Programm. Sie müssen sich hierfür registrieren und Gebühren zahlen.
2
Konfigurieren Sie Passport als den Authentifizierungsmodus in der Konfigurationsdatei:
Sicherheit 13 3
Implementieren Sie die Passport-Authentifizierung und die Autorisierung entsprechend den Anweisungen in der Passport-Dokumentation.
Dieses Programm erfordert die Passport-Registrierung der Benutzer einer Website. Benutzer können sich durch Einrichtung eines Hotmail- oder MSN-Accounts registrieren. Sie können auch direkt auf die Passport-Seite gehen und sich dort registrieren. Wenn ein Benutzer eine geschützte Ressource anfordert und die Anfrage kein gültiges Passport-Ticket enthält, so wird eine 302-Fehlermeldung angezeigt und der Benutzer auf die Passport-Seite zurückgeleitet. Die verschlüsselten Parameter der ursprünglichen Anfrage werden mit dem Anfrage-Service an Passport weitergeleitet. Passport präsentiert ein LoginFormular, das die geforderten Daten über SSL (Secure Socket Layers) zurücksendet. Der Passport-Loginserver authentifiziert den Benutzer und leitet ihn zu der ursprünglichen URL zurück, wobei das Authentifizierungs-Ticket im Anfragestring verschlüsselt wird. Der Server entdeckt das Fehlen eines Cookies und die Existenz des Authentifizierungs-Tickets im Anfragestring und erstellt daraufhin einen Authentifizierungs-Cookie. Nachfolgende Anfragen an die Ressource werden durch das gelieferte Ticket authentifiziert.
Windows-basierte Authentifizierung Windows oder IIS bieten eine geradlinige Authentifizierung. Aktivieren Sie einfach die IIS-Basisauthentifizierung im IIS MMC. Geben Sie an, welchen Benutzern Zugang zu einer bestimmten Webanwendung gewährt werden soll, und legen Sie Windows als Authentifizierungsmodus in der Konfigurationsdatei fest.
Aktivierung der Basissicherheitsauthentifizierung Im folgenden Beispiel wird Windows NT verwendet:
335
ASP.NET 336
13 1
Öffnen Sie IIS MMC. Klicken Sie mit der rechten Maustaste auf Default Website und wählen Sie Properties/Directory/Security/Edit.
2
Markieren Sie die Basic Authentication-Checkbox wie in Abbildung 13.3 gezeigt
Konfiguration der Genehmigungen Nun müssen Sie noch ACL (access control lists) auf der Basis der Gruppen oder Benutzer Ihrer Anwendung einstellen. 1
Wählen Sie den physischen Ordner Ihrer Anwendung (nicht den virtuellen Ordner). Klicken Sie mit der rechten Maustaste darauf und wählen Sie das Register Security. In Windows NT sehen Sie den Bildschirm nun wie in Abbildung 13.4 gezeigt.
2
Konfigurieren Sie ACL auf der Basis der Gruppen oder Benutzer Ihrer Anwendung.
Konfigurieren der Genehmigung in Windows NT Abb. 13.3
Sicherheit 13
Aktivierung der Basissicherheit Abb. 13.4
Editieren der Web.config-Datei Modifizieren Sie den Sicherheitsbereich der web.config-Datei, um die Windows-Authentifizierung zu aktivieren:
Wenn ein Benutzer versucht, auf eine Ressource in der Anwendung zuzugreifen, wird er gebeten, sich einzuloggen, wie in Abbildung 13.5 zu sehen ist.
Zusammenfassung ASP.NET bietet in Kombination mit IIS einige nützliche Sicherheits-Features. Die formularbasierten Sicherheitsoptionen bieten größtmögliche Flexibilität. Die Beispiele aus diesem Kapitel können ohne weiteres in echten Websites verwendet werden. Der Authentifizierungs-Provider Passport muss noch
337
ASP.NET 338
13
Windows-basierter Login Abb. 13.5
auf seine Akzeptanz geprüft werden. Zurzeit wird dieser Provider von Firmen wie American Express, Click Commerce, eBay, Expedia.com und Groove Networks benutzt. Glaubt man den Visionen von Microsoft, nach denen Passport eine wichtige Rolle im .NET-Design spielen soll, werden sicherlich noch weitere Unternehmen folgen.
Projekt 1: Webservices
ASP.NET 340
Projekt 1 – Überblick Mit ASP.NET und Webservices könnten Sie Anwendungen erschaffen, die Daten senden und empfangen können, indem sie das Internet und das HTTP-Protokoll benutzen. Sie könnten z.B. eine persönliche Finanzbuchhaltungssoftware webfähig machen und über das Internet benutzen. Die Konsequenzen dieser Betrachtungsweise können sich über weite Gebiete erstrecken. Stellen Sie sich einen Fall vor, bei dem ein Automobilhersteller auf eine große Anzahl von Zulieferfirmen angewiesen ist, die ihn mit Einzelteilen wie Luftfiltern, Scheibenwischern, Reifen usw. beliefern. Diese Zulieferunternehmen wären nun über die gesamte Welt verstreut. Dieser Automobilhersteller arbeitet mit Just in time-Fertigungstechniken und die Zulieferfirmen produzieren (und beliefern) nur so viel, wie der Hersteller in einer bestimmten Periode verbraucht. Dadurch wird beiderseitig die Lagerung des Inventars vermieden. Nehmen wir an, ein ausländisches Unternehmen fertigt Luftfilter für den Automobilhersteller. Es würde tagtäglich aktuelle Informationen über den Luftfilterverbrauch des Automobilhersteller benötigen, um die eigene Herstellung dementsprechend anzupassen. Dafür bräuchte der Zulieferer Zugriff auf den täglichen Produktionsbedarf des Automobilherstellers, der andererseits auf den Zugriff auf die Produktions- und Inventarzahlen des Zulieferunternehmens im Ausland angewiesen ist. Müssten Sie dafür eine Satellitenverbindung zwischen den beiden Unternehmen aufbauen, um ihre Datenbanken miteinander verknüpfen zu können? Eine Einzelhandelskette hat Filialen über das ganze Land verteilt. Jedes Mal, wenn ein Kunde einen Erwerb tätigt, muss der verkaufte Artikel aus dem Inventar gelöscht werden und der Geldbetrag in den Finanzbüchern als Umsatz verbucht werden. Angenommen, alle einzelnen Filialen dieser Kette greifen auf dieselbe Datenbank zu. Würden Sie dafür eine Netzwerkinfrastruktur aufbauen wollen? Und was würde das für Kosten verursachen? In den beiden vorangegangenen Beispielen müssen wir Verbindungen zwischen verschiedenen Datenbanken an weit entfernten Orten aufbauen. Um dies zu erreichen, würden wir herkömmlicherweise eine Netzwerkinfrastruktur aufbauen.
Projekt 1: Webservices 341 Sie könnten die Datenbanken jedoch auch mit Webservices über das Internet miteinander verlinken. Eine Anwendung, die mit einer Datenbank interagiert, muss grundsätzlich die Möglichkeit bieten, Datensätze von der Datenbank zu selektieren, einzufügen, zu aktualisieren und zu löschen. Mit Hilfe von Webservices können wir die Datenbankinteraktionslogik über eine Folge von Methodenaufrufen über das Internet erreichen. Wenn wir die Fähigkeit haben, über das Web auf die Datenbank zuzugreifen, bräuchten wir keine teuren Satelliten- oder Direktverbindungen zwischen den Anwendungen und den Datenbanken. Eine Benutzerschnittstelle im Browser kann durch die ASP.NETTechnologie mit Datenbanken kommunizieren. Durch weitere Tools, wie Visual Basic.NET und C#, können Sie Anwendungen erstellen, die benutzerfreundlich sind und eine ansprechendere Benutzerschnittstelle bieten. Benutzer haben sich zum Beispiel daran gewöhnt, Symbolleisten, MDI (multiple document interface) und andere graphische Leckerbissen in Anwendungen vorzufinden. Mit einem Browser können Sie das natürlich nicht erzeugen. Wäre es nicht schön, wenn Sie eines dieser Entwicklungstools einsetzen und trotzdem über das Internet kommunizieren könnten? Wir würden dann in der Lage sein, Anwendungen mit einer umfangreichen graphischen Oberfläche zu erstellen, ohne aufwändige Netzwerksysteme aufbauen zu müssen. Genau dafür gibt es die Webservices. In diesem Projekt werde ich Ihnen zeigen, wie Sie generische Datenbankzugriffsdienste erstellen und diese dann in Visual Basic.NET-, C#oder ASP.NET-Anwendungen einbinden können. Sie werden außerdem einen persönlichen Finanzbuchhalter erstellen, der diesen Webservice mit ASP.NET verwenden wird. Sie können eine moderne Anwendung (mit all Ihren graphischen Feinheiten) in Visual Basic.NET oder C# entwickeln und weiterhin diesen Webservice verwenden.
Aufbau eines generischen Datenbank-Webservices
ASP.NET 344
14 In Kapitel 8 Business-Objekte wurde Ihnen gezeigt, wie Sie ein generisches Datenbank-Objekt erzeugen können, um mit einer Datenbank zu kommunizieren. Dieses Objekt hatte die Möglichkeit, Datenbankabfragen wie Insert, Update und Delete auszuführen. Basierend auf SQL-Benutzerabfragen konnte dieses Objekt auch eine allgemeine Routine ausführen, um einen Datensatz zurückzugeben. Dieser Datensatz konnte dann dazu benutzt werden, um ein ASP.NET-Servercontrol zu binden. Ich werde Ihnen zeigen, wie Sie dieses Business-Objekt in einen Webservice konvertieren können. Verschiedenste Buchhaltungsmodule können dann auf die Funktionen zugreifen, die durch den Webservice gegeben sind. Ich werde Sie nun durch den Prozess der Erstellung eines Webservices leiten. Dazu sind einige Schritte notwendig: 1
Erstellen Sie die asmx-Datei für den Webservice: Benutzen Sie dafür NotePad und legen Sie eine Datei mit dem Namen SQLService.asmx und folgendem Inhalt an:
Listing 14.1: SQLService.asmx Imports System Imports System.Web.Services Imports System.Data Imports System.Data.OleDb Imports System.Text Public Class SQLService: Inherits WebService Public Function TestFunction (vInput as Boolean) As String If (vInput = TRUE) Then TestFunction = "It is the truth..." Else TestFunction = "False!False!False" End if End Function Public Function add( a as integer, b as integer) as string add = cstr(a+b) End function
Aufbau eines generischen Datenbank-Webservices 14
Public Function Populate(ConnStr as string, SQL as string) As DataSet Dim dv As DataView Dim i As integer Dim myConnection As OleDbConnection Dim myCommand As OleDbDataAdapter Dim ds As New DataSet myConnection = New OleDbConnection(ConnStr) myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "vTable") 'Populate = ds.Tables("vTable").DefaultView Populate = ds End Function PUBLIC Function RunSql ( ConnStr as string, vsql as string) as String Dim Message As string try message = "Success" Dim myConnection As OleDbConnection myConnection = New OleDbConnection(ConnStr) Dim mycommand As New OleDbCommand(vsql,myConnection) myConnection.Open() myCommand.ExecuteNonQuery() myConnection.Close() Catch ex As OleDbException Dim errItem As OleDbError Dim errString As String For Each errItem In ex.Errors errString += ex.Message + " " Next Message = "SQL Error.Details follow:" & errString Catch myException as Exception message = "Exception: " + myException.ToString() End try RunSql = message End Function End Class
345
ASP.NET 346
14 Das ist genau der gleiche Code, den wir gemeinsam in Kapitel 8 Business Objekte erarbeitet haben, deswegen werde ich ihn hier nicht noch einmal im Detail besprechen. Die Unterschiede sind, dass die Datei eine asmxEndung hat, die Klasse von WebService erbt, ein WebService-Attribut in der Kopfzeile eingefügt wurde, der System.Web.Services-Namensraum (namespace) importiert wurde und jede Funktion mit einem -Tag gekennzeichnet wurde. Das WebMethodTag signalisiert der ASP.NET-Runtime, dass die entsprechende Methode über das Internet aufgerufen werden kann. 2
Erstellen Sie die WSDL-Datei: Öffnen Sie SQLService.asmx, so dass es durch IIS aufgerufen wird (wie zum Beispiel http://localhost/Ihr_virtueller_Ordner/SQLService.a smx). Klicken Sie auf Zeige WSDL. Speichern Sie die erzeugte Datei als SQLService.wsdl. Beachten Sie, dass Sie das Gleiche auch erreichen können, wenn Sie http://localhost/Ihr_virtueller_Ordner/SQLService. asmx?wsdl im Browser aufrufen.
3
Erstellen und kompilieren Sie den Proxy. Führen Sie msqlProxy.bat aus, welches den Proxy SQLService.cb im lokalen Ordner erstellt und die kompilierte DLL SQLService.dll im bin-Ordner erstellt.
Listing 14.2: MsqlProxy.bat REM ------------Erstelle Proxy-----------wsdl.exe /l:VB /n:NameSpaceHersh /out:SqlService.vb SqlService.wsdl REM ------------Kompiliere Proxy-----------Rem Bitte ändern Sie die outdir-Variable, so dass sie auf Ihren bin-Ordner verweist. set outdir=g:\AspNetSamples\bin\SQLService.dll set assemblies=System.dll,System.Web.dll,System.Data. dll,System.Web. Services.dll,System.Xml.dll vbc /t:library /out:%outdir% /r:%assemblies% SQLService.vb pause
Aufbau eines generischen Datenbank-Webservices 14 4
Testen Sie den Service: Das Formular, das ich geschrieben habe, um diesen Service zu testen, heißt SQLService.aspx und hat den folgenden Code:
Listing 14.3: SQLService.aspx Dim SQL as string, vcn as string Sub Page_Load(Source As Object, E As EventArgs) vcn= "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) rebind end if End Sub Sub Show_Click(Sender As Object, E As EventArgs) Message.Text = "Masters-Tabelle angezeigt... " ReBind End Sub Sub Insert_click(Sender As Object, E As EventArgs) sql = "Insert into Masters(code_display,code_category,type)" sql = sql + "Values ('test',701,'E')" RunSQL(sql) rebind Message.Text = " ..Test-Aufzeichnung eingefügt... " End Sub Sub Delete_click(Sender As Object, E As EventArgs) sql = "delete from masters where code_display = 'test'" RunSQL(sql) rebind
347
ASP.NET 348
14 Message.Text = "...alle Test-Aufzeichnungen gelöscht..." End Sub Sub Update_Click(Sender As Object, E As EventArgs) sql = "UPDATE Masters Set Opening = 90 WHERE code_display = 'test'" RunSQL(sql) rebind Message.Text = "...alle TestAufzeichnungen aktualisiert: Setze closing balance = 90...! " End Sub Sub ReBind() Dim t As NameSpaceHersh.SqlService = New NameSpaceHersh.SqlService() Dim vsql as string Dim ds as DataSet vSQL = "select * from Masters" ds = t.Populate(vcn, vSql) DataGrid1.DataSource=ds.Tables("vTable").DefaultV iew DataGrid1.DataBind() End Sub Function RunSQL (vSQL as String) Dim t As NameSpaceHersh.SqlService = New NameSpaceHersh.SqlService() t.RunSQL(vcn,vSQL) End Function ASP .NET Webservices
Aufbau eines generischen Datenbank-Webservices 14
In dem Page_load-Event spezifiziere ich den Connection-String als vcn= "Provider=SQLOLEDB; Data Source=(local);Initial Catalog=ASPNET;User ID=sa;"
Der Sub ReBind ruft die Populate-Funktion des Webservices auf und übergibt ihr die Query select * from Masters sowie den Connection-String. Die Populate-Funktion gibt einen Datensatz zurück, dessen Default View an das DataGrid wie folgt gebunden ist: Sub ReBind() Dim t As NameSpaceHersh.SqlService = New NameSpaceHersh.SqlService() Dim vsql as string Dim ds as DataSet vSQL = "select * from Masters" ds = t.Populate(vcn, vSql) DataGrid1.DataSource=ds.Tables("vTable").DefaultView DataGrid1.DataBind() End Sub
Beachten Sie, dass dies eine ziemlich geschickte Art ist, Abfragen aufzurufen, die Daten zurückgeben. Sie können jede SQLAbfrage (die Abfrage kann auch eine Verknüpfung auf multiple Tabellen sein) übermitteln und einen Datensatz zurückbekommen, der dann beliebig manipuliert werden kann. Sie können auch eine Verbindung zu jeder beliebigen Datenbank aufbauen, da der Connection-String der Datenbank an die Funktion weitergegeben wird. Die drei Buttons habe ich mit Click-Events versehen, die ein insert-, ein update- und ein delete-Statement an die entsprechende RunSQL-Funktion des Formulars übermitteln. Diese ruft daraufhin die RunSQL- Funktion des Webservices auf. Hier sind die drei Funktionen:
349
ASP.NET 350
14 Sub Insert_click(Sender As Object, E As EventArgs) sql = "Insert into Masters(code_display,code_category,type)" sql = sql + "Values ('test',701,'E')" RunSQL(sql) rebind Message.Text = " .. Test-Aufzeichnungen eingefügt... " End Sub Sub Delete_click(Sender As Object, E As EventArgs) sql = "delete from masters where code_display = 'test'" RunSQL(sql) rebind Message.Text = "...alle Test-Aufzeichnungen gelöscht..." End Sub Sub Update_Click(Sender As Object, E As EventArgs) sql = "UPDATE Masters Set Opening = 90 WHERE code_display = 'test'" RunSQL(sql) rebind Message.Text = "...Alle Test Aufzeichnungen Aktualisiert: Setze closing balance = 90...! " End Sub
Die lokale RunSQL-Funktion ruft die RunSQL-Funktion des Webservices auf und übergibt ihr den SQL-String und den Connection-String. Die Webservice-Funktion führt daraufhin den Aktionsaufruf (action query) aus. Function RunSQL (vSQL as String) Dim t As NameSpaceHersh.SqlService = New NameSpaceHersh.SqlService() t.RunSQL(vcn,vSQL) End Function
Webservices sind ein wichtiger Bestandteil von ASP.NET. Die in diesem Kapitel entwickelten Methoden zeigen, wie der Prozess der Datenbankinteraktion als ein Webservice abstrahiert und verkapselt werden kann. In den folgenden Kapiteln dieses Projekts werde ich Ihnen erklären, wie sich die in diesem Kapitel entwickelten Methoden für eine Buchhaltungsanwendung umsetzen lassen.
Gestaltung eines Navigationssystems
Navigationslinks
352
Die Benutzersteuerung
353
Die Steuerung verwenden
354
ASP.NET 352
15 In Kapitel 6 Benutzer-Kontrollen gestalteten Sie ein XML-basiertes Navigationssystem für eine Website. Sie entwickelten eine Benutzersteuerung für eine Webseite, die Navigationslinks generierte. In Abbildung 15.1 können Sie sich anschauen, wie diese Navigationslinks aussehen. Die Navigationslinks wurden in einer XML-Datei gespeichert. Ich werde noch einmal kurz die Benutzersteuerung erklären, da ich sie in jedem Formular dieses Projektes verwenden werde.
Navigationslinks Die Navigationslinks dieses Projektes sind in der Datei nav.xml gespeichert. Listing 15.1: Nav.xml Home default.aspx Masters masters3.aspx Transactions selection.aspx Trial Balance Trialbalance.aspx
Jeder Link, der angezeigt werden soll, ist in dem Site-Knoten integriert. Dieser hat zwei Elemente: den Site-Namen und den Site-URL. Meine Benutzersteuerung zeigt jeden dieser URLs am oberen Ende jeder Seite an.
Gestaltung eines Navigationssystems 15
Navigationslinks Abb. 15.1
Die Benutzersteuerung Die Benutzersteuerung wird in Kapitel 6 Benutzer-Kontrollen beschrieben. Um es noch einmal kurz anzureißen: Sie können ihr die GridLines-, BorderColor- und CellPadding-Merkmale zuweisen. Sie liest eine XML-Datei und bindet eine DataList an sich. Die DataList zeigt die Links, die man auf jeder Seite vorfinden kann. Hier ist der Code: Listing 15.2: nav.ascx 'Public Variable for each exposed Property PUBLIC vGridLines As GridLines PUBLIC vBorderColor as String PUBLIC vCellPadding As Integer Sub Page_Load(Source As Object, E As EventArgs) Dim ds As New DataSet Dim fs As filestream Dim xmLStream As StreamReader
353
ASP.NET 354
15 fs = New filestream(Server.MapPath("nav.xml"), FileMode.Open, FileAccess.Read) xmlStream = new StreamReader(fs) ds.ReadXML(XmlStream) fs.Close() dlist.DataSource=ds.Tables("site").DefaultView dlist.DataBind() dlist.GridLines = vGridLines dlist.BorderColor=System.Drawing.Color.FromName(vBorderC olor) dlist.CellPadding=vCellPadding End Sub
Die Steuerung verwenden Jede Webseite muss diese Steuerung registrieren, indem sie die folgende Deklaration am Anfang jeder Seite einbindet.
Gestaltung eines Navigationssystems 15 Innerhalb der Seite wird die Steuerung wie folgt aufgerufen:
355
Integration von Webservices in die Felder eines Buchhaltungsformulars
ASP.NET 358
16 Man könnte einen persönlichen Finanzbuchhaltungs-Manager so entwickeln, dass er ein Webformular zusammen mit einem VB-Code-Behind- Formular verwendet. In diesem Kapitel werde ich jedoch zeigen, wie man den SQLService-Webservice verwendet. Die beiden Methoden des VB-Code-Behind-Formulars, die mit der Datenbank interagieren würden, müsste man so gestalten, dass sie den Webservice benutzen würden. Es sind die Methoden Rebind und RunSQL. Normalerweise würde man im Masters.vb in der ReBind()-Methode ein DataGrid und eine DropDownList an eine Datenbanktabelle binden. Hier ist der Codeauszug, den ich danach verändern will: Listing 16.1: Zu verändernde ReBind-Methode Sub ReBind() SQL = "select m.*, g.code_display as category " SQL = SQL + "from masters m, groups g " SQL = SQL + " where m.code_category = g.code_value" myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "masters") 'Ein Grid wird gebunden Grid1.DataSource=ds.Tables("masters").DefaultView Grid1.DataBind() SQL = "Select * from groups order by code_display" myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "groups") 'populate drop down list acode_category.DataSource=ds.Tables("groups").DefaultView acode_category.DataBind() hidePanel() End Sub
Um nun den Webservice zu benutzen, habe ich den Code folgendermaßen abgeändert: Listing 16.2: Die veränderte ReBind-Methode, welche den Webservice benutzt Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet ' Bind Grid SQL = "select m.*, g.code_display as category "
Integration von Webservices 16 SQL = SQL + "from masters m, groups g " SQL = SQL + " where m.code_category = g.code_value" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'populate drop down list SQL = "Select * from groups order by code_display" ds = t.Populate(ConnStr, SQL) acode_category.DataSource=ds.Tables("vTable").DefaultView acode_category.DataBind() hidePanel() End Sub
In der modifizierten ReBind-Methode rufe ich die WebserviceMethode Populate zweimal auf. Jedes Mal übergebe ich dabei einen Connection-String und einen SQL-Aufruf. Die Funktion gibt einen Datensatz zurück, der das Ergebnis enthält. Das benutze ich, um das DataGrid und die DropDownList-Schnittstelle daran zu binden. Die zweite Funktion, die daran gebunden sein muss, ist RunSQL. Diese Funktion wird dazu verwendet, eine Zeile hinzuzufügen, zu löschen oder zu aktualisieren. Die entsprechenden Eventhandler übergeben dieser Funktion eine SQL Action Query oder einen gespeicherten Prozedurnamen mit den jeweiligen Parametern. Hier ist der VB-Auszug: Listing 16.3: Die VB-Methode RunSQL Sub RunSql(sql as string) 'Catch Control Validator errors if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt") rebind exit sub end if try Dim mycommand2 As New OleDbCommand(sql,myConnection) myConnection.Open() myCommand2.ExecuteNonQuery() myConnection.Close() 'editing ausschalten
359
ASP.NET 360
16 Grid1.EditItemIndex = -1 Catch ex As OleDbException ' SQL error Dim errItem As OleDbError Dim errString As String For Each errItem In ex.Errors errString += ex.Message + "" Next Message.Text = "SQL Error.Details follow:" & errString Message.Style("color") = "red" Catch myException as Exception Response.Write("Exception: " + myException.ToString()) Message.Style("color") = "red" End try rebind response.write(sql) End Sub
Der folgende Listingsauszug enthält die modifizierte Version dieser Funktion: Listing 16.4: Modifizierte Version der RunSQL-Methode Sub RunSql(vSQL as string) 'Catch Control Validator errors if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt ") rebind exit sub end if Dim t As New NameSpaceHersh.SQLService Dim s As string s = t.RunSQL(ConnStr,vSQL) Grid1.EditItemIndex = -1 Rebind if s "Success" then Message.Text = s Message.Style("color") = "red" End if End Sub
Integration von Webservices 16 Diese Funktion ruft die RunSQL-Funktion des Webservices auf und übergibt ihr den Connection-String sowie den SQL-/Prozeduraufruf als Parameter. Wenn der Aufruf bzw. die Prozedur erfolgreich ausgeführt wird, wird der String Success von der Funktion zurückgegeben. Sonst wird der entsprechende Fehlerstring im Browser angezeigt. Hier ist nun der gesamte Code der Code-Behind-Datei Masters.vb, nachdem wir die beiden Methoden wie oben besprochen in der zweiten Fassung belassen. An dem Webformular Masters.aspx muss nichts weiter verändert werden. Listing 16.5: Masters3.vb Option Strict Off Imports System Imports System.Collections Imports System.Text Imports System.Data Imports System.Data.OleDb Imports System.Web.UI Imports System.Web.UI.WebControls Public Class BaseClass Inherits System.Web.UI.Page Protected Grid1 as DataGrid Protected Message as label Protected acode_category as dropdownlist Protected AddPanel as Panel Dim ConnStr As String Dim SQL As String Sub Page_Load(Source As Object, E As EventArgs) ConnStr = "Provider=SQLOLEDB; Data Source=(local); " ConnStr = ConnStr+" Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) rebind end if End Sub Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet ' Bind Grid SQL = "select m.*, g.code_display as category "
361
ASP.NET 362
16 SQL = SQL + "from masters m, groups g " SQL = SQL + " where m.code_category = g.code_value" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'populate drop down list SQL = "Select * from groups order by code_display" ds = t.Populate(ConnStr, SQL) acode_category.DataSource=ds.Tables("vTable").DefaultView acode_category.DataBind() hidePanel() End Sub Sub Grid1_Edit(Sender As Object, E As DataGridCommandEventArgs) Grid1.EditItemIndex = E.Item.ItemIndex ReBind() End Sub Sub Grid1_Cancel(Sender As Object, E As DataGridCommandEventArgs) Grid1.EditItemIndex = -1 ReBind() End Sub Sub hidePanel() if AddPanel.visible = true then AddPanel.visible = false end if End Sub Sub RunSql(vSQL as string) 'Catch Control Validator errors if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt") rebind exit sub end if Dim t As New NameSpaceHersh.SQLService Dim s As string s = t.RunSQL(ConnStr,vSQL) Grid1.EditItemIndex = -1 Rebind if s "Success" then Message.Text = s
Integration von Webservices 16 Message.Style("color") = "red" End if End Sub End Class
363
Einbinden eines Webservice in ein Transaktionsformular
ASP.NET 366
17 In diesem Kapitel geht es um ein Transaktionswebformular (Transactions.aspx zusammen mit dem Code Behind von Transactions.vb) für einen persönlichen Finanzbuchhaltungsmanager. In diesem Kapitel zeige ich ihnen, wie man dieses Formular für die Datenbankinteraktion mit und ohne dem Webservice SQLService benutzt. Ich werde dazu jeweils die beiden Methoden ReBind und RunSQL verändern, die beide in Transactions.vb zu finden sind. Das aspx-Formular bleibt jeweils unverändert. Die ReBind-Methode bindet ein DataGrid und ein DropDownList-Control an eine Datenbanktabelle. Hier ist die erste Version der Methode, die ich danach verändern werde: Listing 17.1: ReBind-Methode ohne SQLService-Webservice Sub ReBind() sql = " select m.code_value,m.code_display,t.*, h.* ," sql = sql + "(select code_display from masters where code_value = t.posted_to) " sql = sql + " as posted_display " sql = sql + " from tr_header h,transactions t, masters m " sql = sql + " where t.doc_no = h.doc_no " sql = sql + " and m.code_value = t.code_value" sql = sql + " and m.code_value = (select selection from tblSelection)" myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "transactions") 'Binding a Grid Grid1.DataSource=ds.Tables("transactions").DefaultView Grid1.DataBind() 'populate account selection drop down list ' which is visible in the add mode sql = "Select * from masters where code_value " sql = sql + " (select selection from tblSelection)" myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "masters")
Einbinden eines Webservice 17 aposted_display.DataSource=ds.Tables("masters").DefaultView aposted_display.DataBind() addshow.visible = true
Um den SQLService-Webservice zu benutzen, habe ich es so verändert: Listing 17.2: ReBind-Methode mit SQLService-Webservice Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet SQL = " select m.code_value,m.code_display,t.*, h.* ," sql = sql + "(select code_display from masters where " sql = sql + " code_value = t.posted_to) as posted_display " sql = sql + " from tr_header h,transactions t, masters m " sql = sql + " where t.doc_no = h.doc_no " sql = sql + " and m.code_value = t.code_value" sql = sql + " and m.code_value = (select selection from tblSelection)" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'populate account(add mode) selection drop down list 'SQL = "Select * from masters" SQL = "Select * from masters where code_value " SQL = SQL + " (select selection from tblSelection)" ds = t.Populate(ConnStr, SQL) aposted_display.DataSource=ds.Tables("vTable").DefaultView aposted_display.DataBind() addshow.visible = true End Sub
In dieser Funktion rufe ich die Webservice-Methode Populate zweimal auf. Jedes Mal übergebe ich dabei einen ConnectionString und einen SQL-Aufruf. Die Funktion gibt einen Datensatz zurück, der die Datenbankzeilen enthält. Diese benutze ich, um das DataGrid und das DropDownList-Control daran zu binden.
367
ASP.NET 368
17 Die zweite Funktion, die wir verändern müssen, ist RunSQL. Diese Funktion wird dazu verwendet, eine Zeile hinzuzufügen, zu löschen oder zu aktualisieren. Die entsprechenden Eventhandler übergeben dieser Funktion eine SQL Action Query oder einen gespeicherten Prozedurnamen mit den jeweiligen Parametern. Hier ist der VB-Auszug: Listing 17.3: RunSQL-Funktion ohne SQLService-Webservice Sub RunSql(vsql as string) 'Catch Control Validator errors if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt") rebind exit sub end if try Dim mycommand2 As New OleDbCommand(vsql,myConnection) myConnection.Open() myCommand2.ExecuteNonQuery() myConnection.Close() 'editing ausschalten Grid1.EditItemIndex = -1 Catch ex As OleDbException ' SQL error Dim errItem As OleDbError Dim errString As String For Each errItem In ex.Errors errString += ex.Message + "" Next Message.Style("color") = "red" Response.write("DataBase Error :" + errString) Catch myException as Exception Response.Write("Exception: " + myException.ToString()) Message.Style("color") = "red" Finally message.text = vsql end try End Sub Sub hidePanel() if AddPanel.visible = true then
Einbinden eines Webservice 17 AddPanel.visible = false 'reset values adate.text = "" aref.text = "" adr_amount.text = "" acr_amount.text = "" anarr.text = "" end if End Sub
Hier ist die modifizierte Version dieser Funktion: Listing 17.4: RunSQL-Funktion mit SQLService-Webservice Sub RunSql(vsql as string) if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt ") rebind exit sub end if Dim t As New NameSpaceHersh.SQLService Dim s As string s = t.RunSQL(ConnStr,vSQL) Grid1.EditItemIndex = -1 Rebind if s "Success" then Message.Text = s Message.Style("color") = "red" End if End Sub
Diese Funktion ruft die RunSQL-Funktion des Webservices auf und übergibt ihr den Connection-String sowie die SQL-Zeichenfolge als Parameter. Wenn der Aufruf bzw. die Prozedur erfolgreich ausgeführt wird, wird der String Success von der Funktion zurückgegeben. Sonst wird der entsprechende Fehlerstring im Browser angezeigt. Hier ist nun das Listing des Code-Behind-Formulars Transactions.vb
369
ASP.NET 370
17 Listing 17.5: Transactions.vb Option Strict Off Imports System Imports System.Collections Imports System.Text Imports System.Data Imports System.Data.OleDb Imports System.Web.UI Imports System.Web.UI.WebControls Public Class BaseClass Inherits System.Web.UI.Page Protected Grid1 as DataGrid Protected Message as label, title as label Protected aposted_display as dropdownlist, selection as dropdownlist Protected AddPanel as Panel Protected adate as TextBox, aref as TextBox, adr_amount as TextBox Protected acr_amount as TextBox , anarr as TextBox Protected addshow as button Dim ds As New DataSet Dim ConnStr As String Dim SQL As String Sub Page_Load(Source As Object, E As EventArgs) ConnStr = "Provider=SQLOLEDB; Data Source=(local); " ConnStr = ConnStr+" Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) Dim code As string, display As string code = Request.Form("Selection") title.text = code if code = "" then response.redirect("selection.aspx") end if UpdateSelection(code) rebind end if End Sub Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet SQL = " select m.code_value,m.code_display,t.*, h.* ,"
Einbinden eines Webservice 17 sql = sql + "(select code_display from masters where " sql = sql + " code_value = t.posted_to) as posted_display" sql = sql + " from tr_header h,transactions t, masters m " sql = sql + " where t.doc_no = h.doc_no " sql = sql + " and m.code_value = t.code_value" sql = sql + " and m.code_value = (select selection from tblSelection)" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'populate account(add mode) selection drop down list sql = "Select * from masters where code_value " sql = sql + " (select selection from tblSelection)" ds = t.Populate(ConnStr, SQL) aposted_display.DataSource=ds.Tables("vTable").DefaultView aposted_display.DataBind() addshow.visible = true End Sub Sub Grid1_Edit(Sender As Object, E As DataGridCommandEventArgs) Grid1.EditItemIndex = E.Item.ItemIndex ReBind() End Sub Sub Grid1_Cancel(Sender As Object, E As DataGridCommandEventArgs) Grid1.EditItemIndex = -1 ReBind() End Sub Sub RunSql(vsql as string) if not page.isvalid then response.write("Gespeicherte Prozedur wurde nicht ausgeführt ") rebind exit sub end if Dim t As New NameSpaceHersh.SQLService Dim s As string s = t.RunSQL(ConnStr,vSQL) Grid1.EditItemIndex = -1 Rebind if s "Success" then
371
ASP.NET 372
17 Message.Text = s Message.Style("color") = "red" End if End Sub Sub hidePanel() if AddPanel.visible = true then AddPanel.visible = false 'reset values adate.text = "" aref.text = "" adr_amount.text = "" acr_amount.text = "" anarr.text = "" end if End Sub Sub UpdateSelection(vselection) sql = "delete from tblSelection " sql = sql + " insert into tblSelection(selection)" sql = sql + " values('" + vselection + "')" runSql(sql) End Sub End Class
Integration des Webservice in einen Saldenbilanzbericht
Projekt 1 – Zusammenfassung
378
ASP.NET 374
18 In diesem Kapitel werde ich Ihnen das SaldenbilanzberichtWebformular TrialBalance.aspx vorstellen. Auch hier werden wir es uns einmal ohne und einmal mit dem SQLService-Service anschauen. Wir müssen dazu die ReBind-Methode modifizieren, die zwei DataGrid Controls an zwei DataView Controls bindet. Hier ist der Code der Funktion ohne SQLService: Listing 18.1: ReBind-Funktion ohne SQLService-Benutzung Sub ReBind() sql = "SELECT code_display, closing, " sql = sql + " dr_amount = CASE type WHEN 'A' THEN " sql = sql + " closing WHEN 'E' THEN closing ELSE 0 END, " sql = sql + " cr_amount = CASE type WHEN 'I' " sql = sql + " THEN closing WHEN 'L' THEN closing ELSE 0 END " sql = sql + " From Masters" myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "Masters") 'Binding a Grid Grid1.DataSource=ds.Tables("Masters").DefaultView Grid1.DataBind() 'totals sql = "SELECT 'Total' as nothing ," sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('A','E')) as dr_total , " sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('I','L')) as cr_total " myCommand = New OleDbDataAdapter(SQL, myConnection) myCommand.Fill(ds, "totals") 'Binding a Grid Grid2.DataSource=ds.Tables("totals").DefaultView Grid2.DataBind() End Sub
Um den SQLService-Service zu benutzen, müssen Sie diese Funktion wie folgt abändern:
Integration des Webservice 18 Listing 18.2: ReBind-Funktion mit SQLService-Benutzung Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet sql = "SELECT code_display, closing, " sql = sql + " dr_amount = CASE type WHEN 'A' THEN " sql = sql + " closing WHEN 'E' THEN closing ELSE 0 END, " sql = sql + " cr_amount = CASE type WHEN 'I' " sql = sql + " THEN closing WHEN 'L' THEN closing ELSE 0 END " sql = sql + " From Masters" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'totals sql = "SELECT 'Total' as nothing ," sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('A','E')) as dr_total , " sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('I','L')) as cr_total " ds = t.Populate(ConnStr, sql) Grid2.DataSource=ds.Tables("vTable").DefaultView Grid2.DataBind() End Sub
Die Webservice-Methode Populate wird zweimal aufgerufen. Jedes Mal wird ihr der Connection-String und der SQL-Aufruf übergeben. Ein Datensatz, der die Datenbankzeilen beinhaltet und zur Bindung der zwei DataGrid Schnittstellen verwendet wird, wird daraufhin zurückgegeben. Hier ist das vollständige Listing der TrialBalance.aspx mit Benutzung des SQLService-Services: Listing 18.3: TrialBalance.aspx mit SQLService-Benutzung
375
ASP.NET 376
18 Dim ConnStr As String Dim SQL As String Sub Page_Load(Source As Object, E As EventArgs) ConnStr = "Provider=SQLOLEDB; Data Source=(local); " ConnStr = ConnStr+" Initial Catalog=ASPNET;User ID=sa;" if NOT (isPostBack) rebind end if End Sub Sub ReBind() Dim t As New NameSpaceHersh.SQLService Dim ds As DataSet sql = "SELECT code_display, closing, " sql = sql + " dr_amount = CASE type WHEN 'A' THEN " sql = sql + " closing WHEN 'E' THEN closing ELSE 0 END, " sql = sql + " cr_amount = CASE type WHEN 'I' " sql = sql + " THEN closing WHEN 'L' THEN closing ELSE 0 END " sql = sql + " From Masters" ds = t.Populate(ConnStr, SQL) Grid1.DataSource=ds.Tables("vTable").DefaultView Grid1.DataBind() 'totals sql = "SELECT 'Total' as nothing ," sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('A','E')) as dr_total , " sql = sql + " (Select sum(closing) From masters " sql = sql + " where type in('I','L')) as cr_total " ds = t.Populate(ConnStr, sql) Grid2.DataSource=ds.Tables("vTable").DefaultView Grid2.DataBind() End Sub a { color:black; text-decoration:none;} a:hover { color:red; text-decoration:underline;}
Integration des Webservice 18 Trial Balance
377
ASP.NET 378
18
Projekt 1 – Zusammenfassung Finanzbuchhaltungsprogramme über Browser auszuführen hat viele Vorteile. Sie können dadurch Information über relevante Daten von jedem beliebigen Ort aus abrufen. Es ist dadurch nicht nötig, Netzwerkinfrastrukturen aufzubauen, nur um verschiedene Buchhaltungsmodule miteinander kommunizieren zu lassen. Der Nachteil einer browsergesteuerten Anwendung ist, dass man nicht den gewohnten Bedienkomfort einer aufwändigen Benutzerschnittstelle genießen kann, den
Integration des Webservice 18 man von normalen Desktop-Anwendungen her gewöhnt ist. Wenn Sie jedoch den Datenbankzugriff und die Manipulationsroutinen in einen Webservice integrieren, können Sie mit Sprachen wie Visual Basic.NET oder C# ein schönes Graphical User Interface aufbauen. Den Webservice benutzen Sie dann dazu, um mit der Datenbank über das Internet zu kommunizieren. In diesem Projekt habe ich Ihnen gezeigt, wie das aussehen kann. Wir haben einen persönlichen Finanzbuchhaltungsmanager entwickelt, der über einen Webservice auf eine Datenbank zugreifen kann. Da dieses Buch von ASP.NET handelt, haben wir diese Sprache auch als Entwicklungssprache verwendet. Sie hätten genauso gut auch Visual Basic.NET oder C# benutzen können, um die Benutzerschnittstelle zu entwickeln. Diese kann dann über den Webservice auf die Datenbank zugreifen.
379
Projekt 2: Visual Studio.NET
ASP.NET 382
Projekt 2 – Überblick Visual Studio beinhaltet eine Vielzahl an Entwicklungstools, um Web- und Windows-Anwendungen komfortabel in möglichst kurzer Zeit zu entwickeln. Es ist eine integrierte Entwicklungsumgebung, die es Ihnen ermöglicht, Anwendungen mit unterschiedlichen Programmiersprachen zu entwickeln. Sie können dazu Visual Basic, C#, ASP.NET usw. verwenden. Unabhängig davon, welche dieser Sprachen Sie bevorzugen, brauchen Sie nur eine Entwicklungsumgebung zu erlernen. Visual Studio erneuert und erweitert die Funktionalität von Visual InterDev und ermöglicht ein schnelles Zusammenbauen von Programmen mit Hilfe von Drag & Drop. Die IDE bietet auch hervorragende Debugging-Möglichkeiten. Das funktioniert bei den Sprachen, den Prozessen und sogar bei den gespeicherten Prozeduren. In diesem Teil, der insgesamt drei Kapitel umfasst, werden wir die wichtigsten Features des Visual Studio kennen lernen. In Kapitel 19 Datenbankinteraktion mit Visual Studio.NET werde ich Ihnen zunächst einen Überblick über die verschiedenen Assistenten, Tools und Komponenten von Visual Studio.NET geben. Dann werden Sie ein Datenbank-Webformular aufbauen, indem Sie die Drag & Drop-Features von Visual Studio intensiv nutzen. In Kapitel 20 CRUD-Applikationen mit Visual Studio.NET werden Sie CRUD (create-read-update-delete) in dieses Webformular implementieren. Am Ende des zweiten Projektes werden Sie mit Visual Studio.NET Webservices in Windeseile entwickeln können.
Datenbankinteraktion mit Visual Studio.NET
Erstellung der C#-Webanwendung
384
Der Anwendungsordner
386
Die erzeugten Dateien
386
Die Projekt-Eigenschaften (Project Properties)
388
Datenbankinteraktion
389
Erstellen einer Verbindung (Connection) und eines DataAdapters
390
Der generierte Code von SqlConnection und SqlDataAdapter
396
Das DataSet
400
ASP.NET 384
19 In diesem Kapitel werde ich Ihnen zeigen, wie man ein DataGrid an ein Strongly Typed DataSet« bindet. Und im weiteren Verlauf werde ich Ihnen die verschiedenen Tools, Assistenten und Komponenten von Visual Studio.NET für die Datenbankinteraktion vorstellen. Ein Strongly Typed DataSet ist ein von Visual Studio.Net erzeugtes DataSet. Der Entwickler schreibt keinen Code für dieses DataSet, sondern zieht einfach ein DataSet-Objekt aus der Visual Studio.NET-ToolBox. Ein so erzeugtes DataSet ist enger an das .NET Framework gebunden als ein von Hand geschriebenes DataSet. Das Typed DataSet profitiert von der Syntaxvervollständigung des Visual Studio.NET, welches zur produktiveren Entwicklung führen kann. Ein Typed DataSet ist eine Unterklasse der DataSet-Klasse und besitzt eine Schemadatei (eine .XSDDatei), welche die Struktur der Tabellen in dem DataSet beschreibt. Dieses Schema enthält die Tabelle mit den Spaltennamen, die Datentypen und die Informationen über die Beschränkungen (constraints) der Daten. Ein Untyped DataSet hat kein entsprechendes Schema. Visual Studio.NET erzeugt dieses Datenbankschema vollautomatisch. Anschließend werde ich Sie durch eine in C# geschriebene Webanwendung leiten, welche die Daten der authors-Tabelle der PUBS-Datenbank in einem DataGrid anzeigt.
Erstellung der C#-Webanwendung Visual Studio.NET organisiert die Entwicklung von Anwendungen nach dem Projektmappen- (Solutions) und Projekte-Konzept. Eine Projektmappe kann eine oder mehrere Projekte beinhalten und ein Projekt ist wiederrum ein Verzeichnis, das alle Objekte einer Anwendung zusammenhält. In diesem Schritt werde ich ein C#-ASP.NET-Webprojekt erstellen. Dies sind die dazu nötigen Schritte: Erstellen Sie eine Webanwendung durch klicken auf die Schaltfläche Neues Projekt auf der Startseite oder über das Menü Datei/Neu/Projekt. Wählen Sie, wie in Abbildung 19.1 gezeigt, Visual C#Projekte auf der linken und ASP.NET-Webanwendung auf rechten Seite. Sie können das Projekt VSÜberblick nennen.
Datenbankinteraktion mit Visual Studio.NET 19
385
Erstellung einer ASP.NETWebanwendung Abb. 19.1
VS erstellt einen virtuellen Ordner im IIS. Abb. 19.2
ASP.NET 386
19
Der Anwendungsordner VS erstellt einen Anwendungsordner mit dem Namen VSÜberblick im Verzeichnis wwwroot. Es wird auch einen virtuellen Ordner in IIS erstellen. Sie können sich das anschauen, indem Sie mit der rechten Maustaste auf Arbeitsplatz klicken und dann mit der linken Verwalten auswählen. Unter Dienste und Anwendungen/Internet-Informationsdienste/Websites/Standardwebsite werden Sie dann ein neues VSÜberblick-Verzeichnis entdecken können.
Die erzeugten Dateien Schauen Sie sich bitte jetzt die ASP.NET-Webanwendung an, die von VS (Visual Studio) erstellt wurde. Ihr Bildschirm sollte wie in Abbildung 19.3 aussehen.
Das von VS erzeugte leere Projekt Abb. 19.3
Auf der rechten oberen Seite des Bildschirms sehen Sie den Projektmappen-Explorer (Solution Explorer). Sie werden feststellen, dass VS eine Global.asax-Datei, eine Web.config-Datei und ein Standard- Webformular mit dem Namen WebForm1.aspx erstellt hat. Die Global.asax-Datei ist für die Logik der Anwendung durch Anwendungs-Events wie zum Bei-
Datenbankinteraktion mit Visual Studio.NET 19 spiel Application_Start, Application_End, Session_Start und Session_End zuständig. In Kapitel 10 ASP.NET-Anwendungen können Sie auch noch Näheres darüber in Erfahrung bringen. Die Web.config-Datei speichert die Konfigurationsdaten der Anwendung. Sie befindet sich im Root-Verzeichnis des Anwendungsverzeichnisses und ist auch aus allen Unterverzeichnissen heraus zugreifbar. In ihr werden Fehler-, Sicherheits-, Kompilations-, Debugging-, Session- und Globalinformationen gespeichert. Auch dazu finden Sie in Kapitel 10 ASP.NET-Anwendungen Genaueres. Das Webformular WebForm1.aspx wird als Vorlage zur Verfügung gestellt. Sie können daraus ein neues Webformular erstellen. Schauen Sie sich bitte die beiden Schaltflächen Entwurf (Design) und HTML unter dem Arbeitsbereich an. Beim Start von VS.NET befinden Sie sich automatisch im Modus Entwurf (Design). Der Modus Entwurf (Design) erlaubt Ihnen durch einfaches Drag & Drop, die Komponenten auf das Formular zu ziehen. Dort können Sie sie auch mit der Maus nach Belieben visuell anordnen. Webseiten, die durch VS erstellt werden, benutzen Code-Behind-Dateien. Wenn Sie ins VSÜberblick-Verzeichnis in Ihrem wwwroot-Ordner hineinschauen, können Sie die Code-BehindDatei WebForm1.aspx.cs sehen. Um sich die Datei in VS anzuschauen, haben sie dazu eine der folgenden Möglichkeiten: Wählen Sie aus dem Projekt-Menü Alle Dateien anzeigen (Show All Files). Dadurch taucht ein Plus-Zeichen vor WebForm1.aspx im Projektmappen-Explorer (Solution) auf. Wenn Sie auf das Pluszeichen klicken, werden Sie die Code-Behind-Datei sehen können. Im Projektmappen-Explorer (Solution) gibt es einen Button, der Alle Dateien anzeigen (Show All Files) als Hinweistext anzeigt, sobald Sie mit dem Mauszeiger darüberfahren. Klicken Sie ihn an. Rechtsklicken Sie auf WebForm1.aspx und wählen Sie Zeige Code (View Code). Beachten Sie, dass im Code Behind bereits einige Namensräume (namespaces) importiert sind. In der Entwicklungsphase werden Sie vielleicht viele verschiedene Webformulare erstellen. Wenn Sie sich eines davon im
387
ASP.NET 388
19 Browser anschauen wollen, klicken Sie mit der rechten Maustaste auf den Namen des Formulars und wählen Sie In Browser anzeigen (View in Browser). Sie können auch ein Webformular als Startformular auswählen. Wenn Sie Ihre Anwendung ausführen, wird im Browser dieses Formular als erstes angezeigt. Klicken Sie dazu mit der rechten Maustaste auf das Webformular und wählen Sie anschließend Als Startseite festlegen (Set as Start Page) aus.
Die Projekt-Eigenschaften (Project Properties) Rechtsklicken Sie bitte auf den Projektnamen im Projektmappen-Explorer und wählen Sie Eigenschaften (Properties). Das Eigenschaften-Fenster öffnet sich, wie in Abbildung 19.4 gezeigt.
Die ProjektEigenschaftenseiten Abb. 19.4
Sie können den Namensraum (namespace) Ihres Projektes unter Standardnamespace eintragen. Die Vorgabe ist Ihr Projektname. Sollten Sie hier den Namespace ändern, wird dies nicht automatisch in den schon erstellten Formularen übernommen. Sie müssten dann die Namespaces der einzelnen Formulare von Hand ändern, sonst gibt es Kompilierfehler. Jedes neu
Datenbankinteraktion mit Visual Studio.NET 19 erstellte Webformular wird jedoch in dem hier vorgegebenen Namensraum erzeugt. Jetzt wollen wir der WebForm1.aspx-Datei einen bedeutungsvolleren Namen geben. Rechtsklicken Sie bitte diese Datei im Projektmappen- Explorer und wählen Sie Umbenennen (Rename). Nennen Sie sie bitte TypedDataSet.aspx. Wenn Sie sich jetzt den Code Behind genauer anschauen, werden Sie feststellen, dass der Klassenname und der Konstruktorname immer noch WebForm1 heißen. Falls Sie hier die Namen nicht zu TypedDataSet umändern, werden Sie später Erstellungsfehler bekommen, wenn Sie dem Formular neue Komponenten hinzufügen. Das ist natürlich leicht zu beheben, indem Sie einfach den Klassen- und Konstrukturnamen von WebForm1 in TypedDataSet umbenennen. Sie können das entweder über Finden und Ersetzen bewerkstelligen oder Sie löschen einfach die Datei und erstellen Sie erneut mit dem neuen Namen. Ein Konstruktur ist eine Methode, die den gleichen Namen hat wie die Klasse. Das ist die erste Methode, die ausgeführt wird, sobald die Klasse instanziiert wird. (Ein Webformular ist eine Klasse.) Ein leerer Konstruktor, der keine Parameter besitzt, wird von Haus aus mit einer Klasse kreiert. Natürlich können Sie zusätzliche Konstruktoren hinzufügen, die Parameter akzeptieren.
Datenbankinteraktion In diesem Abschnitt werde ich Ihnen zeigen, wie man auf eine Datenbank zugreift, einen DataAdapter bevölkert (populate) und ihn dazu benutzt, einen Datensatz (DataSet) zu füllen. Dazu werde ich die authors-Tabelle der PUBS-Datenbank zu Demonstrationszwecken benutzen. Ich werde Ihnen zusätzlich noch zwei alternative Methoden zur Datenbankinteraktion zeigen. Alle Komponenten, die mit einer Datenbank interagieren, findet man in der Daten-Sektion der Toolbox. Um eine dieser Komponenten zu benutzen, müssen Sie sie nur anklicken und auf das Webformular ziehen. Abbildung 19.5 zeigt Ihnen die Komponenten, die für die Datenbankinteraktion zur Verfügung stehen.
389
ASP.NET 390
19
Die Data-Sektion der Toolbox Abb. 19.5
Erstellen einer Verbindung (Connection) und eines DataAdapters Ich werde den SQL Managed Provider verwenden, um eine Verbindung mit der Datenbank zu erstellen. Wie Sie sich vielleicht erinnern, kann für eine Datenbankinteraktion eine SQLConnection verwendet werden. Ein SQL-Select-Befehl nutzt diese Verbindung, um den SqlDataAdapter mit Datenbankdaten zu füllen. Wie versprochen werde ich Ihnen zwei unterschiedliche Methoden zeigen, mit denen Sie das erreichen können. Erstellen einer SqlConnection und eines SqlDataAdapters – Methode 1
Um eine SQLConnection und einen SqlDataAdapter zu erstellen, ziehen Sie einen SqlDataAdapter aus der Daten-Sektion der ToolBox auf das Webformular. Anschließend steht Ihnen ein Assistent zur Seite. Und so wird es gemacht: 1
Ziehen Sie einen SqlDataAdapter aus der Daten-Sektion der ToolBox auf das Webformular. Ein Datenadapter-Konfigurations-Assistent (Data Adapter Configuration Wizard) erscheint und hilft Ihnen, eine Datenbankverbindung herzustellen und die entspre-
Datenbankinteraktion mit Visual Studio.NET 19
391
chenden Kommandos zu erzeugen. Klicken Sie auf Weiter (Next) und das Fenster Wählen sie Ihre Datenverbindung (Choose your DataConnection) erscheint. Klicken sie auf Neue Verbindung (New Connection) und Sie sehen die Datenverknüpfungseigenschaftenseite (Data Link Properties). 2
Dieses Fenster sollte wie in Abbildung 19.6 gezeigt ausgefüllt werden. Hier sind einige Details: Bestimmen Sie den Servernamen, den Benutzernamen und das Kennwort. Wenn Sie die pubs-Datenbank im Ausgangszustand belassen, ist der Benutzername sa und das Kennwort leer. Selektieren Sie das Kontrollkästchen Speichern des Kennworts zulassen (Allow saving of password). Schließlich wählen Sie noch die pubs-Datenbank unter Wählen Sie die Datenbank auf dem Server aus (Select database on server) und klicken auf die Schaltfläche Verbindung testen (Test Connection), um die Verbindung zu testen.
Das Datenverknüpfungseigenschaften-Fenster Abb. 19.6
3
Im folgenden Schritt präsentiert Ihnen der Assistent drei Abfragetypoptionen: SQL Anweisungen verwenden (Use SQL statements), Neue gespeicherte Prozedu-
ASP.NET 392
19 ren erstellen (Create new stored procedures) und Vorhandene gespeicherte Prozeduren verwenden (Use existing stored procedures). Das ist in Abbildung 19.7 zu sehen. Wie ich in Kürze beschreiben werde, kann ein insert-, update-, delete- und select-Befehl mit dem DataAdapter assoziiert werden. Die Option SQL-Anweisungen verwenden (Use SQL statements) erstellt vier SQL-Befehle für die Zeilen der Datenbank, und zwar jeweils eine für select, insert, update und delete. Die Option Neue gespeicherte Prozeduren erstellen (Create new stored procedures) erstellt vier neue gespeicherte Prozeduren und die Option Vorhandene gespeicherte Prozeduren (Use existing stored procedures) ermöglicht Ihnen die Namen von vier bereits erstellten gespeicherten Prozeduren anzugeben. Für unsere Demonstration wählen Sie bitte die Option SQL-Anweisungen verwenden (Use SQL statements).
Das Fenster Abfragetyp auswählen (Choose a query) Abb. 19.7
Ein neues Fenster mit dem Namen SQL-Anweisungen generieren (Generate the SQL Statement) erscheint. Dieses Fenster erlaubt Ihnen einen Select-Befehl zu spezifizieren. Schreiben Sie Select * from authors, wie in Abbildung 19.8 gezeigt.
Datenbankinteraktion mit Visual Studio.NET 19
393
Ein SQL Befehl im Fenster Erzeugen Sie einen SQLBefehl (Generate the SQL Statement) Abb. 19.8
Sie können in diesem Fenster einen SQL-Befehl auch graphisch erzeugen. Dazu klicken Sie bitte auf die Schaltfläche AbfrageGenerator (Query Builder). Dadurch wird ein Abfrage-Generator-Tool (Query Builder) zum Vorschein gebracht. Sehen Sie sich bitte dazu die Abbildung 19.9 an. Dieses Tool ist ähnlich aufgebaut wie Microsoft Access. Hier können Sie mehrere Tabellen selektieren und verknüpfen, um anschließend durch Drag & Drop der Spaltennamen die Befehle zu generieren. Die weiteren Einzelheiten zu erkunden überlasse ich aber Ihnen. Nachdem Sie mit Ihrem SQL-Befehl zufrieden sind, drücken Sie bitte die Schaltfläche Weiter und anschließend die Schaltfläche Finish. Ein SqlDataAdapter und eine SqlConnection werden daraufhin im unteren Teil Ihres Webformulars erscheinen (siehe Abbildung 19.10). Diese werden SqlDataAdapter1 und SqlConnection1 heißen. Das ist das Ergebnis, das wir durch die erste Methode erreichen wollten. Wir haben mit VS einen SqlDataAdapter und eine SqlConnection kreiert. Jetzt widmen wir uns Methode 2.
ASP.NET 394
19
Der Abfrage-Generator erlaubt Ihnen die Abfragen graphisch zu erstellen. Abb. 19.9
Der SqlDataAdapter1 und die SqlConnection1 wurden in VS erzeugt. Abb. 19.10
Erstellen einer SqlConnection und eines SqlDataAdapters – Methode 2
Jetzt werde ich Ihnen eine andere und schnellere Methode zeigen, wie man eine SqlConnection und einen SqlDataAdapter erstellt. Sie sollten dafür am besten von vorne beginnen. Also erstellen Sie bitte zunächst ein neues Webformular mit dem
Datenbankinteraktion mit Visual Studio.NET 19
395
Namen TypedDataSet2.aspx. Da Sie dieses Formular im Browser anschauen wollen, setzen Sie es am besten als Startformular fest. Dazu klicken Sie bitte im Solution Explorer mit der rechten Maustaste auf das Formular und wählen Als Startseite festlegen (Set as Start Page) aus. Der Server-Explorer
Der Server-Explorer ist ein Datenbank-Explorer, der die verschiedenen Datenbankobjekte wie Tabellen, Trigger und gespeicherte Prozeduren anzeigt. Sie können ihn durch Ansicht/Server-Explorer (View/Server Explorer) im Menü oder das Tastaturkürzel S+A+s erreichen. Der Server-Explorer ist in Abbildung 19.11 gezeigt. Sie können ihn dazu verwenden, Ihre Tabellen zu manipulieren. Die weiteren Details überlasse ich Ihrem persönlichen Forschungsdrang.
Der Server-Explorer erlaubt Ihnen Datenbankobjekte anzuschauen und ihre Tabellen zu manipulieren Abb. 19.11
Alles, was Sie jetzt tun müssen, um eine SqlConnection und einen SqlDataAdapter zu erschaffen, ist die authors-Tabelle vom Server-Explorer auf das Formular zu ziehen. (Beziehen Sie sich auf die Abbildung 19.11, um diese Tabelle im Server-Explorer zu finden.) Das resultierende Formular sollte genauso aussehen wie in Abbildung 19.10. Es hat auch jeweils eine SqlConnection und einen SqlDataAdapter mit den Namen SqlConnection1 und SqlDataAdapter1.
ASP.NET 396
19
Der generierte Code von SqlConnection und SqlDataAdapter Wenn Sie auf SqlConnection1 rechtsklicken und Eigenschaften (Properties) auswählen, öffnet sich die Eigenschaftenseite, wie in Abbildung 19.12 gezeigt. Beachten Sie, dass Sie Name und ConnectionString ändern können. Außerdem ermöglicht Ihnen dieses Tool auch, die Eigenschaftseinstellungen durch andere Eigenschaftsseiten wie zum Beispiel Visual Basic zu verändern.
Die Eigenschaftsseite von SqlConnection1 Abb. 19.12
Die Eigenschaftsseite von SqlDataAdapter1 sieht entsprechend aus, wie Sie in Abbildung 19.13 sehen können. Schauen wir uns jetzt den erzeugten Code genauer an. Rufen Sie die Code-Behind-Datei in VS auf und erweitern Sie alle Knoten, indem Sie auf die Pluszeichen klicken. Dadurch wird jedes Plus zum Minus und Sie können den Code der entsprechenden Methode sehen. Beachten Sie bitte die Markierungen #region und #endregion. Code, der in diesen Tags eingeschlossen ist, kann aus- und eingeklappt werden. Natürlich können Sie auch in das Anwendungsverzeichnis wechseln und die Datei TypedDataSt.aspx.cs in einem beliebigen Texteditor betrachten.
Datenbankinteraktion mit Visual Studio.NET 19
397
Die Eigenschaftsseite von SqlDataAdapter Abb. 19.13
Mehrere Namensräume sind in der Code-Behind Datei-folgendermaßen importiert: using using using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.SessionState; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls;
Eine Klasse mit dem Namen TypedDataSet, die von System.Web.UI.Page erbt, wird im VSÜberblick-Namespace folgendermaßen erzeugt: namespace VSÜberblick { public class TypedDataSet2 : System.Web.UI.Page { //Hier steht jede Menge Code } }
ASP.NET 398
19 Vier Command-Objekte werden deklariert: protected System.Data.SqlClient.SqlCommand sqlSelectCommand1; protected System.Data.SqlClient.SqlCommand sqlInsertCommand1; protected System.Data.SqlClient.SqlCommand sqlUpdateCommand1; protected System.Data.SqlClient.SqlCommand sqlDeleteCommand1; Eine SqlConnection wird deklariert: protected System.Data.SqlClient.SqlConnection sqlConnection1; Ein SqlDataAdapter wird deklariert: protected System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1; Eine Instanz all dieser Objekte wird durch das Schlüsselwort new in der InitializeComponent-Methode fogendermaßen erzeugt: this.sqlSelectCommand1 = new System.Data.SqlClient.SqlCommand(); this.sqlInsertCommand1 = new System.Data.SqlClient.SqlCommand(); this.sqlUpdateCommand1 = new System.Data.SqlClient.SqlCommand(); this.sqlDeleteCommand1 = new System.Data.SqlClient.SqlCommand(); this.sqlConnection1 = new System.Data.SqlClient.SqlConnection(); this.sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter(); In derselben Methode wird SqlConnection wie folgt festgelegt: // sqlConnection1 this.sqlConnection1.ConnectionString = "data source=BHASIN\\NETSDK;initial catalog=pubs;integrated security=SSPI;persist security info=True;workstation id=BHASIN;packet size=4096";
Datenbankinteraktion mit Visual Studio.NET 19 Der DataAdapter wird mit einem Command-Objekt select, insert, update und delete folgendermaßen erzeugt: this.sqlDataAdapter1.DeleteCommand this.sqlDeleteCommand1; this.sqlDataAdapter1.InsertCommand this.sqlInsertCommand1; this.sqlDataAdapter1.SelectCommand this.sqlSelectCommand1; this.sqlDataAdapter1.UpdateCommand this.sqlUpdateCommand1;
= = = =
Nun werden für jedes Command-Objekt die folgenden Eigenschaften gesetzt: Die CommandText property Die Connection property Die Parameter Collection Obwohl es hier eine Menge Code gibt, ist er doch recht einfach zu verstehen. Zum größten Teil geht es hier um das Setzen der Parameter-Collection. Jedes Feld der Datenbanktabelle wird als Parameter der Parameter-Collection des Command-Objektes hinzugefügt. Dann wird entweder ein insert-, update- oder delete-Befehl erstellt, der all diese Felder beinhaltet. Diese Technik habe ich Ihnen in Kapitel 3 Verwendung von ADO.NET im .NET-Framework im Zusammenhang mit dem Aufruf von gespeicherten Prozeduren mit einem Command-Objekt genauer erklärt. Vielleicht rufen Sie sich dieses Kapitel noch einmal in Ihr Gedächtnis. Es ist jetzt angebracht, über diese vier Commands zu sprechen und auch den Datensatz ins Bild zu rücken. Wenn Sie in ADO 2.x select, insert, update oder delete in einer einzigen Methode unterbringen wollten, mussten Sie vier ADODB-Command-Objekte erzeugen. In ADO.NET gibt es zwar auch vier Commands, jedoch sind alle in einem DataAdapter- Objekt verlinkt, der alle vier Commands angemessen behandelt. Ich wollte das DataSet eigentlich im nächsten Abschnitt vorstellen, allerdings empfinde ich es im Augenblick angebracht, darüber zu sprechen. Wie Sie sich vielleicht erinnern, sitzt der DataAdapter zwischen dem DataSet und der Datenbank. Das DataSet kann auch an ein List-Control wie das DataGrid gebunden sein. Der Benutzer interagiert mit dem DataGrid und kann
399
ASP.NET 400
19 dadurch Datenbankdaten verändern. Da das DataSet an das DataGrid gebunden ist, werden alle Veränderungen am DataGrid auch am DataSet ausgeführt. Sie könnten auch eine Speichern-Schaltfläche auf dem DataGrid anbringen, damit ein Benutzer die Änderungen durch einen Klick darauf in der Datenbank speichern kann. Diese Änderungen könnten inserts, updates oder deletes auf Datenbankzeilen sein. Diese Schaltfläche würde die update()-Methode des DataAdapters aufrufen. Die update() Methode sucht im DataSet nach allen inserts, updates und deletes und ruft den entsprechenden insert-, updateoder delete-Befehl auf. Lassen Sie sich nicht durch den Methodennamen update() verirren, der DataAdapter führt gleichermaßen auch insert- und delete-Aktivitäten aus. In den TableMapping-Eigenschaften können Sie auch freundliche Namen (friendly names) angeben, um sich auf die Datenbank Spalten zu beziehen. Hier sind die Namen und die freundlichen Namen allerdings die gleichen. Zum Beispiel ist Folgendes das TableMapping für au_id. new System.Data.Common.DataColumnMapping("au_id", "au_id").
Diese Eigenschaften (properties) verlinken die Datenbankspalten des Datensatzes mit der Datenbank. Sollten Sie also sehr lange Namen in den Datenbankspalten haben, könnten Sie so mit einem kurzen Alias in dem DataTable darauf verweisen.
Das DataSet Im nächsten Schritt werde ich ein Strongly Typed DataSet erstellen, indem ich die Drag & Drop-Fähigkeiten von Visual Studio.NET ausnutze. Ich werde auch ein wenig Code zur Bevölkerung (populate) des DataAdapters und des DataSet hinzufügen und dann ein DataGrid an den Datensatz binden. Hier sind die einzelnen notwendigen Schritte: 1
Wählen Sie die Menüoption DataSet generieren (Generate Dataset) aus dem Menü Daten (Data).
2
Die Dialogbox DataSet generieren (Generate Dataset) erscheint, wie in Abbildung 19.14 zu sehen ist. Rufen Sie das DataSet dsAuthors auf und vergewissern Sie sich, dass das Kästchen mit der Beschriftung DataSet
Datenbankinteraktion mit Visual Studio.NET 19
401
zum Designer hinzufügen (Add this DatSet to the designer) angehakt ist.
Die Dialogbox DataSet generieren (Generate Dataset) Abb. 19.14
3
Eine Instanz des Datensatzes mit dem Namen dsAuthors1 erscheint nun im unteren Bereich des Formulars und das Objekt dsAuthors.xsd wird im Projektmappen-Explorer (Solution) angezeigt. Siehe dazu Abbildung 19.15. Wenn Sie sich den generierten Code in der Code-Behind-Datei anschauen, werden Sie Folgendes feststellen: Eine protected-Variable dsAuthors1 des Typs dsAuthors wurde deklariert: protected VSÜberblick.dsAuthors dsAuthors1;
Die DataSetName-, Locale- und Namespace-Eigenschaften für dsAuthors sind wie folgt gesetzt: // dsAuthors1 this.dsAuthors1.DataSetName = "dsAuthors"; this.dsAuthors1.Locale = new System.Globalization.CultureInfo("en-US"); this.dsAuthors1.Namespace = "http://www.tempuri.org/dsAuthors.xsd";
ASP.NET 402
19
Eine Instanz des Datensatzes wird erzeugt Abb. 19.15
4
Ziehen Sie nun ein DataGrid aus der Web Form Toolbox auf das Formular. Im nächsten Schritt werde ich dieses DataGrid an das DataSet binden.
5
Erzeugen Sie die Bind()-Methode, welche das DataSet mit der Fill()-Methode des DataAdapters populieren (populate) und das DataGrid an den Datensatz folgendermaßen binden wird: public void Bind() { sqlDataAdapter1.Fill(dsAuthors1); DataGrid1.DataSource=dsAuthors1; }
Letztendlich rufen Sie die Page_load-Event wie folgt auf:
Bind-Methode
private void Page_Load(object sender, System.EventArgs e) { if (! IsPostBack) { Bind(); } }
im
Datenbankinteraktion mit Visual Studio.NET 19
403
Visual Studio.NET bietet Assistenten (Wizards) zur Erstellung von Methoden und Eigenschaften (Properties), allerdings überlasse ich es Ihnen, Genaueres darüber in Erfahrung zu bringen. Wenn Sie das Tasturkürzel S+H+cdrücken oder Ansicht/Klassenansicht (View/Class View) in dem Menü selektieren, erscheint das Fenster Klassenansicht. Diese Ansicht erlaubt Ihnen die Methoden, die Eigenschaften (Properties) und die Felder der Klasse zu erforschen. Sollten Sie auf den Klassennamen rechtsklicken und Hinzufügen (Add) wählen, werden Sie mit neuen Assistenten konfrontiert, die Ihnen helfen wollen, neue Methoden, Eigenschaften, Indizes oder Felder zu kreieren. 6
Führen Sie das Formular aus, indem Sie % drücken. Hier ist ein Screenshot der resultierenden Ausgabe:
Die resultierende Ausgabe Abb. 19.16
Sie werden es zu schätzen wissen, dass Visual Studio.NET es Ihnen erlaubt, Datenbankdaten in einem DataGrid mit nur einigen Zeilen Code zu präsentieren. Als RAD-Tool eignet sich Visual Studio.NET hervorragend. Der generierte Code ist elegant und präzise. Es lohnt sich, mit VS zu arbeiten, da sich die Entwicklungszeit dadurch beträchtlich senken lässt.
CRUD-Applikationen mit Visual Studio.NET
Erstellen Sie eine neue C#-ASP.NETWebanwendung
406
Die Datenkomponenten
408
DataGrid
409
Das Add-Panel
418
Die Command-Methoden des DataGrid spezifizieren
419
Methoden
420
ASP.NET 406
20 CRUD ist ein Akronym für Create-Read-Update-Delete, welche die vier Grundfunktionen einer Datenbankinteraktion darstellen. Visual Studio.NET kann jedoch noch mehr, als nur gut aussehende Oberflächen und entzückende Benutzerschnittstellen zu bauen. Wie Sie in diesem Kapitel sehen werden, kann Visual Studio.NET auch aufwändige Datenbankanwendungen erstellen, welche die Fähigkeit haben, select-, insert-, update- und delete-Befehle auf Datenbankdaten auszuführen. In diesem Kapitel werden wir ein Webformular erstellen, das Aufzeichnungen der stock_master-Tabelle zeigen kann. Mit Visual Studio.NET werden wir ein Formular erzeugen, das Datenbankdaten hinzufügen, modifizieren und löschen kann.
Erstellen Sie eine neue C#-ASP.NETWebanwendung Wie immer müssen Sie zunächst eine neue ASP.NET-Webanwendung erschaffen. Als Scriptsprache habe ich C# ausgewählt, und hier sind die dafür nötigen Schritte: 1
Erstellen Sie eine neue Webanwendung durch Klicken auf den Button Neues Projekt (New Project) auf der Startseite oder durch das Menü Datei/Neu/Projekt (File/New/Project).
2
Wählen Sie Visual C# Project auf der linken und ASP.NET-Webanwendung auf der rechten Seite aus. Ich habe dieses Projekt Kapitel20 genannt. Löschen Sie die Datei WebForm1.aspx, die automatisch erstellt wurde. Fügen Sie eine neue Web Form mit dem Namen StockMaster.aspx ein.
3
Wählen Sie eine Hintergrundfarbe für StockMaster .aspx. Klicken Sie dazu mit der rechten Maustaste auf einen leeren Bereich des Webformulars und wählen Sie Eigenschaften. Klicken Sie auf die Schaltfläche Hintergrund (Background color) aus der Registerkarte Farbe und Ränder (Color and Margins) der DOCUMENTEigenschaftenseiten (Document Property Page). Vergleichen Sie mit Abbildung 20.1. Ich habe mich für die Farbe #99cc99 entschieden.
CRUD-Applikationen mit Visual Studio.NET 20
407
Die Hintergrundfarbe des Webformulars Abb. 20.1
4
Fügen Sie den SqlClient-Namespace in die CodeBehind-Datei ein. Visual Studio.NET erstellt alle Namensräume bis auf den Sql Managed Provider automatisch. Erstellen Sie diesen Namensraum wie folgt: using System.Data.SqlClient;
Die Namespace-Sektion sieht nun so aus: using using using using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.SessionState; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls; System.Data.SqlClient;
ASP.NET 408
20
Die Datenkomponenten Erstellen Sie jetzt eine SqlConnection, einen SqlDataAdapter und ein DataSet: 1
Erstellen Sie die SqlConnection und den SqlDataAdapter durch ziehen der stock_master-Tabelle der ASPNET-Sample- Datenbank vom Server-Explorer auf das Formular. Der Server-Explorer zeigt die stock_masterTabelle wie in Abbildung 20.2 angezeigt an.
Die stock_master-Tabelle im Server-Explorer Abb. 20.2
Eine SqlConnection und ein SqlDataAdapter mit den Namen SqlConnection1 und SqlDataAdapter1 werden entsprechend erstellt. Vergleichen Sie dazu Abbildung 20.3. SqlConnection und SqlDataAdapter wurden durch Visual Studio erzeugt. Abb. 20.3
CRUD-Applikationen mit Visual Studio.NET 20 2
Wählen Sie die Menüoption DataSet generieren (Generate DataSet) aus dem Menü Daten aus. Dazu müssen Sie im Entwurfsmodus (Design) sein. Sie können auch DataSet generieren (Generate DataSet) auf der Eigenschaftsseite des SqlDataAdapters auswählen. Die Dialogbox DataSet generieren (Generate DataSet) erscheint, wie in Abbildung 20.4 zu sehen ist. Rufen Sie den Datensatz dsStock auf und stellen Sie sicher, dass das Kontrollkästchen DataSet zu Designer hinzufügen (Add this DataSet to the designer) angewählt ist.
DataSet generieren Abb. 20.4
Eine Instanz des DataSet dsStock1 erscheint unten auf dem Formular. Das Objekt dsStock.xsd wird auch im Projektmappen-Explorer angezeigt.
DataGrid Als Hauptbenutzerschnittstelle dient das DataGrid. Um es hinzuzufügen, ziehen Sie ein DataGrid von der Web Forms-Toolbox auf das Webformular.
409
ASP.NET 410
20 Sie müssen nun einige Attribute für das DataGrid festlegen. Dazu klicken Sie bitte mit der rechten Maustaste auf das DataGrid und wählen Eigenschaften (Properties). Die Eigenschaftenseite (Property Page) sollte wie in Abbildung 20.5 aussehen.
Setzten der Attribute von DataGrid Abb. 20.5
Verschönern Sie das DataGrid, indem Sie auf den Hyperlink Autom. Formatierung am unteren Ende der Eigenschaftsseite klicken und Klassisch 2 auswählen. Nun setzen Sie bitte die DataGrid-Eigenschaften wie folgt: DataSource = dsStock1 DataMember = stock_master DataKeyField = code_value Ich habe sie in Abbildung 20.5 eingekreist. Wechseln sie nun in die HTML-Ansicht und beachten Sie, dass DataSource-, DataMembers- und DataKeyField-Attribute zum DataGrid-Elementtag hinzugefügt wurden: DataGrid-Spalten selektieren
Wenn Sie die Eigenschaftsseite (Property Page) nicht bereits geöffnet haben, tun Sie dies bitte, indem Sie auf das DataGrid rechtsklicken und Eigenschaften (Properties) auswählen. Klicken sie dann auf den Hyperlink Eigenschaftengenerator (Property Builder), der sich unten befindet. Klicken Sie auf Spalten (Columns). Selektieren Sie alle Spalten, indem Sie auf Alle Felder (AllFields) in der Listbox Verfügbare Spalten (Available Columns) und anschließend auf den Pfeil (>) klicken. Vergleichen Sie bitte mit Abbildung 20.6.
Die Spalten von DataGrid selektieren Abb. 20.6
Wenn Sie sich das Formular in der HTML-Ansicht anschauen, werden Sie sicherlich feststellen, dass das -Elementtag auf diese Weise generiert wurde:
Setzen Sie die closing-Spalte auf read_only, da diese Spalte automatisch durch einen Trigger in der stock_detail-Tabelle aktualisiert wird. Die Primärschlüsselspalte code_value sollte auch auf read_only gesetzt werden. Um dies zu erreichen, tippen Sie einfach in der HTML-Ansicht drauflos und Visual Studio.NET wird Ihnen durch die Auto-Complete-Funktion einige Tags in einer Drop-Down-Liste zur Verfügung stellen. Die closing- und code_value-Spalten sollten wie folgt aussehen: Erstellen Sie die Hyperlinks Hinzufügen, Bearbeiten und Löschen
Erstellen Sie jetzt bitte die Button-Spalten Bearbeiten, Aktualisieren, Abbrechen (die Hyperlinks Update und Cancel erscheinen im Update-Modus des DataGrid). Scrollen Sie dafür in der Box Verfügbare Spalten (Available Columns), bis Sie die Beschriftung Schaltflächenspalten (Button Columns) sehen. Wenn Sie die Liste erweitern, wird die Option Bearbeiten, Aktualisieren, Abbrechen wie in Abbildung 20.7 zu sehen zum Vorschein gebracht.
CRUD-Applikationen mit Visual Studio.NET 20
413
Die Edit-, Update- und Cancel-Buttons Abb. 20.7
Klicken Sie bitte auf die Schaltfläche Hinzufügen (>). Das wird einen Hyperlink Bearbeiten erzeugen. Wenn Sie sich das Webformular in der HTML-Ansicht anschauen, werden Sie sehen, dass die EditCommandColumn-Tags mit den UpdateText-, CancelText- und EditText- Attributen kreiert wurden. Vielleicht erinnern Sie sich noch daran, dass dies die Hyperlinküberschriften sind, die mit den entsprechenden Hyperlinks Bearbeiten, Aktualisieren und Abbrechen angezeigt werden. Anfangs wird der Bearbeiten-Hyperlink im DataGrid dargestellt. Wenn Sie darauf klicken, wird das DataGrid im Bearbeiten-Modus angezeigt und die Aktualisieren- und Abbrechen-Hyperlinks erscheinen dann in dieser Phase.
Erstellen Sie eine Delete-Schaltfläche auf die gleiche Art, wie Sie die Button-Spalten Edit, Update und Cancel erzeugt haben. Diese Button-Spalten-Auswahl befindet sich direkt unter der Auswahl für die Button-Spalten Edit, Update und Cancel in der Liste Verfügbare Spalten (Available Columns). So wird die Button-Spalte Delete in der HTML-Ansicht aussehen:
ASP.NET 414
20
Nun haben Sie in dem DataGrid zwei Hyperlinks mit den Namen Edit und Delete. Wenn sie sich nicht direkt nebeneinander befinden, können Sie sie mit den Pfeiltasten bewegen. Sie können sie auch entfernen, indem Sie das Kreuz benutzen. Ziehen Sie ein LinkButton-Control aus der ToolBox auf das Webformular. Platzieren Sie es bitte auf dem DataGrid unter der Seitenüberschrift. Rechtsklicken Sie bitte darauf und wählen Sie Eigenschaften. Setzen Sie folgende Eigenschaften: ID = Add Text = Add a new record ToolTip = Adds a new inventory master Doppelklicken Sie nun bitte auf das LinkButton-Control. Ein leerer Methodenrumpf mit dem Namen Add_Click ist in der Code-Behind-Datei erzeugt worden. Wir werden den Code später vervollständigen. Zurzeit sieht das Codeskelett so aus: private void Add_Click(object sender, System.EventArgs e) { } Konvertieren Sie die Spalten in Vorlagenspalten (Template Columns)
Obwohl das DataGrid schon jetzt funktioniert, ist es besser, die Spalten in Vorlagenspalten umzuwandeln. Der größte Vorteil besteht darin, dass wir IDs mit den EditItemTemplates assoziieren können, welche dazu benutzt werden können, im Aktualisieren-Modus auf Spaltendaten zuzugreifen. In der Grid1_Update-Methode sind wir gezwungen, auf die Spaltendaten zuzugreifen, um einen Update-SQL-Befehl zu erzeugen. Wenn keine IDs vorhanden sind, haben wir einen Bezug auf die Controls, wenn wir die Indexwerte folgendermaßen benutzen: TextBox t; t = (TextBox)e.Item.Cells[2].Controls[0]; String code_display = " code_display = '" + t.Text.Trim() + "'," ;
CRUD-Applikationen mit Visual Studio.NET 20 Aus irgendeinem Grund klappt das nicht immer wie erwartet, wohingegen die Benutzung der ID des Controls zuverlässig funktioniert. Wie Sie später noch sehen werden, können Sie die FindControl-Methode eines Controls dazu verwenden, um ein Control einer spezifizierten ID innerhalb eines DataGrids zu lokalisieren. Das kann dann auf eine TextBox gecastet werden und seine Text-Attribute können auf diese Weise extrahiert werden: t = (TextBox) e.Item.FindControl("editCode_Display"); String code_display = " code_display = '" + t.Text.Trim() + "'," ;
Um diese Spalten in Vorlagenspalten umzuwandeln, gehen Sie bitte zum Eigenschaftengenerator zurück und selektieren Sie Spalten (Columns). Wählen Sie jeweils einzeln die Spalten code_display, rate, uom und opening in der Listbox Ausgewählte Spalten und klicken Sie auf den Hyperlink Konvertiert die Spalte in eine Vorlagenspalte (Convert this column into a Template Column) im unteren Bereich. In der HTML-Ansicht sollten Sie nun noch den EditItemTemplates eindeutige IDs vergeben. Sobald Sie lostippen, werden Sie feststellen, dass VS versuchen wird, Ihre Eingabe für Sie zu vervollständigen. Jede Template-Spalte hat ein ItemTemplate und ein zugehöriges EditItemTemplate. Dieses EditItemTemplate kann jede Art von ASP.NET- Control sein (z.B. eine TextBox oder ein DropDownList-Control), wohingegen das ItemTemplate ein LabelControl ist. Das ItemTemplate ist das Control, das anfangs im DataGrid in Erscheinung tritt. Wenn Sie auf den Hyperlink Edit im DataGrid klicken, erscheint das EditItemTemplate. Da dies ein editierbares Control ist, können Sie die angezeigten Werte wie in einer TextBox verändern. Fügen Sie bitte die folgenden IDs unter dem EditItemTemplate hinzu: Die code_display Spalte, die ID wird editCode_display sein. Die rate Spalte, die ID wird editRate sein. Die uom Spalte, die ID wird editUom sein. Die opening Spalte, die ID wird editOpening sein.
415
ASP.NET 416
20 Das -Elementtag sollte in der HTML-Ansicht so aussehen:
CRUD-Applikationen mit Visual Studio.NET 20
417
Das Attribut AutoGenerateColumns des DataGrids auf False stellen Abb. 20.8
Wenn Sie das Webformular zu diesem Zeitpunkt ausprobieren, werden Sie sicher feststellen, dass jede Spalte zweimal im DataGrid vorkommt. Das kommt daher, dass das DataGrid zusätzlich zu unseren Vorlagenspalten weitere Spalten autogeneriert. Sie können dies aber verhindern, indem Sie entweder das Attribut AutoGenerateColumns des DataGrids auf False setzen oder indem Sie in dem Kontrollkästchen Spalten
ASP.NET 418
20 automatisch zur Laufzeit erstellen im Eigenschaftengenerator das Häkchen entfernen (siehe Abbildung 20.8). Dem HTML-Code wurde nun ein Attribut AutoGenerateColumns=”False" hinzugefügt. Es befindet sich im DataGrid-Elementtag:
Das Add-Panel Wir benötigen nun noch ein Panel, auf dem sich eine Reihe von TextBox- und Label-Controls befinden. Diese besitzen die Fähigkeit, neue Zeilen in die stock_master-Tabelle einzufügen. Der Grund, aus dem wir diese Controls auf einem Panel unterbringen wollen, ist, weil wir durch das Setzen des Visible-Attributs des Panels auf false die TextBox-Controls und die LabelControls ausblenden können. Ziehen Sie bitte ein Panel aus der ToolBox auf das Webformular. Rechtsklicken Sie bitte auf das Panel und wählen Sie Eigenschaften (Properties). Geben Sie es die ID AddPanel und setzen Visible auf False. Ziehen jetzt noch vier Label-Controls und vier TextBox-Controls auf das Panel. Sie sollten sie untereinander anordnen. Um sie im Panel anzuordnen, ziehen Sie zunächst eine TextBox und ein Label hinein. Rechtsklicken und kopieren Sie bitte das Label, um es dann eine Zeile darunter einzufügen. Strecken sie das zweite Label mit der Maus, bis es mit dem ersten Label gerade abschließt. Nun fügen Sie die TextBox mit Copy & Paste ein, so dass sie sich in der zweiten Zeile neben das Label gesellt. Wiederholen Sie das, bis alle Controls in der gewünschten Ordnung auf dem Formular aneinandergereiht sind. Sie müssen dies so ausführen, damit die Komponenten ordentlich nebeneinander aufgereiht werden. Die TextBox- Controls werden alle die gleiche Größe haben, jedoch werden die Label- Controls je nach der Beschriftung, die Sie haben wollen, unterschiedlich groß ausfallen. Deshalb müssen Sie die Label-Controls mit Ihrer Maus bearbeiten, bis sie sich bündig ausrichten. Sie können
CRUD-Applikationen mit Visual Studio.NET 20 auch mit den Strg-Pfeiltasten die Controls verschieben und mit den Shift-Pfeiltasten ihre Größe verändern. Geben Sie bitte den TextBox-Controls die entsprechenden IDs AddCode_Display, AddRate, AddUom und AddOpening. Sie erreichen dies, indem Sie darauf rechtsklicken und Eigenschaften (Properties) und dann anschließend ID wählen. Gügen Sie bitte noch ein Button-Control hinzu und geben Sie ihm die ID SaveNew. Doppelklicken Sie darauf, um einen Methodenrumpf zu erschaffen, der folgendermaßen aussehen sollte: private void SaveNew_Click(object sender, System.EventArgs e) { }
Diese Methode werden wir etwas später noch programmieren. Ich habe auch noch zusätzlich einen leeren Label hinzugefügt, um das Button- Control in der Mitte des Formulars zu platzieren.
Die Command-Methoden des DataGrid spezifizieren Spezifizieren Sie OnEditCommand, OnCancelCommand, OnUpdateCommand und OnDeleteCommand innerhalb des DataGridElementtags. Diese Attribute des DataGrids spezifizieren die Methode, die aufgerufen wird, sobald der Benutzer auf die Hyperlinks Bearbeiten, Abbrechen, Aktualisieren oder Löschen klickt. Dazu müssen Sie das Formular in der HTML-Ansicht öffnen und diese Attribute eigenhändig innerhalb des DataGridElementtags eintragen:
419
ASP.NET 420
20
Methoden Jetzt werden wir einige Methoden für das Webformular programmieren. Offnen Sie die Code-Behind-Datei (StockMaster.aspx.cs) und ergänzen Sie sie noch mit folgenden Methoden: Die Bind()-Methode füllt den Datensatz mit der Fill-Methode des DataAdapters. Sie bindet auch das DataGrid an den Datensatz: Listing 20.1: Die Bind-Methode public void Bind() { sqlDataAdapter1.Fill(dsStock1); DataGrid1.DataSource=dsStock1; DataGrid1.DataBind(); if (AddPanel.Visible==true) {AddPanel.Visible=false;} }
Die Bind-Methode wird im Page_Load-Event aufgerufen: private void Page_Load(object sender, System.EventArgs e) { if (! IsPostBack) { Bind(); } }
Wenn Sie das Webformular ausführen (S+%), sollten Sie das Formular in Ihrem Browser wie in Abbildung 20.9 gezeigt sehen. Die Grid1_Edit-Methode wird aufgerufen, sobald der Benutzer den Edit-LinkButton klickt. Sie setzt den EditItemIndex des DataGrid auf die angeklickte Zeile und ruft die Bind-Methode folgendermaßen auf:
CRUD-Applikationen mit Visual Studio.NET 20
421
Das Stock-MasterFormular zeigt die Daten an Abb. 20.9
Listing 20.2: Grid1_edit public void Grid1_Edit(Object sender, DataGridCommandEventArgs e) { DataGrid1.EditItemIndex = e.Item.ItemIndex; Bind(); }
Das Grid1_Cancel-Event wird durch das Klicken des Benutzers auf den Cancel-LinkButton im Edit-Modus des DataGrid aktiviert. Diese Methode setzt einfach den EditItemIndex auf -1, was im Gegenzug dem DataGrid mitteilt, dass keine Zeile mehr selektiert ist und dass es den Update-Modus schließen soll. Anschließend wird die Bind-Methode aufgerufen, um das DataGrid zu aktivieren. Listing 20.3: Grid1_Cancel public void Grid1_Cancel(Object sender, DataGridCommandEventArgs e) { DataGrid1.EditItemIndex = -1; Bind(); }
ASP.NET 422
20 Das Grid1_Delete-Event wird durch einen Klick auf den Delete-LinkButton des DataGrids abgefeuert. Dieses Event extrahiert den Primärschlüssel der angeklickten Zeile und erstellt einen SQL-Delete-Befehl, der dann an die RunSql-Methode zur Weiterverarbeitung übergeben wird. Schließlich wird der EditItemIndex auf -1 gesetzt und das DataGrid durch Aufruf der Bind-Methode aktualisiert. Listing 20.4: Grid1_Delete public void Grid1_Delete(Object sender, DataGridCommandEventArgs e) { int Key=(int)DataGrid1.DataKeys[(int)e.Item.ItemIndex]; String code_value = Key.ToString() ; String s = "Delete from stock_master"; s +=" where code_value = " + code_value; RunSql(s); DataGrid1.EditItemIndex = -1; Bind(); }
Die Grid1_Update-Methode wird abgefeuert, falls der Benutzer mit den Änderungen der Daten im Update-Modus zufrieden ist und anschließend auf den Update-LinkButton klickt. Diese Methode extrahiert den Primärschlüssel, indem sie beim DataKey-Attribut der angeklickten Zeile nachschaut. Anschließend nutzt sie die FindControl-Methode eines Controls, um die ID innerhalb des DataGrids zu lokalisieren. Das zurückgegebene Objekt wird auf eine TextBox gecastet und das Text-Attribut, wie weiter unten gezeigt, extrahiert. Ein SQL-Update-Befehl wird nun aus den extrahierten Text-Attributen des TextBoxControls erstellt. Dieser wird nun an die RunSql-Methode für die eigentliche Ausführung weitergeleitet. Letztendlich wird der EditItemIndex auf -1 gesetzt und die Bind-Methode aufgerufen, um das DataGrid zu aktualisieren. Listing 20.5: Grid1_Update public void Grid1_Update(Object sender, DataGridCommandEventArgs e) { TextBox t;
CRUD-Applikationen mit Visual Studio.NET 20 //Das ist der Primärschlüssel int Key=(int)DataGrid1.DataKeys[(int)e.Item.ItemIndex]; String code_value = " code_value =" + Key.ToString() ; t = (TextBox) e.Item.FindControl("editCode_Display"); String code_display = " code_display = '" + t.Text.Trim() + "'," ; t = (TextBox) e.Item.FindControl("editRate"); String rate = " rate = " + t.Text.Trim() + "," ; t = (TextBox) e.Item.FindControl("editUom"); String uom = " uom ='" + t.Text.Trim() + "'," ; t = (TextBox) e.Item.FindControl("editOpening"); String opening = " opening = " + t.Text.Trim() ; String s = " Update stock_master Set"; s += code_display +rate +uom ; s += opening ; s += " Where " + code_value; RunSql(s); DataGrid1.EditItemIndex = -1; Bind(); }
Diese Methode wird dazu verwendet, die SQL-Befehle Insert, Update und Delete auszuführen. Listing 20.6: RunSql public String RunSql( string vsql) { try { SqlCommand mycommand = new SqlCommand(vsql,sqlConnection1); sqlConnection1.Open(); mycommand.ExecuteNonQuery(); sqlConnection1.Close(); } catch(Exception e)
423
ASP.NET 424
20 { string ret = "Exception: " + e.ToString() ; messages.Text=ret; } return("OK"); }
Das Add_Click-Event wird abgefeuert, sobald der Benutzer auf den Add-LinkButton klickt. Dieses Event initialisiert die TextBox-Controls mit den Standardwerten und zeigt diese an, indem es das Visible-Attribut des AddPanel auf True setzt. Listing 20.7: Add_Click private void Add_Click(object sender, System.EventArgs e) { AddPanel.Visible=true; AddCode_Display.Text= ""; AddRate.Text= "0"; AddUom.Text= ""; AddClosing.Text= "0"; }
Das SaveNew_Click-Event wird abgefeuert, sobald der Benutzer auf den SaveNew-Button, der sich auf dem AddPanel befindet, klickt. Dieses Event setzt zuerst die Standardwerte in allen vom Benutzer leer gelassenen TextBox-Controls. Danach erstellt es einen SQL-Befehlsaufruf an die gespeicherte Prozedur p_stock_master und übergibt ihr die benötigten Parameter. Diese Parameter erhält es durch Extrahieren der Text-Attribute der verschiedenen TextBox-Controls. Sie müssen dieser Prozedur ein code_value NULL übergeben, um einen neuen Eintrag einfügen zu können. Der Execute-Aufruf wird dann an die RunSql-Methode weitergeleitet, welche für die eigentliche Verarbeitung zuständig ist. Nun wird noch der EditItemIndex auf -1 gesetzt und die Bind- Methode wird aufgerufen, um das DataGrid zu aktualisieren. Listing 20.8: SaveNew_Click private void SaveNew_Click(object sender, System.EventArgs e) { if (AddCode_Display.Text.Length == 0)
CRUD-Applikationen mit Visual Studio.NET 20 { messages.Text="Leider kann der Konto Name (Account Name) nicht leer sein"; return ; } if (AddRate.Text.Length == 0) {AddRate.Text= "0";} if (AddUom.Text.Length == 0) {AddUom.Text= "";} if (AddClosing.Text.Length == 0) {AddClosing.Text= "0";} String s = "p_stock_master ausführen"; s += " @code_value=NULL," ; s += " @code_display = '" + AddCode_Display.Text + "',"; s += " @rate = " + AddRate.Text + ","; s += " @uom = '" + AddUom.Text + "',"; s += " @closing = " + AddClosing.Text ; messages.Text= ""; RunSql(s); DataGrid1.EditItemIndex = -1; Bind(); }
Damit wäre unsere Betrachtung über CRUD-Applikationen mit Visual Studio.NET zum Abschuss gebracht. Sie haben sicherlich erkannt, welche signifikanten Vorteile ein solches Tool beim Programmieren bringt. Ich muss zugeben, dass ich sehr von der Autovervollständigung der Elementtags in der HTML-Ansicht von Visual Studio.NET beeindruckt bin. Ich muss nicht mehr die einzelnen Attribute der Tags auswendig können, da sie angezeigt werden, sobald ich anfange zu tippen. Auch die Möglichkeit, die Controls nach Lust und Liebe mit der Maus zu verschieben, gehört zu den Features, die ich sehr mag.
425
Einen Webservice mit Visual Studio.NET erstellen
Den generischen DatenbankWebservice erstellen
428
Der Webservice wird aufgebaut
430
Den Webservice aus einem Webformular aufrufen
436
Projekt 2 – Zusammenfassung
446
ASP.NET 428
21 In diesem Kapitel werde ich Ihnen zeigen, wie man einen Webservice mit Visual Studio.NET entwickelt. Sie werden erst einmal einen generischen Datenbankservice in C# erstellen. Dieser Webservice wird eine Methode mit dem Namen Populate haben. Diese Methode wird SQL-SELECT-Befehle entgegennehmen. Aufgrund dieses SELECT-Befehls wird der Webservice diesen ausgewählten Datensatz an das aufrufende Objekt zurückgeben. Der Webservice wird noch eine RunSql-Methode haben, die dazu verwendet wird, eine Action Query (einen Insert-, einen Update- oder einen Delete-Befehl) an die Datenbank weiterzuleiten. Sie werden dann noch ein Webprojekt entwickeln, das sich diesen Service zunutze machen wird. Dieses Projekt wird die Populate-Funktion des Webservices mit den entsprechenden Parametern aufrufen und daraufhin einen Datensatz mit dem Resultat erhalten. Ein DataGrid wird dann an den Datensatz gebunden, um die angeforderten Daten der Zeilen zu visualisieren. Sie werden auch die RunSql-Methode testen, indem einige Zeilen eingefügt und gelöscht werden.
Den generischen Datenbank-Webservice erstellen 1
Starten Sie Visual Studio.NET.
2
Wählen Sie Datei/Neu/Projekt (File/New/Project).
3
Wählen Sie C# Projects auf der linken und ASP.NET Webdienst auf der rechten Seite. Abbildung 21.1 zeigt den aktuellen Zustand von VS.NET. (In der Release Candidate Version von Visual Studio.NET kann man den Projektnamen hinter dem Pfad anfügen – in diesem Falle http://localhost/CSharpdbService. Das Namensfeld ist deaktiviert, wird aber automatisch den eingetippten Projektnamen anzeigen.)
4
Wählen Sie bitte den Namen CSharpdbService.
Einen Webservice mit Visual Studio.NET erstellen 21
429
Ein C#- ASP.NETWebservice wird erstellt Abb. 21.1
5
Visual Studio.NET erstellt eine neue Projektmappe (Solution), welche ein Verweiseverzeichnis und vier Dateien kreiert. Web.config ist eine XML-Datei, die verschiedene Konfigurationssoptionen (z.B. Session Timeout Interval) enthält und den Webservice zur Laufzeit kontrolliert. CSharpdbService.vsdisco ist eine XML-Datei, die für die dynamische Suche nach Webservices durch Clients zuständig ist. Das heißt, wenn Sie diesen Service in einem anderen Projekt benutzen wollen, navigieren Sie zu dieser Datei und VS.NET erstellt eine Referenz zu diesem Service für Sie. In der Datei Global.asax residieren projektweite Eventhandler wie ApplicationStart und ApplicationEnd.
6
Rechtsklicken Sie auf Service1.asmx und selektieren Sie Öffnen mit (OpenWith) und anschließend Quellcode-Editor (Text). Oder navigieren Sie zu dem Applikationsverzeichnis und öffnen Sie die Datei in Ihrem Editor. Sie werden entdecken, dass diese Datei auf den Code einer anderen Datei (Service1.asmx.cs) verweist:
ASP.NET 430
21 Wenn sie so weit gekommen sind, haben Sie alle Teile für den Webservice beisammen. Sie müssen jetzt nur noch den Code für die Webservice-Datei (asmx) programmieren.
Der Webservice wird aufgebaut In diesem Teil werden wir einen Webdienst mit dem Namen dbService erstellen. Er wird die Methoden Populate und RunSql besitzen. 1
Löschen Sie bitte die automatisch erstellte Datei Service1.asmx und fügen Sie eine neue Webdienstdatei hinzu. Dazu rechtsklicken Sie bitte auf den Projektnamen und wählen Hinzufügen/Webdienst hinzufügen (Add/Add Webservice). Nennen Sie diesen Webdienst dbService.asmx.
2
Ein Webdienstgrundgerüst wird erschaffen und beinhaltet einige Namensräume. Diese Namespaces sind nun in der Datei dbService.asmx.cs vorhanden: using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Diagnostics; System.Web; System.Web.Services;
Da Sie mit Datenbanken kommunizieren wollen, müssen Sie entweder die Namensräume für SQL oder für OleDb Managed Provider importieren. Ich habe mich für das zweite entschieden, da ich den dbService-Webservice so generisch wie möglich halten möchte. Der SQL Managed Provider würde uns auf Microsofts SQL Server-Datenbank einschränken. Sie sollten den OleDb Managed Provider-Namespace auf folgende Weise importieren: using System.Data.OleDb;
Der Webservice ist im Namensraum von CSharpdbService erstellt:
Einen Webservice mit Visual Studio.NET erstellen 21 namespace CSharpdbService { //Hier steht der gesamte Code }
Die Klasse heißt dbService und erbt von System.Web.Services.WebService. Die Vererbung wird durch den Doppelpunkt (:) vor der Basisklasse angezeigt: public class dbService : System.Web.Services.WebService
dbService hat ein connStr-Feld, welches Sie als private deklarieren müssen: private String connStr;
Die dbService-Klasse hat einen Konstruktor ohne Parameter. Ein Konstruktor ist eine Methode, die den gleichen Namen wie die Klasse hat. Jede Klasse besitzt einen Standardkonstruktor, der keine Parameter akzeptiert. Es steht jeder Klasse frei, zusätzliche Konstruktoren, die beliebige Parameter akzeptieren, zu beherbergen. Im Konstruktor wird der ConnectionString folgendermaßen auf das private Feld connStr gesetzt: public dbService() { InitializeComponent(); connStr = "Provider=SQLOLEDB; Data Source=(local); "; connStr = connStr+" Initial Catalog=PUBS;User ID=sa;Password="; } 3
Zwei Webmethoden müssen in der dbService-Klasse erstellt werden. Eine Webmethode wird wie eine normale C#-Methode erstellt, ist jedoch mit einem vorangestellten Attribut [WebMethod] versehen. Die erste Methode heißt Populate und sendet einen SELECT- SQL-Befehl an die Datenbank und erhält dafür das resultierende DataSet zurück. Dieses DataSet kann dann dazu benutzt werden, um ein Bound-Control wie
431
ASP.NET 432
21 das DataGrid zu binden. Hier ist die Auflistung der Methode: [WebMethod] public DataSet Populate(string SQL) { //für abfragen, die Daten zurückliefern //und für bindende Controls OleDbConnection myConnection = new OleDbConnection(connStr); OleDbDataAdapter myCommand = new OleDbDataAdapter(SQL, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "vTable"); return ds; }
Die zweite Methode RunSQL sendet ein Action Query an die Datenbank. Eine Action Query ist, wie Sie sicher wissen werden, eine SQL Query, wie z.B. Insert, Delete oder Update. Sie führt irgendeine Aktion in der Datenbank aus, ohne Daten zurückzuerhalten. Diese Methode akzeptiert ein gültiges SQL Insert, Delete oder Update Query und leitet es an die Datenbank weiter. Hier ist der Code dieser Methode: [WebMethod] public String RunSQL( string vsql) { try { OleDbConnection myConnection = new OleDbConnection(connStr); OleDbCommand mycommand = new OleDbCommand(vsql,myConnection); myConnection.Open(); mycommand.ExecuteNonQuery(); myConnection.Close(); return("OK"); } catch(Exception e) { string ret = "Exception: " + e.ToString() ;
Einen Webservice mit Visual Studio.NET erstellen 21 return ret; } }
Ihr Webdienst ist nun fertig gestellt. Sie können ihn mit einem rechten Mausklick auf die asmx-Datei des Webservices (dbService.asmx) im Projektmappen-Explorer und die Auswahl von Als Startseite festlegen (Set as Start Page) ausprobieren. Jetzt drücken Sie noch % und die Webservice-Testseite sollte wie in Abbildung 21.2 aussehen.
Die Testseite des Webservices Abb. 21.2
Klicken Sie nun auf die Methode Populate. Auf der nun erscheinenden Seite tragen sie bitte folgenden Parameterwert ein: Select * from authors
Wenn Sie auf die Schaltfläche Aufrufen (invoke) klicken, werden alle Aufzeichnungen der authors-Tabelle im XML-Format angezeigt:
433
ASP.NET 434
21
Die Populate-Methode gibt Datenbankzeilen als XML aus Abb. 21.3
Hier ist der vollständige Code des Webservices: Listing 21.1: dbService.asmx using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Diagnostics; System.Web; System.Web.Services; System.Data.OleDb;
namespace CSharpdbService { /// /// Zusammenfassungsbeschreibung für dbService. /// public class dbService : System.Web.Services.WebService { private String connStr; public dbService() { //CODEGEN: Dieser Aufruf ist für den ASP.NETWebdienst-Designer erforderlich. InitializeComponent(); connStr = "Provider=SQLOLEDB; Data Source=(local); ";
Einen Webservice mit Visual Studio.NET erstellen 21 connStr = connStr+" Initial Catalog=PUBS;User ID=sa;Password="; } #region Component Designer generated code /// /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem CodeEditor geändert werden. /// private void InitializeComponent() { } #endregion /// /// Die verwendeten Ressourcen bereinigen. /// protected override void Dispose( bool disposing ) { } [WebMethod] public DataSet Populate(string SQL) { //Für Abfragen, die Daten zurückerhalten, //und für bindende Controls OleDbConnection myConnection = new OleDbConnection(connStr); OleDbDataAdapter myCommand = new OleDbDataAdapter(SQL, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "vTable"); return ds; } [WebMethod] public String RunSQL( string vsql) { try { OleDbConnection myConnection = new OleDbConnection(connStr); OleDbCommand mycommand = new
435
ASP.NET 436
21 OleDbCommand(vsql,myConnection); myConnection.Open(); mycommand.ExecuteNonQuery(); myConnection.Close(); return("OK"); } catch(Exception e) { string ret = "Exception: " + e.ToString() ; return ret; } } } }
Den Webservice aus einem Webformular aufrufen In diesem Teil werde ich eine Clientapplikation entwickeln, die den Webdienst, den wir im letzten Abschnitt gebaut haben, benutzen wird. Diese Anwendung ist eine C#-ASP.NET-Webanwendung und wird wie in den nächsten Schritten beschrieben erstellt: 1
Starten Sie Visual Studio.NET und öffnen Sie die CSharpdbService-Projektmappe (Solution), die wir zuvor erstellt haben. (Diese Projektmappe muss geöffnet werden, da Sie das neue Projekt dort einfügen werden.)
2
Wählen Sie Datei/Neu/Projekt (File/New/Project).
3
Wählen Sie C# Projects auf der linken und ASP.NET Webdienst auf rechten Seite. Aktivieren Sie das Optionsfeld mit der Bezeichnung Zu Projektmappe hinzufügen (Add to Solution – siehe Abbildung 21.4). Dadurch wird dieses neue Projekt in die bestehende Projektmappe (Solution) eingefügt und Sie können mit beiden Projekten gleichzeitig in einer Projektmappe arbeiten. Nennen Sie dieses neue Projekt TheClient. In der Release Candidate Version von Visual Studio.NET kann man den Projektnamen hinter dem Pfad anfügen
Einen Webservice mit Visual Studio.NET erstellen 21
437
– in diesem Falle http://localhost/TheClient. Das Namensfeld ist deaktiviert, wird aber automatisch den eingetippten Projektnamen anzeigen.
Eine neue C#-ASP.NETWebapplikation erstellen Abb. 21.4
So werden beide Projekte im Projektmappen-Explorer aussehen:
Beide Projekte werden im Projektmappen-Explorer angezeigt Abb. 21.5
ASP.NET 438
21 4
Rechtsklicken Sie bitte auf das aspx-Formular mit dem Namen WebFrom1.aspx, welches automatisch erschaffen wurde, und legen Sie es als Startseite fest. Sie müssen auch noch das Projekt TheClient als Startprojekt festlegen. Dazu klicken Sie im Projektmappen bitte wieder mit der rechten Maustaste auf den Projektnamen und wählen Als Startprojekt festlegen (Set as StartUp Project).
5
Rechtsklicken Sie bitte auf eine freie Stelle auf dem Formular und wählen Sie Eigenschaften (Properties). Stellen Sie sicher, dass das Page_Layout-Attribut auf GridLayout gesetzt ist. Mit GridLayout können Sie die Controls visuell mit der Maus auf dem Formular positionieren. Ziehen Sie bitte ein DropDownList-Control, zwei Label-Controls, ein DataGrid-Control und zwei Button-Controls auf das Formular. Rechtsklicken Sie auf jeden der Buttons und wählen Sie Eigenschaften (Properties). Dort geben Sie ihnen die IDs Populate und RunSql. Das erste Label-Control wird für den Titel dieses Formulars benutzt. Dem zweiten Label-Control wird eine ID von messages gegeben. Rufen Sie die Eigenschaften des DropDownList-Controls auf (wie immer mit Rechtsklick und Eigenschaften (Properties)). Finden Sie das items-Attribut und klicken Sie auf die drei Punkte daneben, um den ListItem-AuflistungsEditor aufzurufen. Klicken Sie auf die Schaltfläche Hinzufügen unten auf dem Panel. Nun müssen Sie noch einige SELECT-SQL-Abfragen in die Value Input Box eintragen. Sie können z.B. Folgendes eintragen: Select Select Select Select
* * * *
from from from from
authors titles publishers pub_info where pub_id = "9999"
Der Benutzer wird einen dieser SELECT-Aufrufe aus der Drop-Down-List auswählen, die dann wiederum an die Populate-Methode des Webservices weitergeleitet werden. Der Webservice wird ein DataSet zurückgeben, das das DataGrid binden wird. Ich habe das Webformular verschönert, indem ich mit der rechten Maustaste auf eine leere Stelle geklickt und
Einen Webservice mit Visual Studio.NET erstellen 21 die Eigenschaften aufgerufen habe. Das ruft das Fenster Dokument-Eigenschaftenseiten (Document Property Pages) auf, wo ich dann auf dem Feld Farbe und Ränder (Colors and Margins) auf die drei Punkte neben der Box Hintergrundfarbe geklickt habe. Dort habe ich dann eine schicke Farbe für das Formular ausgewählt. Ich habe mich für die Farbe #ffcc99 entschieden. Danach wollte ich noch das DataGrid verschönern. Also rechtsklickte ich auf das DataGrid und begab mich in das Fenster Eigenschaften (Properties), wo ich weiter unten auf den Hyperlink Autom. Formatierung klickte. Ich entschied mich für das Farbschema Klassisch 2 aus der mir präsentierten Liste von Stilen. Das Webformular sollte nun wie in Abbildung 21.6 ausschauen.
Design des ClientWebformulars Abb. 21.6
6
Sie müssen eine Referenz auf den CSharpdbService erstellen, um ihn in der Anwendung benutzen zu können. Dazu wählen Sie bitte Projekt/Webverweis hinzufügen (Project/Add Web Reference) aus dem Hauptmenü. Oder Sie klicken auf den Projektnamen im Projektmappen-Fenster und wählen Webverweis hinzufügen (Add Web Reference).
439
ASP.NET 440
21 Ein neues Fenster mit dem Namen Webverweis hinzufügen erscheint. Auf der linken Seite klicken sie bitte auf den Hyperlink Webverweise auf dem Lokalen Webserver. Dies sollte Ihnen alle Discovery-Dateien (*.disco oder *.vsdisco) anzeigen. Daraus wählen Sie bitte CSharpdbService.vsdisco aus. Visual Studio.NET wird den Webservice entdecken und das Resultat wie in Abbildung 21.7 präsentieren. Sie können auch den vollständigen Pfad (localhost) des Webservices angeben und ein ?wsdl hinten in der Adressleiste anfügen. Zum Beispiel befindet sich mein Webservice auf http://localhost/CSharpdbService/dbService.asmx? wsdl.
Die Suche nach Webservices Abb. 21.7
Klicken Sie nun bitte auf die Schaltfläche Verweis hinzufügen am unteren Rand des Fensters. Eine Referenz auf den Webservice wird nun im Projektmappen-Explorer zusätzlich angezeigt.:
Einen Webservice mit Visual Studio.NET erstellen 21
441
Referenz auf den Webservice im Solution Explorer Abb. 21.8
7
Um das Ganze zum Laufen zu bringen, fehlt noch ein wenig Code. Als Erstes deklarieren und instanziieren Sie den Webservice folgendermaßen: private localhost.dbService mydbService = new localhost.dbService();
Programmieren sie nun den Click-Event von Button1. Bitte beachten Sie, dass sich die Click-Events der beiden Buttons hinter der Methode InitializeComponent()befinden müssen, da die Delegates für diese Click-Events erst in dieser Methode erzeugt werden. Wenn Sie sie doch vor diese Methode platzieren sollten, werden sie nicht abgefeuert. private void Populate_Click(object sender, System.EventArgs e) { DataSet ds = new DataSet(); String s = DropDownList1.SelectedItem.ToString(); ds = mydbService.Populate(s); DataGrid1.DataSource=ds; DataGrid1.DataBind(); }
ASP.NET 442
21 Dies testet die Populate-Methode. Der vom Benutzer ausgewählte SELECT-Befehl wird an die Populate-Methode des Webservices gesendet. Ein Datensatz wird zurückgegeben, welcher an das DataGrid gebunden wird. Nachdem Sie % gedrückt haben, um die Populate-Methode zu testen, sollte das Webformular wie im Screenshot in Abbildung 21.9 aussehen.
Auswahl eines SELECTBefehls zeigt das Ergebnis im DataGrid an Abb. 21.9
Um die RunSQL-Methode des Webservice zu testen, muss der folgende Code hinter das Click-Event des RunSql-Buttons angefügt werden: private void RunSql_Click(object sender, System.EventArgs e) { string s; String ret; s = "Delete from pub_info where pub_id = '9999'"; ret=mydbService.RunSQL(s); messages.Text= ret; //füge eine zufällige Zahl ein Random r = new Random(); s = " insert into pub_info(pub_id,pr_info) values("; s = s + " '9999','" + r.Next(1000).ToString() + "')"; ret = mydbService.RunSQL(s); messages.Text= ret;
Einen Webservice mit Visual Studio.NET erstellen 21
443
//Refresh the DataGrid to show changes DataSet ds = new DataSet(); s = "Select * from pub_info where pub_id = '9999'"; ds = mydbService.Populate(s); DataGrid1.DataSource=ds; DataGrid1.DataBind(); }
Diese Methode benutzt die Webservice-Methode RunSql, um zuerst die Zeilen der pub_info-Tabelle mit der pub_id von 9999 zu löschen. Anschließend wird mit Hilfe der Random-Klasse eine zufällige Zahl zwischen 1 und 1000 erzeugt. Dies macht die Next-Methode der Random-Klasse, basierend auf dem Parameter, den es erhält. Dieser Parameter spezifiziert das obere Limit der Zufallszahl, das ich hier auf 1000 gesetzt habe. Diese Zahl wird in die pr_info-Spalte der pub_info-Tabelle mit der pub_id von 9999 eingefügt. Schließlich wird die Populate-Methode aufgerufen, um die veränderte Zeile zurückzugeben. Das DataGrid ist wieder einmal an den zurückgegebenen Datensatz gebunden und zeigt deswegen den aktuellsten Wert an. Sie können diese Methode testen, indem sie auf die Schaltfläche RunSql Test klicken. Jedes Mal, wenn Sie das tun, werden Sie eine neue Zahl in der pr_info-Spalte angezeigt bekommen (siehe Abbildung 21.10).
Der Button RunSql Test fügt eine Zufallszahl in die Tabelle ein. Abb. 21.10
ASP.NET 444
21 Hier ist das gesamte WebForm1.aspx.cs:
Listing
der
Code-Behind-Datei
Listing 21.2: WebForm1.aspx.cs using using using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.SessionState; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls;
namespace TheClient { /// /// Zusammenfassungsbeschreibung für WebForm1. /// public class WebForm1 : System.Web.UI.Page { protected System.Web.UI.WebControls.DataGrid DataGrid1; protected System.Web.UI.WebControls.Label Label1; protected System.Web.UI.WebControls.DropDownList DropDownList1; protected System.Web.UI.WebControls.Button RunSql; protected System.Web.UI.WebControls.Button Populate; private localhost.dbService mydbService = new localhost.dbService(); public WebForm1() { Page.Init += new System.EventHandler(Page_Init); } private void Page_Load(object sender, System.EventArgs e) { // Setze Benutzercode, um die Seite zu initialisieren
Einen Webservice mit Visual Studio.NET erstellen 21 } private void Page_Init(object sender, EventArgs e) { // //CODEGEN: Dieser Aufruf ist für den ASP.NETWebdienst-Designer erforderlich. InitializeComponent(); } #region Web Form Designer generated code /// /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem CodeEditor geändert werden. /// private void InitializeComponent() { this.Populate.Click += new System.EventHandler(this.Populate_Click); this.RunSql.Click += new System.EventHandler(this.RunSql_Click); this.Load += new System.EventHandler(this.Page_Load); } #endregion private void Populate_Click(object sender, System.EventArgs e) { DataSet ds = new DataSet(); String s = DropDownList1.SelectedItem.ToString(); ds = mydbService.Populate(s); DataGrid1.DataSource=ds; DataGrid1.DataBind(); } private void RunSql_Click(object sender, System.EventArgs e) { string s;
445
ASP.NET 446
21 String ret; s = "Delete from pub_info where pub_id = '9999'"; ret=mydbService.RunSQL(s); messages.Text = ret; //erzeugt eine Zufallszahl Random r = new Random(); s = " insert into pub_info(pub_id,pr_info) values("; s = s + " '9999','" + r.Next(1000).ToString() + "')"; ret=mydbService.RunSQL(s); messages.Text = ret;
//Aktualisiere das DataGrid, um die Änderungen anzuzeigen DataSet ds = new DataSet(); s = "Select * from pub_info where pub_id = '9999'"; ds = mydbService.Populate(s); DataGrid1.DataSource=ds; DataGrid1.DataBind(); } } }
Webservices mit Visual Studio.NET zu erstellen ist ziemlich einfach. Die verfügbaren Assistenten und Tools machen die Aufgabe der Positionierung der Komponenten zu einer Kleinigkeit. Der generierte Code ist kompakt und präzise und ich mag diesen Aspekt sehr. Ein großes Problem der früheren MicrosoftTools wie Visual InterDev war, dass sie jede Menge zusätzlich benötigte Dateien erstellten. Das ist in Visual Studio.NET nicht der Fall. Es ist stets möglich, die Dateien auch in einem TextEditor zu öffnen, um an ihnen weiterzuarbeiten.
Projekt 2 – Zusammenfassung In diesem Teil haben Sie die Möglichkeiten von Visual Studio.NET für das Rapid Application Development (RAD) kennen gelernt. Sie haben mit verschiedenen Tools, Designern und
Einen Webservice mit Visual Studio.NET erstellen 21 Komponenten dieser Umgebung experimentiert und auch eine Datenbank und eine Webservice-Applikation mit dieser Entwicklungsumgebung erzeugt. Als ein RAD-Tool ist Visual Studio.NET sehr zu empfehlen. Seine integrierte Entwicklungsumgebung ermöglicht Ihnen, mit mehreren Sprachen zu arbeiten, und hat auch einen wunderbaren Debugger. Visual Studio.NET hat seine graphische Benutzerschnittstelle von früheren Microsoft-Produkten wie Visual InterDev und Visual Basic 6x geerbt. Ein großes Problem, das man bei Visual InterDev hatte, war, dass es hinter dem Rücken einige wichtige Dateien erstellte. Erfahrene Programmierer scheuten davor zurück, dieses Programm zu benutzen, und bevorzugten lieber einfache Text-Editoren. Sie können jedoch erleichtert aufatmen, denn dies ist jetzt in Visual Studio.NET nicht mehr der Fall. Der generierte Code ist elegant und präzise und in den meisten Fällen dem ziemlich ähnlich, was Sie von Hand programmieren würden. Sie können dasselbe Tool benutzen, um in den Programmiersprachen C#, VB.NET und ASP.NET zu programmieren, und müssen keine neue Arbeitsumgebung kennen lernen. Zusammenfassend möchte ich sagen, dass dies eine schöne Entwicklungsumgebung ist, die zu besserer Entwicklungsproduktivität führen kann.
447
Stichwortverzeichnis 449
Stichwortverzeichnis Symbols #endregion 396 #region 396
A Abbruch 278 Abfrage-Generator 393 Abfragen 87, 181 Abfrage-String 178 Abfragetypoptionen 391 Abhängigkeit 309 Abkürzung 166 Ablauf 253 Absturz 193 Abwärts-Kompatibilität 38 Action Query 432 Add LinkButton 424 Add_Click Event 424 AddButton 197 AddCode_Display 419 Addition 262 AddOpening 419 AddPanel 418 AddRate 419 AddUom 419 ADO 399 AdRotators 18, 55 Aktions-Abfragen 86 Aktions-Anfragen 72, 222 Aktualisieren 63, 412 Aktualisierung 23, 105, 149, 174, 306, 312 Algorythmen 325 als Startprojekt festlegen 438 als Startseite festlegen 395, 433 Anbindung 75 Änderungen 68, 111, 196 Anfragen 132, 244, 298 Ansicht 333 Antwort 245, 248 Anwendungen 60, 96, 168, 220, 260, 272, 292, 337
Anwendungsobjekt 280 Anwendungsordner 246, 252 Anwendungsvariable 280 Anwendungsverzeichnis 318 Anzahl 97 Anzeige 179 Anzeigearten 148 ApplicationEnd 429 ApplicationStart 429 Arbeitsprozess 301 Arbeitsschritte 179 Arbeitsweisen 220 Argumente 124 ASP.NET 379, 447 Assistenten 384, 403, 446 Attribute 158, 167, 239, 246, 298 Aufbau 184, 304 Auffrischung 101 Auffüllungsprozess 79 Auflistung 160 Aufruf 156, 245, 268 Aufrufen 433 Ausdruck 144 Ausfall 290 Ausführen 185, 196, 263 Ausführung 70, 79, 111 Ausrichtung 47 Auswahl 59 Auswahlkriterium 80 Auswahlmöglichkeiten 47 Authentizierung 22, 322, 335 Auto-Complete Funktion 412 AutoGenerateColumns 417, 418 autom. Formatierung 439 AutoPostback 97 Autorisierung 322 Autorisierungsbereich 327 Autorisierungscodes 18 Autovervollständigung 425
B Bannerwerbungen 54 Basis 336
Bearbeiten 412 Bearbeitung 297, 299 Befehl 68, 72 Befehls-Syntax 76 Befehlszeilen 286 Befehlszeilen-Utility 249 Begrenzungen 63 Begriffsinhalte 144 Beispiel-Anwendung 276 Beispiel-Webformular 246 Benutzer 30, 55, 86, 97, 141, 190, 295, 329 Benutzer-Eingabeformular 179 Benutzereingaben 325 Benutzerkontrolle 19, 152 Benutzername 329 Benutzeroberflächen 33, 165 Benutzerschnittstellen 341, 378, 406 Benutzersteuerung 352 Berechtigungsnachweise 325 Bereiche 258, 291, 317, 325 Beschränkungen 152 Beschreibung 192, 249 Bestimmung 285 Betriebssysteme 238, 268 Bewertung 90 Bezeichnung 298 Beziehungen 88 Bild 51, 52 Bildschirm 199 Bind Methode 402 Bind() Methode 420 binden 402 Bindung 94, 221, 222 Bookmarks 334 Boolean 238 Boolean-Wert 330 BorderColor 353 Bound-Kontrolle 69 Browser 37, 60, 148, 168, 262, 292, 312, 378, 388 Browser-Erkennung 37, 42 Buchhaltungsformular 357
ASP.NET 450 Business Logic 20 Business-Objekte 21, 214 ButtonColumn 413 Buttons 115, 197, 258, 290 Button-Spalte 132
C C# 379, 384, 406, 428, 447 Cache-Speicher 306 Cache-Speicherung 21 Caching 304 Calendar-Kontrolle 56 CellPadding 353 Checkboxen 43, 47 Click-Events 349, 441 Client 248 Client Applikation 436 Client/Server-Anwendungen 16 Client-Funktion 146 Client-Verbindungen 62 closing 412 Code 16, 60, 80, 101, 110, 184, 242, 331 Code Behind 17, 118, 361, 387, 396, 407, 414 Code Behind-Datei 34 Code Behind-Formular 369 code_display 415 Code-Datei 185 Code-Liste 207, 267 Code-Wert 176 Codierung 297 Command-Objekte 69, 77, 398, 399 Commands 399 CommandText property 399 Connection 390 Connection property 399 Connection String 349, 359, 361, 367, 396 connStr Feld 431 Constructor 219 Control 431 ControlToValidate 144 Cookie 283, 328 Cookieless 291
CreateChildControls 191 CRUD 382, 406, 425 CSharpdbService 436, 439 CSharpdbService.vsdisco 429
D DataAdapter 389, 399, 400 DataAdapter-Objekt 65 DataColumns 183 DataGrid 71, 164, 358, 367, 374, 399, 402, 417, 428 DataGrid-Funktionalität 19 DataKey 422 DataKeyField 410 DataList 43, 353 DataMember 410 DataReader 64, 88 DataRepeater 97 DataSet 19, 63, 126, 306, 402 generieren 400, 409 DataSet zu Designer hinzufügen 409 DataSource 410 DataView 374 Dateien 63, 152 Dateizugang 253 Daten 94 Datenansichten 80, 83, 181, 228, 281 Datenbank Explorer 395 Datenbankanwendungen 406 Datenbanken 18, 23, 25, 63, 69, 228, 289 Datenbankinteraktion 350, 366, 383, 389, 406 Datenbank-Klasse 223 Datenbankschema 384 Datenbanktabelle 358, 366 Datenbankverbindung 171 DatenbankverbindungsString 221 Datenbearbeitung 62 Datenbehälter 124 Datenbindung 37, 91 Dateneditierung 101 Datenfüllung 75 Datengitter 207
Datenkomponenten 408 Datenkorruption 279 Datenliste 119, 124, 312 Datenmodell 62 Daten-Navigationsfunktionen 54 Datenquelle 36, 48, 62, 64 Datenreihe 181 Datensätze 71, 116, 264, 375 DatenSet 384, 400 Datenspalten 181 Datenstrom 86 Datentabelle 81, 84, 191 Datenüberprüfung 323 Datenübertragungsprotokoll 21 Datenvalidierung 325 Datenverbindung 391 Datenverknüpfungseigenschaftenseite 391 Datum 58 dbService 430 dbService.asmx 430, 433 Deaktivierung 149 Debugger 252, 447 Definitionen 190, 220, 241 Deinstallation 289 Deklaration 75, 354 delete 392 Demonstration 317 Design 338, 387 Designer 401 Detail-Datensätze 132 Details 126, 214 Dialogbox 253 Direktive 149, 305 Display 193 Dokument-Eigenschaftenseiten 439 Domain 268 Drag & Drop 28, 382 DropDown-Liste 94, 358, 367 dsStock 409
E Edit LinkButton 420 EditCommandColumn Tag 413
Stichwortverzeichnis 451 Editier-Modus 105, 124, 172 EditItemIndex 422, 424 EditItemTemplates 414, 415 Editor 172 Eigenschaften 46, 54, 68, 94, 104, 154, 170, 223, 252, 333, 396 Eigenschaften-Fenster 388 Eigenschaftengenerator 411 Eigenschaftsblock 154 Eigenschafts-Markierungen 104 Eigenschafts-Syntax 216 Eigenschafts-Werte 31, 36, 58 Einbindung 18 Eingabe 42, 79, 144, 147, 177, 288 Eingabefelder 137, 196 Eingabeformular 172 Eingabekontrolle 246 Eingabemodus 172 Eingabeparameter 76, 245 Eingabeüberprüfung 136 Eingabewerte 136, 175 Eingrenzungen 90 Einheit 215 Einschränkung 164, 280 Einstellungen 284 Einstellungsmöglichkeiten 300 Eintrag 318 Elemente 83, 247, 325 Element-Markierungen 241 Empfangen 247 Entwickler 42, 63, 295 Entwicklung 164, 233, 236, 250 Entwicklungsschritte 165 Entwicklungstools 382 Entwicklungsumgebung 382 Entwurf 387 Entwurfsmodus 409 Ergebnisse 71, 77, 239, 249, 260, 266, 317 Ergebnistabelle 315 Erinnerung 305 Erläuterungen 207, 292 Eröffnungs-Tabelle 85 Erstellung 179, 221, 248, 258 Erweiterungen 28, 146, 238, 249, 294 Event 59, 114, 329
Event-Handler 198 Event-Sequenz 277 ExecuteScaler 72 Extrahierung 112
Funktionalität 21, 42, 51, 146, 168, 226 Funktionen 214, 237 Fußzeilen 120
F
G
Fähigkeiten 240 Farbe 158 Farbe und Ränder 406, 439 Feedback 137 Fehler 143, 148, 256, 296 Fehler String 361, 369 Fehlerbehebungsprogramm 256 Fehlerbereich 295 Fehlermeldung 141, 317, 335 Fehlernummern 296 Fehlerseite 295 Fehlfunktion 284 Feineinstellung 94 Feldnamen 164 Feldsammlung 175 Fernabfragen 295 Fern-Prozeduraufruf 242 Filestream 126 Fill-Funktion 65 Filter 81 Filtern 90 Finanzbuchhalter 341 Finanzbuchhaltungsmanager 358, 366 Finanzbuchhaltungsprogramm 378 Finanzbuchhaltungssoftware 340 FindControl 415 FindControl Methode 422 Firewall-Programme 64 Flexibilität 337 Formular 28, 65, 105, 329 Formularmarkierungen 157 Framework 298 Freeware 171 friendly names 400 Funktion 20, 115, 147, 148, 222, 359, 360, 369
Gebrauch 252 Gebühren 334 GenEditAdd-Kontrolle 184 Genehmigungen 323 Generierung 197 generische DatenbankZugriffsdienste 341 generisches DatenbankObjekt 344 Gitter 76, 101 Gleichordnungskontrolle 111 Global.asax 429 GridLayout 438 GridLines 353 Grundanforderungen 83 Grundansicht 81 Grundeinstellung 70, 148, 284 Grundelement 241 Gruppen 336
H Hauptdatei 156 Hauptfunktionalität 34 Haupttabelle 65 Hauptteil 195, 318 HeaderStyle 104 Hintergrund 100 Hintergrundfarbe 406, 439 Hinzufügen 112, 318, 412 Hotmail-Account 334 HTML Ansicht 410, 416 HTML-Elemente 28 HTML-Kontrollen 17, 33 HTML-Vorzeichen 40 http Protokoll 340 HTTP Unterstützung 16 Hyperlink-Kontrolle 159 Hyperlinks 51, 179, 249, 412 Hyperlink-Spalten 207
ASP.NET 452
I ID 415 id 36 Identität 215, 322, 327 IIS 346 Implementierung 112, 132, 283 Import-Funktion 33 Index 111 Informationen 291, 308, 318 Inhalt 275 Inhärenz 166 Initialisierung 36 InitializeComponent() 398 Methode 441 Initiierung 223 Input-Kontrollen 42 insert 392 Installation 24 Instanz 299 Interaktion 66, 199 Interface 299 Internet 340, 379 Internet Service Manager 272 Internet-Einstellungen 268 Internet-Sitzung 278 Intervention 308, 312 ItemTemplate 415
J Java-Applets 164 JIT-Compiler 29
K Kalender 56 Kategorien 315 Klasse 36, 216, 389 Klassenansicht 403 Klassenname 389 Klassifizierung 237 Klassisch 2 410, 439 Kombination 337 Kommunikation 236, 242, 266 Kompatibilität 275 Kompilieren 249 Kompilier-Sprache 239
Kompilierung 225, 294 Komponenten 154, 214, 217, 280, 311, 389 Komponenten-Registrierung 20 Konfiguration 284, 300 Konfigurationsdatei 207, 291, 335 Konfigurations-Formular 176 Konstruktion 304 Konstruktorname 389 Konstruktur 389 Kontrollen 35, 60, 94, 173, 258, 324 Konzepte 237, 275, 302 Kopfzeile 120, 247 Kosten 286, 304
Meldung 260, 300, 312 Metadaten 168 Methoden 70, 314, 326, 358, 389, 420 Methoden-Signatur 240 Microsoft Access 393 Microsoft Data Engine 24 Microsofts SQL Server Datenbank 430 Modifizierungen 174 Modus 182, 198, 286 Muster 145 Muster-Aufruf 244
N
Label 192 Label Control 415, 438 Laden 97 Layout 97, 143 Leerlaufzeit 301 Leistung 286, 287 Leistungsfähigkeit 305 Lesen 259 Link 51, 105 LinkButton Control 414 Liste 97, 318 Listenkontrollen 17, 125 LiteralControl 192 localhost 440 Logik 198 Login-Formular 327 Löschen 412 Lösungen 256, 284, 314
Nachteile 30 Namen 307 Namensfelder 32, 36, 155, 171, 190, 239, 273 namespace 166, 346, 387, 388, 430 Navigation 88 Navigationskontrolle 23 Navigationsleiste 312 Navigationslinks 352 Navigationsstruktur 156, 308 Navigationssystem 351 Netzwerkinfrastruktur 378 Netzwerkprotokoll 237 Neubindungs-Funktion 115 neue gespeicherte Prozeduren erstellen 392 new 398 Notepad 165 NULL code_value 424 Null-Wert 175 Nutzung 220
M
O
Manipulation 216, 233 Markierung 85, 100 Markierungszeichen 42, 192 Maschinensprache 29 Master-Reihen 126 Masters-Tabelle 178 Mehrfachauswahl 49, 50
Objekte 120, 132, 136, 216, 272 OleDb Managed Provider 430 OnCancelCommand 419 OnDeleteCommand 419 OnEditCommand 419 OnServerValidate 147 OnUpdateCommand 419
L
Stichwortverzeichnis 453 opening 415 Operatoren 142 Option 293, 307 Ordner 273 Organisation 214 Organisierung 111
P p_stock_master 424 Page_Layout Attribut 438 Panel 52 Panel-Markierung 54 Parameter 68, 70, 80, 148, 256, 266, 389 Parameter Collection 399 Parameter-Sammlung 76 Passport 334 Passport-Registrierung 335 Passwörter 141, 324 Passwort-Sammlung 323 Passwort-String 326 Pfad 33, 298, 318 Platzhalter 124 Populate 232, 359, 367, 375, 428, 431, 442 populate 400 Ports 241, 285 Position 193, 241 Positionierung 446 Präsentation 32, 233, 263 Präsentations-Elemente 220 Präsentationslogik 16 Primärschlüssel 422 Primärschlüsselspalte 412 Problem 268, 284 Produktionsseiten 324 Programm 314 Programmieren 281 Programmierung 136, 146, 218 Programmierzeilen 22, 113 Programmzeilen 319 Projekt 214, 253 Projektmappen 384, 429 Projektmappen Explorer 386, 401 Projektnamen 258, 388 protected 401
Protokolle 64, 240, 242 Provider 64, 322 Proxy 248, 346 Prozedur-Aufruf 174 Prozeduren 70, 76, 78, 223 Prozess 284 pubs Datenbank 391
Q Quellcode 165, 215 Quellcode-Editor 429 Quelldatei 165 Query Builder 393
R Radiobutton 47 Random-Klasse 443 rate 415 read_only 412 ReBind 358, 366, 374 Referenzen 34, 67 Referenz-Ordner 253 Regeln 243 Register 215, 336 Register-Direktive 153 Registerkarte 406 Registrierung 167, 214 Registry 167 Reihen 100, 333 RejectChanges-Methode 91 Relationen 19, 90 Release Candidate 436 Render-Funktion 166 Rendern 43, 98, 191 Required Field 141 Ressource 22, 300, 335, 337 Rich-Kontrollen 17 Rückmeldung 97 Rücksendung 138 RunSQL 349, 358, 359, 366, 422 RunSql Methode 428 RunSQL-Funktion 229, 350 Runtimemodul 298
S Saldenbilanz 374 Samples 24 SaveNew_Click Event 424 Schablonen 94, 115 Schleife 84, 90 Schlüssel 174, 193 Schlüssel-Feldname 178 Schlüsselwert 283 Schlüsselwörter 25, 34, 79, 113 Schreibsystem 297 Schreibweise 237 Scroll-Liste 49 SDK-Installation 24 Seiten-Direktive 177, 294 Seitenvariable 155 Seitenwechsel 100, 113 Sektion 293 select 392 Select * from authors 433 select * from Masters 349 SELECT SQL Abfragen 438 Senden 236, 247 Sequenz 145 Server 28, 50, 219, 248, 323 Server Control 344 Server-Explorer 395, 408 Server-Fehler 288 Server-Kontrollen 38, 65 Service1.asmx 429 Service1.asmx.cs 429 Services 166, 250 SessionState 287 Sicherheit 322 Sicherheits-Attribut 325 Sicherheitsbereich 323, 324, 337 Sicherheitsrisiko 137 Sicherung 279 Site Knoten 352 Site URL 352 Sitzung 280 Sitzungs-ID 291 Sitzungsinhalt 284 Sitzungsstatus 275 Skript 152, 266 Skript-Blöcke 29 Skript-Code 28, 32
ASP.NET 454 Skript-Sprache 31, 294 SOAP 21 Solution Explorer 386 Sortierung 115 Spalten 64, 84, 85, 97, 111, 315 Spalten automatisch zur Laufzeit erstellen 418 Spaltenlegenden 114 Spaltensammlung 182 Spaltenwert 86 Speicher 86, 287 Speichern 286, 290 Speichern des Kennworts zulassen 391 Speicherperiode 304 Speicherung 280, 307 Spezifikationen 243 Spezifizieren 295 Spezifizierung 94 Sprache 294 SQL Action Query 359, 368 SQL SELECT-Befehle 428 SQL-Anfragen 23, 69 SQL-Anweisungen generieren 392 SQL-Anweisungen verwenden 391 SQL-Benutzerabfragen 344 SqlClient 407 SQLConnection 390, 393, 394, 398 SqlDataAdapter 390, 393, 394, 398 SQL-Provider 67 SQLService 344, 358, 367, 374 SQL-String 76 SQL-Zeichenfolge 369 Standardkonstruktor 431 Start-Prozeduren 289 Startseite 36 StateBag 191 Statement 34, 97, 195, 221, 315 Status 29, 191, 273, 290 Status-Management 30, 195 Steuerung 354 stock_master 408 StockMaster.aspx 406 String 112, 158, 361
Strongly Typed DataSet 384, 400 Strukturen 31, 48, 236, 247, 309 Stylesheet 265 Sub-Element 292 Subfunktion 59 Suchanfrage 23 Suchen 297 Symbolleisten 341 Syntax 68, 169, 229 System 252 Systemadministrator 289
T Tabelle 47, 72, 88, 100, 177 Tabellen-Tabulator 98 TableMapping-Eigenschaften 400 Technologien 62, 238, 268 Template Columns 414 Test 173 Test-Funktion 217, 244 Testseite 256 TestService 239 Test-Webformular 194 Text 116 Text Attribut 422 Text Editor 446 TextBox 86, 141, 195, 415 TextBox Controls 418 Textdatei 152, 323 Text-Editor 24 Textfelder 46, 59 TextPad 25 Textwerte 36 Textzeile 152 TheClient 438 Theorie 211 Ticket 335 Toolbox 389, 409 Tools 171, 446 Trace-Funktion 314 Tracing 315 Transaktionsformular 365 Transfer-Mechanismen 248 Trigger 193 TypedDataSet 389, 397
TypedDataSet2.aspx 395 Typen-Bibliothek 239
U Übereinstimmung 145 Überlastung 301 Überprüfung 112, 137, 149, 322 Überprüfungsaufgaben 136 Überschriften 113 Übertragung 167, 280, 325 Übertragungs-Protokoll 247 Umbenennen 389 Unterbereich 294 Unterfunktionen 34 Unterstützung 239 uom 415 Update 124, 392 update()-Methode 400 Update-Funktion 68 Update-Modus 192 Ursprungs-Verzeichnis 314
V Validierung 137 Validierungs-Routinen 136 Variable 114, 158, 190, 221 VB 359, 368 VB Code Behind Formular 358 VB.NET 447 Veränderungen 283 Verbindung Testen 391 Verbindungen 67, 72, 126, 290 Verbindungs-String 179, 228 Vereinfachung 79 Verfeinerung 220 verfügbare Spalten 411 Verhaltensmuster 263 Verlässlichkeit 287 Verschlüsselung 325 Verschlüsselungsmethode 325 Verschwendung 308 Version 327 Verweis hinzufügen 440 Verwendung 70, 317 Verzeichnis 167, 272, 299, 331 Verzögerungen 276
Stichwortverzeichnis 455 Visible Attribut 424 Visual Basic.NET 379 Visual Studio.NET 382, 383, 427 Voreinstellung 301 vorhandene gespeicherte Prozeduren 392 Vorlagenspalten 414 Vorzeichen 196 Vorzüge 291 VSÜberblick 384, 397
W Web Services 341, 344, 358, 365, 367, 427 Web.config 429 Webanwendung 384, 386 WebControl-Basisklasse 42 Webdienst 430 Webdienst hinzufügen 430 WebForm1.aspx 386 Web-Formulare 17, 120, 171, 179, 281, 361, 388, 406, 417, 436
Web-Gärten 301 Web-Kontrollen 36 WebMethod 346, 431 Web-Programmierung 16 Webserver 440 Web-Service 20, 243, 267 Website 330 Webverweis 439 Weißbuch 334 Weitergabe 264 Werbesequenzen 54 Werbung 54 Werkzeug 262 Werte 111, 154, 184, 250, 288 Wertebereich 143 Windowsanwendung 382 WSDL-Vertrag 242 wwwroot 386
X XML 352, 353, 429 XML-Datei 55
Z Zeichen 193 Zeichenkombination 145 Zeitraum 304 Zeit-Stempel 307 Ziel-String 145 ZIP-Codes 144 Zufallszahl 443 Zugang 262, 322 Zugangspfad 38 Zugriff 86, 240, 300, 307 Zugriffs-Datenbank 331 Zuordnung 154 Zusammenfügung 168 Zusammensetzungen 215, 272, 294 Zuverlässigkeit 288 Zwischen-Code 179