Geschrieben von: Christoph Wille
Kategorie: Web Services
This printed page brought to you by AlphaSierraPapa
Wenn man Web Services in ASP.NET programmiert, dann bekommt man ein bequemes Feature frei Haus geliefert - man kann Session State verwenden, und zwar völlig gleich zu normalen ASP.NET Seiten. Nur ein einziges Attribut muß gesetzt werden, und schon kann man zB ein einfaches Loginsystem für Web Services basteln.
Bevor wir beginnen, möchte ich die "dunkle Seite" des Session State in ASP.NET Web Services beleuchten: wie üblich bedient sich der Session State entsprechender Cookies, die allerdings nicht alle Clients annehmen. Für eine leicht zu kontrollierende Lösung (=Intranet) ist dies kein Problem - soll der Web Service allerdings einer breiten Masse via dem Internet zugänglich gemacht werden, sollte man auf Session State verzichten - und sei es nur, um noch ein letztes Quentchen an Performance herauszuquetschen.
Um den heute vorgestellten Code ausführen zu können, muß ASP.NET am Server installiert sein. Für das Erstellen von Assemblies benötigt man das vollständige .NET SDK (nicht notwendigerweise am Server, allerdings auf der Maschine, auf der die Assembly kompiliert werden soll).
In der Einleitung habe ich davon gesprochen, daß wir nur ein einziges Attribut benötigen. Stimmt. Man muß nur EnableSession beim sowieso erforderlichen WebMethod Attribut hinzufügen, und schon kann man auf Session State vertrauen:
[ WebMethod(EnableSession=true) ]
Ich habe das natürlich gleich in ein einfaches, wenig anspruchvolles Beispiel gepackt: SimpleStateful.asmx. Dieser Web Service hat zwei Methoden, MethodA und MethodB. Wenn man MethodA mit einem String aufruft, wird dieser in einer Sessionvariable abgelegt, und kann durch Aufruf der Methode MethodB wieder ausgelesen werden:
<%@ WebService Language="C#" Class="SimpleState" %> using System; using System.Web.Services; public class SimpleState : WebService { [ WebMethod(EnableSession=true) ] public void MethodA(string strValue) { Session["SessionStateTest"] = strValue; } [ WebMethod(EnableSession=true) ] public string MethodB() { object objState = Session["SessionStateTest"]; if (null != objState) return (string)objState; return ""; } }
Die Verwendung von Session State unter ASP.NET funktioniert etwas anders als bisher gewohnt. Existiert eine Variable nämlich nicht, bekommt man eine null Referenz zurückgeliefert - und diese umzucasten und zu konvertieren wäre nicht klug (außer man liebt Exceptions). Deshalb der Check gegen null in der Funktion MethodB.
Daß das Arbeiten mit Session State funktioniert kann man im Browser versuchen - mittels der von ASP.NET vorgenerierten Seiten. Ich gehe aber sofort dazu über, mir einen Proxy zum Aufrufen des Web Services zu generieren.
Der Proxy wird wieder mit Hilfe des wsdl.exe Utility's erzeugt. Ich habe mir dazu die Batchdatei CreateProxy.bat angelegt:
Wsdl /language:cs /protocol:httpget /namespace:SimpleStateProxy /out:SimpleStateProxy.cs http://192.168.1.203/SessionStateServices/SimpleStateful.asmx
Im Vergleich zum Artikel Web Services in Anwendungen konsumieren habe ich hier das Protokoll verändert: von soap auf httpget. Sinn und Zweck der Übung ist eindeutig klarzustellen, daß wir hier keinen "korrekten" SOAP Web Service vor uns haben, sondern einen ASP.NET Web Service.
Übrigens gäbe es auch httppost als Protokoll. Die Extraerwähnung verdient es wegen der im Internet sehr häufig anzutreffenden Proxy Server: GET Requests können gecacht werden, POST hingegen nicht. Wer also die leidigen Caching Probleme ausschalten will, sollte sich für httppost entscheiden.
Die Proxyklasse hätten wir, sie muß nur noch kompiliert werden (Compile.bat):
csc.exe /target:library SimpleStateProxy.cs
Für die Verwendung in ASP.NET Seiten muß die erzeugte Assembly in das bin Verzeichnis der Applikation kopiert werden, für Windows Applikation in das Verzeichnis des Programms.
Im heutigen Download findet sich zwar auch ein Kommandozeilenbeispiel, allerdings gehe ich im Artikel nur die ASP.NET Lösung durch, die in CallService.aspx implementiert ist. Ich habe ein Web Form erstellt, das nur eine Schaltfläche beeinhaltet. Wenn man auf diese klickt, wird ein Event ausgelöst, und der Web Service aufgerufen:
<% @Import Namespace="SimpleStateProxy" %> <% @Import Namespace="System.Net" %> <script language="C#" runat="server"> void btnPress_Click(Object Sender, EventArgs E) { SimpleState myStateService = new SimpleState(); CookieContainer cc = new CookieContainer(); myStateService.CookieContainer = cc; myStateService.MethodA("This is the World @" + DateTime.Now.ToString()); lblOutput.Text = myStateService.MethodB(); } </script> <html> <body> <form runat="server"> <asp:Button id="btnPress" text="Test Service" onClick="btnPress_Click" runat="server" /> <p><asp:Label id="lblOutput" text="" runat="server" /></p> </form> </body> </html>
Das Ergebnis sieht dann im Browser so aus:
Allerdings würde die ganze Sache ohne den folgenden zwei Zeilen keinesfalls funktionieren:
CookieContainer cc = new CookieContainer(); myStateService.CookieContainer = cc;
Um Web Services mit Session State verwenden zu können, muß man einen CookieContainer instanzieren, und der CookieContainer Eigenschaft der Web Service Klasse zuweisen. Nur so kommt man in den Genuß von Session State. Sonst differiert der Aufruf der Web Service Funktionen nicht von einem, der keinen Session State verwendet.
In der Einleitung erwähnt, hier kommt es - eine Authentifizierung für Web Services. Besonders praktisch dann, wenn man nur bestimmten Benutzern die Verwendung des Web Services gestatten will - und nicht auf andere Authentifizierungsmethoden (zB Windows Authentication) ausweichen möchte.
Die Datei LoginSample.asmx zeigt, wie es ablaufen muß. Diese Datei ist nur ein "Skelett", in das Datenbankcode für die Benutzerkonten, sowie die eigentliche Funktionalität des Web Services eingefügt werden muß. Die Infrastruktur aber ist vorhanden und getestet:
<%@ WebService Language="C#" Class="LoginSample" %> using System; using System.Web.Services; public class LoginSample : WebService { [ WebMethod(EnableSession=true) ] public bool Login(string Username, string Password) { // replace with database code to your liking if ("user" == Username && "pwd" == Password) { Session["LoggedIn"] = true; return true; } else { Session["LoggedIn"] = false; } return false; } [ WebMethod(EnableSession=true) ] public bool IsUserLoggedIn() { object loggedIn = Session["LoggedIn"]; if (null != loggedIn) return (bool)loggedIn; return false; } }
Wer den oben gezeigten Code übrigens nicht jedes Mal eintippen oder kopieren will - er ist als C# und VB.NET Template in SharpDevelop mit dabei:
Session State kann in Intranetanwendungen sehr wohl praktikabel sein, da man ja out-of-process Session Stores verwenden kann. Für den Web Service, den man Kunden aus aller Welt und auf allen Plattformen anbieten möchte, sollte man aber zu anderen Methoden greifen, um Logins (oder State generell) zu managen.
This printed page brought to you by AlphaSierraPapa
Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20010627.zip
Web Projekte mit SharpDevelop erstellen
http:/www.aspheute.com/artikel/20010208.htm
Web Services 101 in ASP.NET
http:/www.aspheute.com/artikel/20010621.htm
Web Services in Anwendungen konsumieren
http:/www.aspheute.com/artikel/20010622.htm
DotNetGerman Diskussionslisten
http://www.dotnetgerman.com/
SharpDevelop
http://www.icsharpcode.net/opensource/sd/
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.