Peter Bucher - Mein Experiment, meine Spielereien, meine Welt...   ·   Stefan Falz   ·   Jürgen Gutsch   ·   Golo Roden   ·   ASP.NET Zone   ·   Microsoft ASP.NET
Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe
WerbeanzeigeApose

Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Einführung
Wenn per Browser eine Webseite abgerufen wird, sendet der Browser eine GET oder POST Anforderung an den Webserver zu einen bestimmten Identifier bzw. Adresse.
Der Webserver schickt dann - aufgrund der Infos die per Request hineingekommen sind - die entsprechenden Daten zurück.
Bei einer Webseite werden diese Daten im Textformat verschickt.
Der Contentype ist dann entweder text/html bei normalen Html Dokumenten oder application/xhtml+xml bei XHtml Dokumenten.

Sobald die Seite im Browser angekommen ist, geht der Parser den Text durch.
Falls es dort noch weitere verlinkte Dateien gibt (Html / Javascript- / CSS-Includes, Bilder) lädt der Browser die genannten Ressourcen nach (Auch per GET oder POST Anforderung an den Webserver) und stellt diese innerhalb der Webseite dar.

Es fällt aber auf, das diese Daten, bspw. ein Bild nicht direkt im Html Quellcode steht, wo also sind diese Daten und weshalb nicht im Code der Webseite?
Diese Daten befinden sich je nach Situation entweder im Arbeitsspeicher oder auf der Festplatte bei den temporären Internetdateien.
Diese Daten werden also getrennt gehalten. Das macht auch auf verschiedene Arten mehr als Sinn.

  1. Ist so der Quelltext übersichtlich und nicht durch irgendwelche binäre Zeichenfolgen verwüstet
  2. Werden diese externen Ressourcen je nach Einstellung im Browsercache gehalten und müssen nicht bei jeder Anforderung zusätzlich geladen werden
  3. Sind diese externen Daten auch phyisisch vom restlichen Code getrennt

Eine ASPX Seite ist nichts anderes als eine Textdatei mit einer speziellen Endung, trifft der Webserver auf diese Endung, wird die besagte Datei von der ASP.NET Engine verarbeitet.
Diese Engine macht aus der ASPX Seite, dem deklerativen Teil und etwaigen externen Ressourcen schlussendlich das Endergebnis, das der Webserver dann zum Browser sendet.

Was ist ein HttpHandler?
Ein Handler kann sich als Teil des Prozesses vorgestellt werden, der bei einem Request abgearbeitet wird.
Wenn ein Request eintrifft, wird anhand von Mappings entschieden, welcher Handler den Request abarbeitet.

In ASP.NET gibt es schon mehrere bestehende Handler, der bekannteste von ihnen ist der Page Handler der auf alle Dateianforderungen mit der Endung *.aspx reagiert.
Webservices *.asmx gehen auch durch einen spezifischen Handler. Sowie bspw. WebResource.axd.
Die Klasse "Page", die bzw. deren Ableitungen für jede ASPX Seite benutzt wird, stellt den oben genannten Handler dar.

Sie implementiert das Interface IHttpHandler:

public class Page : TemplateControl, IHttpHandler { }

Und was macht jetzt ein Handler?
Ein Handler bearbeitet einen Request der ihm zugeteilt wurde.
Bei einer Anforderung auf den Handler selbst (Handler.ashx) oder auf einen Pfad der auf den Handler gemappt ist.
Im Falle des HttpHandlers Klasse Page stellt dieser Handler ein Grundgerüst für Webseite bereit.

Und wieso noch mehr Handler?
Nicht jeder Request geht an eine Webseite, es gehen viele Requests an andere Median wie bspw. ein Bild.
Wenn ein Request auf eine Datei geht die auf dem Webserver liegt, wird diese vom Webserver direkt ausgeliefert.
Es gibt jedoch Situationen in denen bspw. Bilder dynamisch zum Client geschickt werden sollen.

Und genau für solche Situationen kann ein HttpHandler geschrieben werden.
Im Unterschied zum Page HttpHandler ist eine Klasse die nur IHttpHandler implenentiert nur ein Grundgerüst.

Ein einfacher HttpHandler

public class HelloWorld : IHttpHandler
{   public void ProcessRequest(HttpContext context) {
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }
        public bool IsReusable {
        get { return false; }
    }
}

Die Eigenschaft IsReusable gibt an ob der Handler für einen weiteren Request wiederverwendet werden soll.
In der Methode ProcessRequest wird - wie der Name sagt - der Prozess abgearbeitet.

Über das Argument context kann auf den aktuellen Request, Response, etc... zugegriffen werden.
Wie schon weiter oben geschrieben gibt es verschiedene Content Typen die dem Client mitteilen um welchen Typ Datei es sich handelt.
Mit context.Response.ContentType kann der gewünschte ContentType angegeben werden. Bei einem jpg Bild wäre das bspw. image/jpeg.
Eine Liste der häufigsten Content Typen stellt SelfHtml bereit.
Im nächsten Schritt erfolgt die Ausgabe per Response Objekt.
Bei Text wird die Methode .Write benutzt, bei einer binären Datei (zip, exe, dll) .WriteFile oder .BinaryWrite.

Wie wird ein HttpHandler aktiv?
Ein HttpHandler kann - sowie auch eine ASPX Datei - über seinen Dateipfad abgerufen werden.
Oder per Mapping auf einen bestimmten Pfad, Endung und Übertragungstyp (GET / POST) das bspw. in der web.config erstellt werden kann.

In unserem Beispiel sieht das Mapping in der web.config im <system.web> Zweig so aus:

<httpHandlers>

       <add verb="*" path="*.genial" type="HttpHandlerTest.Genial" />
</httpHandlers>

Wenn eine Ressource mit der Endung .genial angefragt wird, verarbeitet der Handler Genial den Request und gibt die Response zurück.
Im Beispiel machen wir nichts anderes als die Url abzufragen, zu splitten und eine formatierte Ausgabe der Url zu tätigen.

public class Genial : IHttpHandler
{   public void ProcessRequest(HttpContext context) {
        context.Response.ContentType = "text/plain";         string value = context.Request.Url.ToString().Split('/')[3];
        value = value.Replace(".", " ");
        context.Response.Write(value);
    }
     public bool IsReusable {
        get { return false; }
    }
}

Bei einer Eingabe der Url: http://localhost:<Port>/das.ist.genial kommt folgende Ausgabe zurück:

das ist genial

Ist es das nicht? :-)

Ein weiterer Anwendungsfall gefällig?
In einer Anwendung sollen Downloads zur Verfügung gestellt werden.
Dies sollte (vielfach leider nicht der Fall) mit einem HttpHandler erledigt werden.
Ein Link auf eine Datei könnte folgendermassen lauten: localhost/ImageHandler.ashx?path=images/meinBild.jpg

Das funktioniert zwar, sieht aber nicht wirklich schön aus.
Mit einem HttpHandler, dem entsprechendem Mapping und UrlRewrite könnte das so aussehen: localhost/download/meinBild.jpg

Ich beleuchte hier nur die Rolle des HttpHandlers.
Es besteht die HttpHandler Klasse "Download" die einen Download ausliefert und auf folgendes Mapping reagiert:

<add verb="*" path="/download/*" type="Knowledgebase.Download"/>

Der Handler reagiert auf alles was nach dem Pfad "/download/" folgt.
Also bspw. auf einen solchen Pfad: localhost/download/23_meineDatei.zip

Genauso ist es auch möglich einen "catch all" HttpHandler zu schreiben, der auf alle Anforderungen reagiert.
Das wäre bspw. eine Möglichkeit für einen Log-Handler.

Wie man sieht, gibt es viele Gründe die dafür sprechen HttpHandler zu verwenden sowie auch viele Einsatzzwecke.

Wieso sollte eine Datei oder ein Bild nicht per ASPX Seite versendet werden?
Es ist möglich Grafiken oder Dateien per ASPX Seite an den Client zu schicken, jedoch bringt das Nachteile und Fallstricke mit sich.
Der HttpHandler für die ASPX Seiten, also die Klasse Page stellt ein Grundgerüst zur Verfügung um eine Webseite zu rendern.
Auch wenn noch kein Inhalt auf der Webseite steht, wird ein Grundgerüst als Text zum Client geschickt.

Wenn jetzt also ein Bild zum Client geschickt werden soll, muss sichergestellt werden das wirklich auch nur das Bild geschickt wird.
Ansonsten kann es zu einem solchen ungemütlichen Gemisch beim Client kommen:

[...]
iQZ�RE!QZ�RE!QZ�RE4�(�S) �B(��L�4�LQEj�G��

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<A href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</A>">

<html xmlns="<A href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</A>" >
<head><title>
[...]

Um das zu verhindern muss ganz am Anfang ein Response.Clear() und am Ende ein Response.End() abgesetzt werden.
Der Code dazwischen ist der selbe wie auch bei einem normalen HttpHandler.
Eine ASPX Seite sollte aber als Prinzip nicht zum senden von etwas anderem als Webseiten "missbraucht" werden.

Und wie rufe ich jetzt ein Bild über einen HttpHandler ab?
Es besteht jetzt bspw. ein HttpHandler Namens "Thumbnail.ashx", über GET oder POST Parameter die einer Anfrage mitgegeben werden, gibt der Handler entsprechend ein Thumbnail Bild zurück.
Auf einer ASPX Seite wird ein Image Control oder ein normaler <img>-Tag mit der Adresse des Handlers (bspw. localhost/Thumbnail.ashx?image=me.jpg) ausgestattet.

Wenn die Seite im Browser geparst wird, wird die Information - also die binären Daten - vom Handler gelesen und auf der Seite dargestellt.
Das ganze findet in einem eigenen Request / Response statt und hat mit der Auslieferung der Webseite an sich nur indirekt zu tun.

Unterschiedliches Verhalten der Webserver im Bezug auf HttpHandler, oder: Hilfe! Mein HttpHandler wird nicht aufgerufen.
Beim IIS 5.0 / 5.1 / 6.0 wird nicht standardmässig jeder Request über die ASP.NET Engine abgehandelt,
das führt dann dazu, das der Handler ggf. nicht angesprungen wird.

Beim IIS 7 / WebDev Server ist das Verhalten genau anders rum, dort wird immer jeder request durch die ASP.NET Engine abgehandelt.

Entweder muss man eine schon auf die ASP.NET Engine registrierte Endung nehmen (aspx / ashx / axd), deine gewünschte Endung selber im IIS registrieren (Handler Mapping) oder aber eine Application Wildcard einrichten.
Mit einer Wildcard läuft jeder Request - wie standardmässig beim IIS7 - immer über die ASP.NET Engine.

Wie man eine Application Wildcard einrichtet ist der Dokumentation von urlrewritingnet  zu entnehmen:
http://www.urlrewriting.net/154/de/dokumentation.html

Ich hoffe mit diesem Artikel ein wenig Licht ins Dunkle gebracht zu haben und danke euch fürs lesen.
Natürlich freue ich mich über jeden einzelnen Kommentar!

Weiterführende Links:

Änderungen / Korrekturen:
22.07.09 - Besonderheiten der Webserver im Bezug auf HttpHandler hinzugefügt.

Veröffentlicht Dienstag, 20. November 2007 22:53 von Peter Bucher

Kommentare

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

hehe, sehr fein. cooler artikel, sieht sehr umfangreich aus, ich freu mich schon aufs wochenende, wenn ich zeit habe, ihn ausführlich zu lesen.

aber sag mal .. hatten wir nicht mal gesagt, dass der titel des blogbeitrags anders lauten sollte? :-)

http://ausfuehrliche.artikel.sind.gerade.in/ !!!

Dienstag, 20. November 2007 23:29 by jolli

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Guter Artikel, danke.

HttpHandler waren mit bisher immer zu aufwendig, ich habe einen Download meist wie hier beschrieben http://dotnet-snippets.de/dns/aspnet-eine-datei-zum-download-anbieten-SID519.aspx gelöst. Hat dies erhebliche Nachteile?

Gruss fabian

Mittwoch, 21. November 2007 09:12 by neves

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Hallo zusammen, danke für eure Kommentare!

@jolli

> aber sag mal .. hatten wir nicht mal gesagt, > dass der titel des blogbeitrags anders  lauten  sollte? :-)

Na sag mal, hab ich nicht schon genug Promotion gemacht? ;-)

Nein, ich wollte halt einen sprechenden Titel.

@neves

> Hat dies erhebliche Nachteile?

Auf den ersten Blick gibt es weniger Aufwand und sieht es einfacher aus als dafür einen HttpHandler zu benutzen.

Aber wenn du auf der einen Seite einen HttpHandler und auf der anderen eine ASPX Seite hast, ist es aufwändiger eine Datei mit einer ASPX Seite zu senden, da du die Response zuerst löschen und am Schluss noch abschliessen musst.

Im Prinzip reicht es, wenn du die Zeilen aus dem Snippet in die "ProcessRequest" Methode schreibst und über einen Parameter (handler.ashx?param=value) entscheidest, was heruntergeladen werden sollte.

Wichtig ist aber - wie im Artikel erwähnt - das du bei einer ASPX Seite einen Overhead mit sich bringt, wenn sie als HttpHandler "missbraucht" wird.

Bspw. werden alle Events im Page Lifecycle gefeuert und abgearbeitet, unabhängig davon ob du sie jetzt brauchst oder nicht.

Für grössere Anwendungen und viele Anfragen kann dies Performance kosten.

Mittwoch, 21. November 2007 10:19 by Peter Bucher

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Wow, cooler Artikel. Das kann ich sicher mal gut gebrauchen. Danke Peter!

Freitag, 23. November 2007 18:42 by thomas77

# HttpHandler der besonderen Art - Page Handler

HttpHandler wurden von mir hier im Blog schon einmal erläutert und ein zweites Mal aufgegriffen . Es

Montag, 4. Februar 2008 20:26 by Peter Bucher

# Eine einfache Bildergalerie mit ASP.NET

Für ein kleineres Projekt benötigte ich eine einfache Bildergalerie die ich hiermit kurz vorstellen möchte

Mittwoch, 23. April 2008 13:34 by Jürgen Gutsch

# Was ist eigentlich ASP.NET?

Nach dem letzten Treffen des .NET-Stammtisch Konstanz-Kreuzlingen standen Peter , Thomas Huber und ich

Freitag, 17. April 2009 14:27 by Jürgen Gutsch

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Ist es möglich in einem Image-Tag auf einen Handler zuverweisen, wenn der Handler in einer eigenen Klasse steht und keine .ashx Datei ist?

Dienstag, 6. Juli 2010 10:58 by NoGoQuest

# re: Daten mit ASP.NET zum Client schicken, oder: Wieso eigentlich HttpHandler?

Salute NoGoQuest

Ja, siehe den Teil unter "Ein weiterer Anwendungsfall gefällig?".

Du musst den Handler in der web.config unter einem Pfad bekannt machen. Da musst du eine Endung nehmen, die auf ASP.NET registriert ist.

Oder je nach Einstellung und Version des IIS gehen auch nur "virtuelle" Ordnernamen wie bspw. download/super-tool/.

Einbindung wie gewohnt:

<asp:Image ImageUrl="~/myImages.ashx/Image1" ....

HTH

Dienstag, 6. Juli 2010 12:49 by Peter Bucher
Anonyme Kommentare sind nicht zugelassen