<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BigBasti&#039;s Blog &#187; Programmierung</title>
	<atom:link href="http://blog.bigbasti.com/category/programmierung/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.bigbasti.com</link>
	<description>About Me &#38; my Digital Lifestyle</description>
	<lastBuildDate>Wed, 25 Jan 2012 12:31:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>ASP.NET MVC: HTML5 Elemente mit jQuery Fallback nutzen</title>
		<link>http://blog.bigbasti.com/asp-net-mvc-html5-elemente-mit-jquery-fallback-nutzen/</link>
		<comments>http://blog.bigbasti.com/asp-net-mvc-html5-elemente-mit-jquery-fallback-nutzen/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 09:47:45 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Workaround]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1955</guid>
		<description><![CDATA[Soo, nachdem ich die Überschrift mit all den hippen Begriffen vollgepackt habe die es in Sachen Web momentan so gibt möchte ich euch kurz erklären worum es in diesem Artikel gehen soll.

Ihr werdet sicher mitbekommen haben, dass HTML5 auf dem Vormarsch ist und auch wenn es immer noch nicht offiziell fertig ist findet man ...]]></description>
			<content:encoded><![CDATA[<p>Soo, nachdem ich die Überschrift mit all den hippen Begriffen vollgepackt habe die es in Sachen Web momentan so gibt möchte ich euch kurz erklären worum es in diesem Artikel gehen soll.</p>
<p>Ihr werdet sicher mitbekommen haben, dass HTML5 auf dem Vormarsch ist und auch wenn es immer noch nicht offiziell fertig ist findet man immer häufiger den HTML5-Header &lt;!DOCTYPE html&gt; auf diversen Seiten.</p>
<p>Eins der meiner Meinung nach nützlichsten Features die wir mit HTML5 erhalten sind die <a href="http://www.w3schools.com/html5/html5_form_input_types.asp" target="_blank">neuen Input-Typen</a>. Denn bisher hatten wir keine Wahl und mussten type="text" benutzen!</p>
<p>Die Eingabefelder vom Typ Text konnten natürlich alles enthalten, sind aber nicht gerade Benutzerfreundlich wenn man etwas komplexere Daten eingeben soll wie zum Beispiel ein Datum.</p>
<p>In HTML5 wurden deswegen spezifische Typen für solche immer wieder einkehrende Eingaben eingeführt. Eine von ihnen ist &amp;quot;Date&amp;quot;:</p>
<pre>
<pre class="brush: html; ">

Birthday: &lt;input type=&quot;date&quot; name=&quot;bday&quot; /&gt;
</pre>
</pre>
<p>Der große Vorteil hier ist, dass die Browser nun eine eigene Implementierung für diesen Typ von Eingabefeldern machen können. Falls der Browser nun also diesen neuen Eingabe Typ unterstützt blendet er automatisch einem (mehr oder weniger) schönen Date-Picker ein in dem man bequem das Datum wählen kann:</p>
<div class="wp-caption aligncenter" style="width: 510px"><a href="http://server.bigbasti.com/uploads/uploads/251212842982966.png "><img title="Browsersupport" src="http://server.bigbasti.com/uploads/uploads/251212842982966.png " alt="" width="500" height="300" /></a><p class="wp-caption-text">Ansicht des neuen Typen in verschiedenen Browsern</p></div>
<p>Ein weiterer großer Vorteil ist, dass auch die mobilen Browser wie z.B. auf dem iPhone diese neuen Elemente ebenfalls unterstützen und einen passenden Picker einblenden:</p>
<div class="wp-caption alignleft" style="width: 148px"><a href="http://server.bigbasti.com/uploads/uploads/2512128448977966.png "><img class="   " title="Date-Picker auf dem iPhone" src="http://server.bigbasti.com/uploads/uploads/2512128448977966.png " alt="" width="138" height="208" /></a><p class="wp-caption-text">Date-Picker auf dem iPhone</p></div>
<p>Wie ihr in dem ersten Screenshot sehen könnt unterstützt der FireFox (zumindest zum Zeitpunkt des Screenshots) den neuen Typ nicht. In diesem Fall blendet er ein gewöhnliches Textfeld ein wo wir nun gezwungen sind das Datum auf die gewohnte (unbequeme) Weise einzutragen.</p>
<p>Übrigens, ich glaube ich muss euch nicht sagen warum der Internet Explorer hier nicht mit aufgeführt ist oder? <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Und genau das ist das Problem um das es in diesem Blogpost geht. Wenn wir die tollen neuen Elemente nutzen gehen wir das Risiko ein, dass Nutzer die einen älteren Browser nutzen nicht in den Genuss einer bequemen Eingabe kommen.</p>
<div class="wp-caption alignright" style="width: 245px"><a href="http://jqueryui.com/demos/datepicker/"><img title="jQuery Date-Picker" src="http://server.bigbasti.com/uploads/uploads/251212852193838138.png " alt="" width="235" height="196" /></a><p class="wp-caption-text">jQuery Date-Picker</p></div>
<p>Wir könnten auch komplett auf das HTML5 Element verzichten und direkt alles mit jQuery machen, welches auch einen Date-Picker bietet, aber das ist auch nicht das gelbe vom Ei, denn dann wären die Mobilen Nutzer in Nachteil, da dort die Browser diese Elemente für gewöhnlich unterstützen und eine gewohnte Oberfläche für die Eingabe bieten.</p>
<p>Die Optimale Lösung ist offensichtlich eine Mischung beider Welten. Wenn der Benutzer die Seite mit einem kompatiblen Browser aufruft soll der Date-Picker des Browsers genutzt werden, wenn der Browser aber veraltet ist soll stattdessen der jQuery Fallback greifen und der JavaScript Date-Picker (siehe links) genutzt werden.</p>
<p>Zu unserem Glück macht uns ASP.NET MVC die Umsetzung dieses Plans sehr leicht, da es an den nötigen Stellen sehr einfach erweitert werden kann.</p>
<p>Schauen wir uns mal ein kleines Beispiel an. Wir haben eine Klasse Person, und wollen auch dessen Geburtstag speichern, hier wollen wir die tolle neue Funktionalität nutzen. Implementieren wir das Ganze jedoch erstmal wie gewohnt:</p>
<pre>
<pre class="brush: csharp; ">

    public class Person
    {
        public int ID { get; set; }
        public String Name { get; set; }
        public DateTime Geburtstag { get; set; }
    }
</pre>
</pre>
<p>Wenn wir die Model-Klasse haben können wir das MVC Scaffolding nutzen um für uns eine View zum Erstellen neuer Personen anzulegen:</p>
<div class="wp-caption aligncenter" style="width: 521px"><a href="http://server.bigbasti.com/uploads/uploads/25121296125932661.png "><img class=" " title="MVC Scaffolding kommt uns zu Hilfe" src="http://server.bigbasti.com/uploads/uploads/25121296125932661.png " alt="" width="511" height="504" /></a><p class="wp-caption-text">MVC Scaffolding kommt uns zu Hilfe</p></div>
<p>Schauen wir uns nun doch mal an was da für uns tolles generiert wurde:</p>
<pre>
<pre class="brush: html; ">

    &lt;div class=&quot;editor-field&quot;&gt;
        @Html.EditorFor(model =&gt; model.Geburtstag)
        @Html.ValidationMessageFor(model =&gt; model.Geburtstag)
    &lt;/div&gt;
</pre>
</pre>
<p>Auffällig hierbei ist, dass hier @Html.EditorFor genutzt wird und nicht etwa @Html.TextBoxFor! Der Hintergrund ist der, dass MVC bei der Generierung versuchen wird ein passendes Element für den angegebenen Datentyp (DateTime) zu bestimmen, aber da MVC standardmäßig nur den Typ Text kennt wird hier eigentlich immer ein Input-Element vom Typ text generiert.</p>
<p>Hier kommt uns die Erweiterbarkeit von MVC zu gute, denn wir können ganz einfach NuGet nutzen um uns die nötige Funktionalität zu verschaffen. Wir installieren das Packet MvcHtml5Templates.</p>
<div class="wp-caption aligncenter" style="width: 438px"><a href="http://server.bigbasti.com/uploads/uploads/251212929533298753.png "><img title="Installation über NuGet" src="http://server.bigbasti.com/uploads/uploads/251212929533298753.png " alt="" width="428" height="46" /></a><p class="wp-caption-text">Installation über NuGet</p></div>
<div class="wp-caption alignleft" style="width: 220px"><a href="http://server.bigbasti.com/uploads/uploads/25121293434438753.png "><img title="Neue Templates" src="http://server.bigbasti.com/uploads/uploads/25121293434438753.png " alt="" width="210" height="251" /></a><p class="wp-caption-text">Neue Templates</p></div>
<p>Nachdem NuGet alles erledigt hat werdet ihr feststellen, dass ihr ein paar neue Dateien in eurem Views/Shared Verzeichnis habt (siehe Bild links). Und wie ihr schon an dem Namen erkennen könnt sind das die neuen Input-Typen aus HTML5.</p>
<p>Diese Templates machen im Grunde nichts anderes als die MVC-Eigenen zu überschreiben und versehen die mit dem passendem Type-Attribut.</p>
<p>Hier sind euch keine Grenzen gesetzt ihr könnt natürlich auch eire eigenen Templates definieren mit euren eigenen Typen. (Auch wenn man das eher selten benötigt)</p>
<p>Das Tolle: mehr müssen wir nicht machen. MVC wird nun zur Laufzeit statt einem Text ein Date Input-Element für uns anlegen. Beachtet, dass das nur geht wenn wir in der View die allgemeine Funktion @Html.EditorFor nutzen und keinen Spezifischen Typ angeben.</p>
<p>Schauen wir mal in den Sourcecode der zur Laufzeit für das Geburtstagsfeld generiert wird:</p>
<pre>
<pre class="brush: html; ">

&lt;input class=&quot;text-box single-line&quot;
data-val=&quot;true&quot;
data-val-required=&quot;Das Feld &#039;Geburtstag&#039; ist erforderlich&quot;
id=&quot;Geburtstag&quot;
name=&quot;Geburtstag&quot;
type=&quot;datetime&quot;
value=&quot;&quot;; /&gt;
</pre>
</pre>
<p>Wie ihr seht wird nun der Korrekte Typ, nämlich datetime verwendet. Wenn wir die Seite nun also mit einem kompatiblen Browser aufrufen können wir ganz bequem das Datum wählen.</p>
<p>Leider ist der Opera Browser momentan wohl der einzige Desktop Browser der uns hier einen Benutzerfreundlichen Dialog einblendet (siehe erstes Bild oben), somit müssen wir dafür sorgen, dass die Benutzer mit anderen oder alten Browsern nicht benachteiligt werden.</p>
<div class="wp-caption alignleft" style="width: 248px"><a href="http://server.bigbasti.com/uploads/uploads/251212124663987.png "><img title="JavaScript Magie" src="http://server.bigbasti.com/uploads/uploads/251212124663987.png " alt="" width="238" height="272" /></a><p class="wp-caption-text">JavaScript Magie</p></div>
<p>Auch für diese Problematik bringt MVC bereits alles mit was nötig ist sie zu lösen. Werfen wir doch mal einen Blick in unseren Scripts Ordner finden wir alle nötigen jQuery und jQuery UI Skripte, dazu kommt noch die modernizr Bibliothek die uns auch zu Gute kommen wird.</p>
<p>Die jQuery Bibliotheken liefern und die nötige Funktionalität die wir benötigen um diesen hübschen Date-Picker einzublenden.</p>
<p>Die modernizr Bibliothek dagegen hilft uns herauszufinden ob der Browser, den der Benutzer momentan verwendet die gewünschten HTML5 Features unterstützt.</p>
<p>Nun müssen wir also bei unseren Formularen prüfen, ob der Browser die nötigen Funktionen kennt und bei Bedarf die jQuery Klassen einbinden. Das Ganze ist dank der Einfachheit von Modernizr und jQuery ziemlich simpel.</p>
<p>Wechseln wir zu unserer View und fügen die Referenzen auf die nötigen Skripte und CSS Dateien ein:</p>
<pre>
<pre class="brush: html; ">

&lt;script src=&quot;@Url.Content(&quot;~/Scripts/jquery-1.5.1.js&quot;)&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;@Url.Content(&quot;~/Scripts/jquery-ui-1.8.11.js&quot;)&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;@Url.Content(&quot;~/Scripts/modernizr-1.7.js&quot;)&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;link href=&quot;@Url.Content(&quot;~/Content/themes/base/jquery.ui.all.css&quot;)&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
</pre>
</pre>
<p>Unten in der View fügen wir nun eine Modernizr Abfrage ein und prüfen, ob der Browser das DateTime-Feld unterstützt, und wenn nicht lassen wir jQuery das Ganze für uns regeln:</p>
<pre>
<pre class="brush: html; ">

&lt;script type=&quot;text/javascript&quot;&gt;
    $(function () {
        if (!Modernizr.inputtypes.date) {
            $(&quot;input[type=&#039;datetime&#039;]&quot;).datepicker();
        }
    });
&lt;/script&gt;
</pre>
</pre>
<p>Mit dem Befehl $("input[type='datetime']").datepicker(); werden alle Input-Felder vom Typ DateTime durch den jQuery Picker ersetzt. Coole Sache!</p>
<div class="wp-caption alignleft" style="width: 293px"><a href="http://server.bigbasti.com/uploads/uploads/2512121394635647.png "><img src="http://server.bigbasti.com/uploads/uploads/2512121394635647.png " alt="Unser Browser kennt den Typ nicht :(" width="283" height="262" /></a><p class="wp-caption-text">Unser Browser kennt den Typ nicht <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p></div>
<p>Kleiner Hinweis am Rande: Das ist nicht wirklich best practice da die Skripte auch geladen werden wenn sie gar nicht benötigt werden (der Browser kennt das HTML5 Feld) ich habe das hier der Einfachheit geopfert.</p>
<p>Und das wars auch schon! Alle Browser die das Feld unterstützen blenden nun ihren Picker ein, ansonsten wird der jQuery Fallback genutzt.</p>
<p>Wir müssen uns auch nicht mit irgendwelchen UserAgent-Prüfungen herumschlagen und lassen das alles Modernizr erledigen, der das intern über JavaScript prüft und somit immer aktuell ist. Das heißt dass wenn irgendwann der IE plötzlich die neuen Typen kennt werden diese auch funktionieren!</p>
<p>Genauso könnt ihr auch bei all den anderen neuen HTML5 Typen vorgehen und euren Usern ein bestmögliches Bedienerlebnis bereiten <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p><a href="http://dotnet-kicks.de/kick/?url=http%3a%2f%2fblog.bigbasti.com%2fasp-net-mvc-html5-elemente-mit-jquery-fallback-nutzen%2f"><img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.bigbasti.com%2fasp-net-mvc-html5-elemente-mit-jquery-fallback-nutzen%2f" border="0" alt="kick it on dotnet-kicks.de" /></a></p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1955&amp;md5=6f4995620c5babc5f3ed2b2f69c89eaa" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/asp-net-mvc-html5-elemente-mit-jquery-fallback-nutzen/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Konsolenausgaben in einer WindowsForms Applikation</title>
		<link>http://blog.bigbasti.com/konsolenausgaben-in-einer-windowsforms-applikation/</link>
		<comments>http://blog.bigbasti.com/konsolenausgaben-in-einer-windowsforms-applikation/#comments</comments>
		<pubDate>Tue, 17 Jan 2012 12:14:03 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Gut zu Wissen]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Visual Basic]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1948</guid>
		<description><![CDATA[Manchmal will man eine WindowsForms Anwendung auch über die Konsole aufrufen und dann möchte man natürlich auch Ausgaben der Anwendung in dem Konsolenfesnter sehen. Doch leider ist das nicht so einfach, da alle Aufrufe über die Console-Klasse werden ignoriert.

Doch warum ist das so? Das ist ganz einfach und liegt daran, dass das Konsolenfenster, das ...]]></description>
			<content:encoded><![CDATA[<p>Manchmal will man eine WindowsForms Anwendung auch über die Konsole aufrufen und dann möchte man natürlich auch Ausgaben der Anwendung in dem Konsolenfesnter sehen. Doch leider ist das nicht so einfach, da alle Aufrufe über die Console-Klasse werden <em>ignoriert</em>.</p>
<p>Doch warum ist das so? Das ist ganz einfach und liegt daran, dass das Konsolenfenster, das unser Programm startet zu einem anderem Prozess gehört, nämlich cmd.exe und somit nicht verbunden ist.</p>
<p>Was wir also tun müssen ist, unsere Ausgabe an das Konsolenfenster zu <em>heften,</em> das unsere Anwendung gestartet hat. Dafür kann man die Win32-Methode <a href="http://msdn2.microsoft.com/en-us/library/ms681952.aspx" target="_blank">AttachConsole</a> nutzen.</p>
<p>Diese ist sehr einfach aufgebaut und sollte vor der ersten Ausgabe an die Konsole aufgerufen werden:</p>
<p>Definition des Win32-Aufrufs: (Beispiele in VB.NET)</p>
<pre>
<pre class="brush: csharp; ">

    &lt;DllImport(&quot;kernel32.dll&quot;)&gt; _
    Private Shared Function AttachConsole(dwProcessId As Integer) As Boolean
    End Function
</pre>
</pre>
<p>Um die Ausgabe an den Prozess zu geben der uns aufgerufen hat (Parent-Process) kann man hier als Wert -1 übergeben:</p>
<pre>
<pre class="brush: csharp; ">

    Private Const ATTACH_PARENT_PROCESS As Integer = -1
</pre>
</pre>
<p>Was nun noch bleibt ist es die Methode aufzurufen, zum Beispiel in der Main-Methode der Applikation:</p>
<pre>
<pre class="brush: csharp; ">

    Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AttachConsole(ATTACH_PARENT_PROCESS)
        //[...]
</pre>
</pre>
<p>Das wars auch schon, nun werden eure Ausgaben an das Konsolenfester umgeleitet. Um die Konsole wieder von eurem Prozess zu lösen kann die paremeterlose Methode <a title="MSDN" href="http://msdn.microsoft.com/en-us/library/ms683150.aspx" target="_blank">FreeConsole</a> genutzt werden.</p>
<p>Es lohnt sich hier natürlich dann auch eine Unterscheidung zu machen wie die App gestartet wurde, also ob über Konsole oder über Doppelklick wie immer. Wenn sie über die Konsole gestartet wird, sollte man vielleicht die Oberfläche nicht mehr anzeigen. Das kann man dann zB. daran erkennen, dass Environment.GetCommandLineArgs.Length &gt; 1 ist.</p>
<p><strong>Probleme</strong></p>
<p>Leider gibts ein paar Nebeneffekte die nicht unbeachtlich sind.</p>
<p>Ein Problem ist, dass Konsolenfuntionen die die Ausgabe von Programmen umleiten zB. so: "myapp.exe -test &gt;test.txt" nicht funktionieren, die Ausgabe erfolgt weiterhin auf der Konsole. Hierfür konnte ich leider keine Lösung finden, wenn euch was einfällt einfach kommentieren.</p>
<p>Das zweite ist nur eine Schönheitssache, nämlich wenn das Programm beendet wird wird erst nicht die gewohnte Konsoleneingabezeile angezeigt, sondern nur der blinkende Cursor, so dass es aussieht als ob das Programm noch laufen würde, was es aber nicht mehr tut. (Wie gesagt Schönheitssache) Das kann man zB. dadurch umgehen, dass man vor dem Beenden des Programms noch ein [Enter] auf der Konsole ausgibt.</p>
<p>Weitere Infos und auch eine kleine Diskussion gibts <a href="http://www.csharp411.com/console-output-from-winforms-application/" target="_blank">hier</a> und <a href="http://benincampus.blogspot.com/2011/03/re-console-output-from-winforms.html" target="_blank">hier</a>.</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1948&amp;md5=654870545eed283ba93898fbcfb9fb64" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/konsolenausgaben-in-einer-windowsforms-applikation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC: Zugriff auf Dateien einschraenken</title>
		<link>http://blog.bigbasti.com/asp-net-mvc-zugriff-auf-dateien-einschraenken/</link>
		<comments>http://blog.bigbasti.com/asp-net-mvc-zugriff-auf-dateien-einschraenken/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 18:45:08 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1935</guid>
		<description><![CDATA[Oft kommt es vor dass man bestimmte Inhalte nicht der breiten Öffentlichkeit präsentieren möchte. So will man beispielsweise bestimmte Inhalte nur autorisierten Benutzern oder nur Admins zur Verfügung stellen, andere User die nicht eingeloggt sind sollen diese Inhalte nicht abrufen können. Ein weiterer Anwendungsfall wäre auch hotlinking zu verhindern.

Dieses Verhalten kann man in ASP.NET ...]]></description>
			<content:encoded><![CDATA[<p>Oft kommt es vor dass man bestimmte Inhalte nicht der breiten Öffentlichkeit präsentieren möchte. So will man beispielsweise bestimmte Inhalte nur autorisierten Benutzern oder nur Admins zur Verfügung stellen, andere User die nicht eingeloggt sind sollen diese Inhalte nicht abrufen können. Ein weiterer Anwendungsfall wäre auch <a href="http://de.wikipedia.org/wiki/Hotlinking" target="_blank">hotlinking</a> zu verhindern.</p>
<p>Dieses Verhalten kann man in ASP.NET MVC über verschiedene Wege erreichen. Eine beliebte Möglichkeit ist es</p>
<p><strong>die Dateien über einen Controller zu verteilen.</strong></p>
<p>Hierbei erstellt man einen Controller der eine Action hat in der die gewünschte Datei geladen und an den Browser zurückgegeben wird. Hier hat man dann die Bequemlichkeit, dass man problemlos prüfen kann ob der User eingeloggt ist und über die nötigen Rechte für das Bild verfügt. Das geht zum Beispiel mit dem Authorized-Attribut für die Actions.</p>
<p>Implementiert würde so eine Action dann wohl ca so aussehen:</p>
<pre>
<pre class="brush: csharp; ">

public ActionResult Image(string id)
{
    var dir = Server.MapPath(&quot;/Private/Images&quot;);
    var path = Path.Combine(dir, id + &quot;.jpg&quot;);
    return base.File(path, &quot;image/jpeg&quot;);
}
</pre>
</pre>
<p>Das Bild kann man dann so abrufen:</p>
<pre>
<pre class="brush: html; ">

&lt;img src=&quot;@Html.Content(&quot;~/Content/Image/&quot; + model.pictureID)&quot; /&gt;
</pre>
</pre>
<p>Dieser Ansatz funktioniert problemlos hat aber den kleinen Nachteil, dass er nicht so performant ist wie der direkte Zugriff auf die Ressource.</p>
<p>Eine weitere (und auch meine bevorzugte) Möglichkeit eine solche Zugriffskontrolle zu implementieren ist es durch</p>
<p><strong>einen eigenen RouteHandler.</strong></p>
<p>Eine Beispielimplementierung wie man auf diese Weise Hotlinking verhindern kann habe ich in <a href="http://www.mikesdotnetting.com/Article/126/ASP.NET-MVC-Prevent-Image-Leeching-with-a-Custom-RouteHandler" target="_blank">Mike Brinds Blog</a> gefunden.</p>
<p>Hier sind im Grunde drei kleine Schritte nötig um einen eigenen RouteHandler zum Laufen zu bekommen. (Code von Mikes Blog)</p>
<p>Zunächst müssen wir die RouteHandler Klasse anlegen, die das IRouteHandler Interface und dessen einzige Methode GetHttpHandler implementiert:</p>
<pre>
<pre class="brush: csharp; ">

public class ImageRouteHandler : IRouteHandler
{
  public IHttpHandler GetHttpHandler(RequestContext requestContext)
  {
    return new ImageHandler(requestContext);
  }
}
</pre>
</pre>
<p>Als nächstes erstellen wir die oben genutzte ImageHandler Klasse in der wir das das IHttpHandler Interface implementieren:</p>
<pre>
<pre class="brush: csharp; ">

public class ImageHandler : IHttpHandler
{
  public ImageHandler(RequestContext context)
  {
    ProcessRequest(context);
  }

  private static void ProcessRequest(RequestContext requestContext)
  {
    var response = requestContext.HttpContext.Response;
    var request = requestContext.HttpContext.Request;
    var server = requestContext.HttpContext.Server;

    var validRequestFile = requestContext.RouteData.Values[&quot;filename&quot;].ToString();
    const string invalidRequestFile = &quot;thief.gif&quot;;
    var path = server.MapPath(&quot;~/graphics/&quot;);

    response.Clear();
    response.ContentType = GetContentType(request.Url.ToString());

    if (request.ServerVariables[&quot;HTTP_REFERER&quot;] != null &amp;&amp;
        request.ServerVariables[&quot;HTTP_REFERER&quot;].Contains(&quot;yourdomain.com&quot;))
    {
      response.TransmitFile(path + validRequestFile);
    }
    else
    {
      response.TransmitFile(path + invalidRequestFile);
    }
    response.End();
  }

  private static string GetContentType(string url)
  {
    switch (Path.GetExtension(url))
    {
      case &quot;.gif&quot;:
        return &quot;Image/gif&quot;;
      case &quot;.jpg&quot;:
        return &quot;Image/jpeg&quot;;
      case &quot;.png&quot;:
        return &quot;Image/png&quot;;
      default:
        break;
    }
    return null;
  }

  public bool IsReusable
  {
    get { return false; }
  }
}
</pre>
</pre>
<p>Zu Schluss müssen wir diesen neuen Handler mit einer Route in der Global.asax registrieren:</p>
<pre>
<pre class="brush: csharp; ">

routes.Add(&quot;ImagesRoute&quot;,
                 new Route(&quot;images/{filename}&quot;, new ImageRouteHandler()));
</pre>
</pre>
<p>Hierbei ist noch wichtig, dass ihr die Route an der passenden Stelle registriert, sodass diese nicht ungewollt von einer anderen Route blockiert wird weil diese auch auf dieses Pattern matcht.</p>
<p>Nun werden alle Requests die auf die Route "images/{filename}" gehen und von einer anderen Domain stammen als eurer eigenen auf eine andere Grafik umgeleitet.</p>
<p>Nun bleibt noch ein kleines Problem, denn wenn das Verzeichnis mit den Bildern in eurem Content Verzeichnis liegt kann immer noch darauf verlinkt werden wenn man den vollen Pfad nimmt, also statt dem virtuellem Pfad</p>
<pre>
<pre class="brush: html; ">
http://localhost/images/myimg.jpg
</pre>
</pre>
<p>die URL benutzt unter der tatsächlich alle Bilder liegen:</p>
<pre>
<pre class="brush: html; ">
http://localhost/Content/graphics/myimg.jpg
</pre>
</pre>
<p>Dies liegt daran, dass der neue RouteHandler in diesem Fall nicht greift und die Default Route genutzt wird. Am einfachsten kann man dies verhindern wenn man den Zugriff für Unbefugte über die web.config sperrt:</p>
<pre>
<pre class="brush: xml; ">

  &lt;location path=&quot;Content/graphics&quot;&gt;
    &lt;system.web&gt;
      &lt;authorization&gt;
        &lt;allow roles=&quot;admin&quot; /&gt;
        &lt;deny users=&quot;*&quot; /&gt;
      &lt;/authorization&gt;
    &lt;/system.web&gt;
  &lt;/location&gt;
</pre>
</pre>
<p>Das war dann auch schon, ich nutze gern den zweiten Weg, da dieser mir einfacher und sauberer erscheint. Wenn euch noch andere Möglichkeiten einfallen wie man das anstellen kann dann immer her damit!</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1935&amp;md5=4370312dd926703596c6baf8858b1f24" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/asp-net-mvc-zugriff-auf-dateien-einschraenken/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSL Teil 4: Serverseitige Authentifizierung mit Java</title>
		<link>http://blog.bigbasti.com/ssl-teil-4-serverseitige-authentifizierung-mit-java/</link>
		<comments>http://blog.bigbasti.com/ssl-teil-4-serverseitige-authentifizierung-mit-java/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 10:00:57 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Computer]]></category>
		<category><![CDATA[Gut zu Wissen]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1901</guid>
		<description><![CDATA[Nachdem wir in den letzen Teilen mehr die Theorie durchgenommen haben, möchte ich jetzt zu dem praktischen Teil kommen und euch zeigen wie man diese Theorie in Code umsetzen kann am Beispiel Java. (.NET wird auch noch folgen)

Wir wollen einfach einsteigen und implementieren erst mal nur die eine Serverseitige Authentifizierung, also muss der Server ...]]></description>
			<content:encoded><![CDATA[<p>Nachdem wir in den letzen Teilen mehr die Theorie durchgenommen haben, möchte ich jetzt zu dem praktischen Teil kommen und euch zeigen wie man diese Theorie in Code umsetzen kann am Beispiel Java. (.NET wird auch noch folgen)</p>
<p>Wir wollen einfach einsteigen und implementieren erst mal nur die eine Serverseitige Authentifizierung, also muss der Server sich uns gegenüber ausweisen und wir sind in der Pflicht sein Zertifikat anzunehmen oder abzulehnen.</p>
<p>Wie in Teil 1 erklärt benötigen wir also zunächst einen Ort wo wir die Zertifikate sichern, denen wir vertrauen. Hier können wir (da wir in Java unterwegs sind) nicht die Windows-eigenen nehmen sondern müssen die so genannten Keystores von Java Nutzen.</p>
<p>Ein Keystore, wie der Name schon sagt ist nichts anderes als ein Speicher für Zertifikate. Wenn ihr Java installiert dann legt Java bereits einen Keystore für euch an, diesen findet ihr dann in eurem Java Verzeichnis Java\jre6\lib\security\cacerts die Datei „cacerts“ enthält hier bereits ähnlich wie bei Windows bereits die CA-Zertifikate von den großen Zertifizierungsstellen.</p>
<p>Es wir desweiterhin in Java unterschieden zwischen  Keystore und Truststore, beides sind im Grunde Keystores und unterscheiden sich nur im Namen und in ihrem Inhalt. Eine einzige Datei kann auch beide beinhalten, ist aber eher unüblich, da man die eigenen (privaten) Zertifikate von den CA-Zertifikaten separieren will.</p>
<p><a href="http://server.bigbasti.com/uploads/uploads/121221115126786612.png"><img class="aligncenter" title="Zuständigkeiten" src="http://server.bigbasti.com/uploads/uploads/121221115126786612.png" alt="Zuständigkeiten" width="481" height="268" /></a></p>
<p>So enthalten die Keystores für gewöhnlich die eigenen Privaten Schlüssel und die eigenen von anderen CAs signierte Zertifikate, die bei Verbindungen als Serverzertifikate (Public Keys) genutzt werden. Der Truststore ist das Gegenstück und enthält die Zertifikate denen man vertraut. So müssen wir die Zertifikate die wir vom Server beim Verbindungsaufbau erhalten gegen einen Truststore prüfen.</p>
<p>Fangen wir mit unserem Code an, wir wollen einen Client erstellen, der eine Socket-basierte Verbindung zu einem Server über SSL aufbaut und das vom Server zurückgegebene Zertifikat prüft.</p>
<p>Java ist auf diesem Gebiet sehr entgegenkommend und bietet für fast alle Anwendungsfälle fertige APIs und Klassen die uns fast die ganze Arbeit abnehmen.</p>
<p>Um den Prozess besser aufzeigen zu können schreiben wir uns eine Eigene SSLSocketFactory die für uns den Aufbau der Verbindung übernimmt und unserem Programm im Prinzip ein fertiges Socket liefert.</p>
<p>Dazu erstellen wir eine neue Klasse und lassen diese von SSLSocketFactory erben. Da das eine abstrakte Klasse ist müssen eir einige Methoden implementieren. Wenn das erledigt ist sieht unsere Klasse schon so aus:</p>
<pre>
<pre class="brush: java; ">

/**
 * Stellt eine SSLSocketFactory bereit die einen angegebenen TrustStore nutzt
 * @author Sebastian Gross
 */
public class ServerSSLAuthSocketFactory extends SSLSocketFactory{

    @Override
    public String[] getDefaultCipherSuites() {

    }

    @Override
    public String[] getSupportedCipherSuites() {

    }

    @Override
    public Socket createSocket(Socket socket, String string,
            int i, boolean bln) throws IOException {

    }

    @Override
    public Socket createSocket(String destinationAddress,
            int destinationPort) throws IOException, UnknownHostException {

    }

    @Override
    public Socket createSocket(String string, int i,
            InetAddress ia, int i1) throws IOException, UnknownHostException {

    }

    @Override
    public Socket createSocket(InetAddress ia, int i) throws IOException {

    }

    @Override
    public Socket createSocket(InetAddress ia, int i,
            InetAddress ia1, int i1) throws IOException {

    }
}
</pre>
</pre>
<p>Nun müssen wir diesen Methoden Leben einhauchen, aber keine Angst das ist nicht so schlimm wie es aussieht, denn die einzige Änderung die wir machen müssen ist es der SSLSocktFactory beizubringen mit unserem Truststore zu arbeiten, der Rest der Funktionalität soll unberührt bleiben.</p>
<p>Fügen wir also einen Konstruktor zu unserer Klasse hinzu der das Initialisieren unserer Internen SSLSocketFactory mit unserem Truststore übernimmt.</p>
<pre>
<pre class="brush: java; ">

/** Delegate {@link SSLSocketFactory}. */
private transient SSLSocketFactory factory;

private File caFile;
private KeyStore ks;

private SSLContext context;
private TrustManagerFactory tmf;
private X509TrustManager defTrustManager;
private SavingTrustManager tm;

/**
 * Neue Truststore-basierte SSL-SocketFactory
 * @param truststoreLocation Vollqualifizierter Pfad zum Truststore oder
			leer lassen für Java-Default-Truststore
 * @param truststorePass Passwort für den Truststore. Wenn leer wird
			&quot;changeit&quot; ala Passwort benutzt.
 */
public ServerSSLAuthSocketFactory(String truststoreLocation,
								  String truststorePass){
	super();

	//Wenn ein Pfad zum TrustStore angegeben wurde diesen benutzen
	if(!truststoreLocation.isEmpty()){
		caFile = new File(truststoreLocation);
	}else{
		//Pfad zum default Java TrustStore finden
		caFile = new File(&quot;cacerts&quot;);
		if (!caFile.exists() || !caFile.isFile()) {
			char SEP = File.separatorChar;
			File dir = new File(System.getProperty(&quot;java.home&quot;) + SEP
					+ &quot;lib&quot; + SEP + &quot;security&quot;);
			caFile = new File(dir, &quot;cacerts&quot;);
			if (!caFile.exists() || !caFile.isFile()) {
				caFile = new File(dir, &quot;cacerts&quot;);
			}
		}
	}

	//Prüfen, ob ein TrustStore Password angegeben wurde
	String truststorePassword = truststorePass.isEmpty() ? &quot;changeit&quot; : truststorePass;

	//TrustStore öffnen
	try {
		InputStream in = new FileInputStream(caFile);
		ks = KeyStore.getInstance(KeyStore.getDefaultType());
		ks.load(in, truststorePassword.toCharArray());
		in.close();
	} catch (KeyStoreException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	} catch (NoSuchAlgorithmException ex){
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	} catch (CertificateException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	} catch (FileNotFoundException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	}catch (IOException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	}

	try {
		context = SSLContext.getInstance(&quot;TLS&quot;);
		tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		tmf.init(ks);
		defTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
		context.init(null, new TrustManager[] {defTrustManager}, null);
		factory = context.getSocketFactory();
	} catch (NoSuchAlgorithmException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	} catch (KeyStoreException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	} catch (KeyManagementException ex) {
		Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
	}

}
</pre>
</pre>
<p>Das sieht auf den ersten Blick recht komplex aus, ist aber im Grunde recht simpel.</p>
<ul>
<li>In den Zeilen 23 - 28 prüfen wir ob der Konstruktor einen Pfad zu einem Truststore übergeben bekommen hat, und wenn dies nicht der Fall ist, wird der Pfad zu dem Standard-Java-Truststore in eurem JRE-Verzeichnis ermittelt.</li>
<li>Direkt danach in Zeile 41 prüfen wir ob ein Passwort übergeben wurde. Wenn keins übergeben wurde wird "changeit" genutzt. "changeit" ist das Defaultpasswort für den Standard-Java-Truststore.</li>
<li>In Zeile 45 - 48 öffnen wir den Keystore und laden dessen Inhalt in unsere Kokale KeyStore Variable.</li>
<li>Das Wichtigste geschieht nun in Zeile 67 - 72 hier holen wir uns einen Verweis auf den SSLContext (67) und erstellen uns mit Hilfe unseres KeyStores einene TrustManagerFactory(68-69). Anschließend lassen wir die TrustManagerFactory für uns einen neuen X509TrustManager "produzieren" der dann den Verweis auf unseren eigenen Keystore trägt. (70)</li>
<li>Nun sagen wir dem SSLContext, dass es unseren Trustmanager nutzen soll (71) für die darüber laufende Verbindungen und erstellen uns eine SSLSocketFactory (72)</li>
</ul>
<p>Nun haben wir intern eine SocketFactory, die unseren eigenen (über den Konstruktor angegebenen) Keystore nutzt. Der Rest der Klasse die wir erstellt haben dient hierbei eigentlich nur als Wrapper und Durchreiche, der Wichtigste Teil war der Konstruktor.</p>
<p>Die restlichen Methoden können nun also alle Anfragen direkt an die produzierte SSLSocketFactory weiterleiten. So sieht dann die fertige Klasse aus:</p>
<pre>
<pre class="brush: java; ">

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * Stellt eine SSLSocketFactory bereit die einen angegebenen TrustStore nutzt
 * @author Sebastian Gross
 */
public class ServerSSLAuthSocketFactory extends SSLSocketFactory{

    /** Delegate {@link SSLSocketFactory}. */
    private transient SSLSocketFactory factory;

    private File caFile;
    private KeyStore ks;

    private SSLContext context;
    private TrustManagerFactory tmf;
    private X509TrustManager defTrustManager;
    private SavingTrustManager tm;

    /**
     * Neue Truststore-basierte SSL-SocketFactory
     * @param truststoreLocation Vollqualifizierter Pfad zum
	 *			Truststore oder leer lassen für Java-Default-Truststore
     * @param truststorePass Passwort für den Truststore.
	 *			Wenn leer wird &quot;changeit&quot; ala Passwort benutzt.
     */
    public ServerSSLAuthSocketFactory(String truststoreLocation,
				String truststorePass){
        super();

        //Wenn ein Pfad zum TrustStore angegeben wurde diesen benutzen
        if(!truststoreLocation.isEmpty()){
            caFile = new File(truststoreLocation);
        }else{
            //Pfad zum default Java TrustStore finden
            caFile = new File(&quot;cacerts&quot;);
            if (!caFile.exists() || !caFile.isFile()) {
                char SEP = File.separatorChar;
                File dir = new File(System.getProperty(&quot;java.home&quot;) + SEP
                        + &quot;lib&quot; + SEP + &quot;security&quot;);
                caFile = new File(dir, &quot;cacerts&quot;);
                if (!caFile.exists() || !caFile.isFile()) {
                    caFile = new File(dir, &quot;cacerts&quot;);
                }
            }
        }

        //Prüfen, ob ein TrustStore Password angegeben wurde
        String truststorePassword =
				truststorePass.isEmpty() ? &quot;changeit&quot; : truststorePass;

        //TrustStore öffnen
        try {
            InputStream in = new FileInputStream(caFile);
            ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(in, truststorePassword.toCharArray());
            in.close();
        } catch (KeyStoreException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex){
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        }catch (IOException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        }

        try {
            context = SSLContext.getInstance(&quot;TLS&quot;);
            tmf = TrustManagerFactory.getInstance(TrustManagerFactory
													.getDefaultAlgorithm());
            tmf.init(ks);
            defTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
            context.init(null, new TrustManager[] {defTrustManager}, null);
            factory = context.getSocketFactory();
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        } catch (KeyManagementException ex) {
            Logger.getLogger(ServerSSLAuthSocketFactory.class.getName())
						.log(Level.SEVERE, null, ex);
        }

    }

    @Override
    public String[] getDefaultCipherSuites() {
        return factory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return factory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String string,
					int i, boolean bln) throws IOException {
        return factory.createSocket(socket, string, i, bln);
    }

    @Override
    public Socket createSocket(String destinationAddress,
					int destinationPort) throws IOException, UnknownHostException {
        return (SSLSocket)factory.createSocket(destinationAddress, destinationPort);
    }

    @Override
    public Socket createSocket(String string, int i,
					InetAddress ia, int i1) throws IOException, UnknownHostException {
        return factory.createSocket(string, i, ia, i1);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i) throws IOException {
        return factory.createSocket(ia, i);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i,
					InetAddress ia1, int i1) throws IOException {
        return factory.createSocket(ia, i, ia1, i1);
    }
}
</pre>
</pre>
<p>Da wir nun eine Factory haben die uns Sockets liefert, die auf unseren Truststore zugreift, können wir diese nun nutzen um eine Verbindung zu SSL Servern aufzubauen. Das Schöne hierbei ist, dass Java an sehr vielen Stellen SocketFactories nutzt, so können wir fast in allen Szenarien unsere Klasse einsetzen.</p>
<p>So können wir unsere SSLFactory nun ganz simpel testen:</p>
<pre>
<pre class="brush: java; ">

public static void main (String [] args) throws IOException{

    int port = 443; // default https port
    String host = &quot;httpsurl&quot;;

    try {
      SSLSocketFactory factory
       = (SSLSocketFactory) new ServerSSLAuthSocketFactory(&quot;&quot;,&quot;&quot;);

      SSLSocket socket = (SSLSocket) factory.createSocket(host, port);

      // enable all the suites
      String[] supported = socket.getSupportedCipherSuites();
      socket.setEnabledCipherSuites(supported);

      Writer out = new OutputStreamWriter(socket.getOutputStream());
      // https requires the full URL in the GET line
      out.write(&quot;GET https://&quot; + host + &quot;/ HTTP/1.1\r\n&quot;);
      out.write(&quot;Host: &quot; + host + &quot;\r\n&quot;);
      out.write(&quot;\r\n&quot;);
      out.flush();

      // read response
      BufferedReader in = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));

      // read the header
      String s;
      while (!(s = in.readLine()).equals(&quot;&quot;)) {
          System.out.println(s);
      }
      System.out.println();

      // read the length
      String contentLength = in.readLine();
      int length = Integer.MAX_VALUE;
      try {
        length = Integer.parseInt(contentLength.trim(), 16);
      }
      catch (NumberFormatException ex) {
        // This server doesn&#039;t send the content-length
        // in the first line of the response body
      }
      System.out.println(contentLength);

      int c;
      int i = 0;
      while ((c = in.read()) != -1 &amp;&amp; i++ &lt; length) {
        System.out.write(c);
      }

      System.out.println();
      out.close();
      in.close();
      socket.close();

    }
    catch (IOException ex) {
      System.err.println(ex);
    }
}
</pre>
</pre>
<p>Tragt in Zeile 4 einfach den gewünschten SSL-Host ein wie z.B. Google oder Facebook und startet das kleine Programm. Falls ihr keine Parameter beim Erzeugen der Factory (Zeile 7 und <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> angegeben habt solltet ihr auch keine Probleme beim Verbinden haben und wenn das Programm durchgelaufen ist seht ihr die Antwort des Servers im HTML Format.</p>
<p>Falls ihr doch einen eigenen Truststore eingetragen habt müsst ihr sicherstellen, dass dieser den Public Key des Servers zu dem ihr euch verbinden wollt beinhaltet, sonst wird die Verbindung nicht erfolgen.</p>
<p><a title="SSL Teil 1: Serverseitige Authentifizierung und Zertifikate" href="http://blog.bigbasti.com/ssl-teil1-serverseitige-authentifizierung-und-zertifikate/" target="_blank">Teil 1: Serverseitige Authentifizierung und Zertifikate</a><a title="Teil 1 der Serie" href="http://blog.bigbasti.com/ssl-teil1-serverseitige-authentifizierung-und-zertifikate/"><br />
</a><a title="SSL Teil 2: Beidseitige Authentifizierung" href="http://blog.bigbasti.com/ssl-teil-2-beidseitige-authentifizierung/">Teil 2: Beidseitige Authentifizierung</a><a title="Teil 1 der Serie" href="http://blog.bigbasti.com/ssl-teil1-serverseitige-authentifizierung-und-zertifikate/"><br />
</a><a title="SSL Teil 3: Der SSL Handshake" href="http://blog.bigbasti.com/ssl-teil-3-der-ssl-handshake/" target="_blank">Teil 3: Der SSL Handshake<br />
</a>Teil 4: Serverseitige Authentifizierung mit Java</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1901&amp;md5=5c14c6bafe61fc48928f9e2b59c81248" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/ssl-teil-4-serverseitige-authentifizierung-mit-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eine TreeView durchsuchen und den gefundenen Pfad aufklappen</title>
		<link>http://blog.bigbasti.com/eine-treeview-durchsuchen-und-den-gefundenen-pfad-aufklappen/</link>
		<comments>http://blog.bigbasti.com/eine-treeview-durchsuchen-und-den-gefundenen-pfad-aufklappen/#comments</comments>
		<pubDate>Thu, 29 Sep 2011 14:16:21 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Visual Basic]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1860</guid>
		<description><![CDATA[Da ich heute wieder eine Mail mit der Frage bekommen habe wie man ein Item in einer TreeView finden kann und dieses dann anzeigen kann, dachte ich ich poste es gleich hier falls es noch jemand braucht.

Das Ganze funktioniert sehr einfach mit nur einer kleinen rekursiven Funktion:

   ''' 
    ...]]></description>
			<content:encoded><![CDATA[<p>Da ich heute wieder eine Mail mit der Frage bekommen habe wie man ein Item in einer TreeView finden kann und dieses dann anzeigen kann, dachte ich ich poste es gleich hier falls es noch jemand braucht.</p>
<p>Das Ganze funktioniert sehr einfach mit nur einer kleinen rekursiven Funktion:</p>
<pre>
<pre class="brush: vb; ">

   &#039;&#039;&#039; &lt;summary&gt;
    &#039;&#039;&#039; Diese Funktion durchläuft den ganzen Treenode bis ein Eintrag gefunden wird der dem Suchbegriff
    &#039;&#039;&#039; gleicht. Danach wird der Pfad der zu diesem TreeNode führt (zur Visualisierung) aufgeklappt
    &#039;&#039;&#039; &lt;/summary&gt;
    &#039;&#039;&#039; &lt;param name=&quot;tn&quot;&gt;Der zu durchsuchende Treenode
    &#039;&#039;&#039; &lt;param name=&quot;name&quot;&gt;Der Suchbegriff
    Public Sub findNode(ByVal tn As TreeNode, ByVal name As String)
        For Each tnn As TreeNode In tn.Nodes
            If tnn.Text = name Then
                Dim t As TreeNode = tnn
                For i As Integer = tnn.Level To i = 0 Step -1
                    Try
                        t = t.Parent
                        t.Expand()
                    Catch ex As Exception
                    End Try
                Next
                tnn.Parent.Expand()
                Exit Sub
            End If
            findNode(tnn, name)
        Next
    End Sub
</pre>
</pre>
<p>Hier laufen wir alle Nodes der TreeView durch bis wir auf einen Node stoßen der unserem Suchbegriff entspricht. Ab hier durchlaufen wir den ganzen Weg rückwärts und klappen alle übergeordneten Nodes auf, sodass wir unseren gesuchten Node zu Gesicht bekommen.</p>
<p>Diese Funktion kann man auch ganz gut als Extension Method umschreiben, sodass diese bequemer aufgerufen werden kann, aber das ist dann natürlich jedem selbst überlassen.</p>
<div class="wp-caption aligncenter" style="width: 545px"><a href="http://server.bigbasti.com/uploads/uploads/299211161135833355.png"><img title="Demoapp" src="http://server.bigbasti.com/uploads/uploads/299211161135833355.png" alt="Demoapp in Aktion" width="535" height="305" /></a><p class="wp-caption-text">Demoapp in Aktion</p></div>
<p>Hier noch ein Demoprojekt zum testen: <a href="http://server.bigbasti.com/uploads/uploads/TreeViewSearchDemoApp.zip" target="_blank">Download [VS 2010]</a></p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1860&amp;md5=12995d7d9dee6d0cea9e36a75d122071" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/eine-treeview-durchsuchen-und-den-gefundenen-pfad-aufklappen/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Nice2Know: Attribut-basierende Routen in ASP.NET MVC</title>
		<link>http://blog.bigbasti.com/nice2know-attribut-basierende-routen-in-asp-net-mvc/</link>
		<comments>http://blog.bigbasti.com/nice2know-attribut-basierende-routen-in-asp-net-mvc/#comments</comments>
		<pubDate>Sat, 17 Sep 2011 15:47:31 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1850</guid>
		<description><![CDATA[Für Routen ist in ASP.NET MVC für gewöhnlich die Global.asax zuständig, so werden hier alle Routen definiert und gemappt. Doch wenn man viele verschiedene Routen nutzen will wird es schnell voll in der eigentlich sehr übersichtlichen Klasse.

Da wäre es doch eigentlich cool wenn wir die Routen direct in unseren Controllern definieren könnten. Genau das ...]]></description>
			<content:encoded><![CDATA[<p>Für Routen ist in ASP.NET MVC für gewöhnlich die Global.asax zuständig, so werden hier alle Routen definiert und gemappt. Doch wenn man viele verschiedene Routen nutzen will wird es schnell voll in der eigentlich sehr übersichtlichen Klasse.</p>
<p>Da wäre es doch eigentlich cool wenn wir die Routen direct in unseren Controllern definieren könnten. Genau das können wir mit der Erweiterung <a href="https://github.com/mccalltd/AttributeRouting/wiki/_pages" target="_blank">AttributeRouting</a> machen.</p>
<div class="wp-caption aligncenter" style="width: 459px"><a href="http://server.bigbasti.com/uploads/uploads/179211172286.png "><img title="Installation" src="http://server.bigbasti.com/uploads/uploads/179211172286.png " alt="Installation" width="449" height="96" /></a><p class="wp-caption-text">Installation über NuGet</p></div>
<p style="text-align: left;">Dank NuGet ist die Installation in wenigen Sekunden abgeschlossen und wir können unsere Actions mit Routing-Attributen dekorieren.</p>
<p style="text-align: left;">Die Attribute sind hierbei sehr einfach gestaltet und bieten uns alles was wir benötigen.</p>
<pre>
<pre class="brush: csharp; ">

    public class DemoController : Controller
    {
        [GET(&quot;Ist/Das/Cool/Oder/Was&quot;)]
        public ActionResult Start()
        {
            return View();
        }
    }
</pre>
</pre>
<p>Nun muss man nur noch die Attribut-basierten Routen registrieren:</p>
<pre>
<pre class="brush: csharp; ">

    public static void RegisterRoutes(RouteCollection routes) {
        routes.IgnoreRoute(&quot;{resource}.axd/{*pathInfo}&quot;);

        routes.MapAttributeRoutes(); //--- das wars!

        routes.MapRoute(
            &quot;Default&quot;, // Route name
            &quot;{controller}/{action}/{id}&quot;, // URL with parameters
            new { controller = &quot;Home&quot;, action = &quot;Start&quot;,
                id = UrlParameter.Optional } // Parameter defaults
        );
    }
</pre>
</pre>
<p>Und fertig! Nun können wir die Seite starten und unsere Route testen:</p>
<div class="wp-caption aligncenter" style="width: 530px"><a href="http://server.bigbasti.com/uploads/uploads/1792111731231336.png "><img title="Das Ergebnis" src="http://server.bigbasti.com/uploads/uploads/1792111731231336.png " alt="Das Ergebnis" width="520" height="186" /></a><p class="wp-caption-text">Das Ergebnis</p></div>
<p>Die Routen die wir definieren können, beschränken sich nicht darauf, so können diese auch problemlos parametrisiert werden, inklusive Defaultparameter:</p>
<pre>
<pre class="brush: csharp; ">

    public class DemoController : Controller
    {
        [GET(&quot;Artikel/{artikelid}/{version?}&quot;)]
        [RouteDefault(&quot;artikelid&quot;, &quot;120&quot;)]
        public ActionResult Start(int artikelid, string version)
        {
            ViewBag.ArtikelId = artikelid;
            ViewBag.Version = version;

            return View();
        }
    }
</pre>
</pre>
<p>Hier wird der Parameter artikelid mit einem Defaultwert ausgestattet und der zweite optional gemacht. Das Ergebnis kann sich sehen lasen:</p>
<div class="wp-caption aligncenter" style="width: 463px"><a href="http://server.bigbasti.com/uploads/uploads/1792111742255336.png "><img title="Läuft!" src="http://server.bigbasti.com/uploads/uploads/1792111742255336.png " alt="Läuft!" width="453" height="558" /></a><p class="wp-caption-text">Läuft!</p></div>
<p>Hier hört das Framework nicht auf, so könnt ihr auch Regular Expressions in die Routen integrieren und auch mehrere Routen an eine Action heften. Die Möglichkeiten sind grenzenlos <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Für weitere Infos schaut einfach auf der <a href="https://github.com/mccalltd/AttributeRouting/wiki/2.-Usage" target="_blank">Projekthomepage </a>vorbei, es lohnt sich!</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1850&amp;md5=e86fd31c11e06da4d9708006f221b747" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/nice2know-attribut-basierende-routen-in-asp-net-mvc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nice2Know: Errorlogging mit ELMAH</title>
		<link>http://blog.bigbasti.com/nice2know-errorlogging-mit-elmah/</link>
		<comments>http://blog.bigbasti.com/nice2know-errorlogging-mit-elmah/#comments</comments>
		<pubDate>Sat, 17 Sep 2011 11:16:04 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/nice2know-errorlogging-mit-elmah/</guid>
		<description><![CDATA[Errorlogging? Ist das nicht dieses Zeugs das die ganzen Java Programmierer und Linux Fuzies nutzen werdet ihr euch jetzt denken? Stimmt, aber auch in der .NET Welt ist es sehr nützlich ein Log zu führen und hier gibt es einige Tools für uns Entwickler die für uns diese unschöne Arbeit deutlich ersparen.

Das Tool dass ...]]></description>
			<content:encoded><![CDATA[<p>Errorlogging? Ist das nicht dieses Zeugs das die ganzen Java Programmierer und Linux Fuzies nutzen werdet ihr euch jetzt denken? Stimmt, aber auch in der .NET Welt ist es sehr nützlich ein Log zu führen und hier gibt es einige Tools für uns Entwickler die für uns diese unschöne Arbeit deutlich ersparen.</p>
<p>Das Tool dass ich euch heute vorstellen möchte ist ELMAH, was für Error Logging Modules and Handlers steht.</p>
<p>Was kann ELMAH? Hier ein Ausschnitt von der <a href="http://code.google.com/p/elmah/" target="_blank">Hompage</a>:</p>
<ul>
<li>Logging of nearly all unhandled exceptions.</li>
<li>A web page to remotely view the entire log of recoded exceptions.</li>
<li>A web page to remotely view the full details of any one logged exception, including colored stack traces.</li>
<li>In many cases, you can review the original <a href="http://en.wikipedia.org/wiki/Yellow_Screen_of_Death#ASP.NET">yellow screen of death</a> that ASP.NET generated for a given exception, even with <tt>customErrors</tt>mode turned off.</li>
<li>An e-mail notification of each error at the time it occurs.</li>
<li>An RSS feed of the last 15 errors from the log</li>
</ul>
<p>&nbsp;</p>
<p>Zusammengefasst gesagt schnappt ELMAH sich jede Exception die ihr nicht abgefangen habt und loggt diese für euch im Speicher oder in einer Datenbank und fasst diese auch noch schön zusammen auf einer Übersichtswebseite, in einem RSS Feed oder schickt euch diese direkt per Mail zu.</p>
<p>So könnt ihr jeder Zeit nach der Exception schauen was schiefgelaufen ist und euch den kompletten Stacktrace anschauen und (fast) jeden Yellow Screen of Death nachstellen.</p>
<p>Was mir an diesem Tool besonders gefällt ist die sehr einfach Integration in ein Projekt. Alles was ihr machen müsst ist es dafür zu sorgen dass die DLL in eurem bin-Verzeichnis und einen Handler in eure web.config einzutragen. Nun werden alle eure unbehandelten Exceptions geloggt.</p>
<p>Und es geht sogar noch einfacher, wenn ihr NuGet nutzt werden euch sogar diese Schritte abgenommen, einfach NuGet anwerfen, nach ELMAH suchen und installieren - fertig.</p>
<p><img src="http://server.bigbasti.com/uploads/uploads/1792111247365398.png" alt="" /></p>
<p>Das Schöne an NuGet ist, dass es nicht nur die Bibliothek herunterlädt sondern auch alle nötigen Einträge für uns anpasst, so werdet ihr nun auch ein paar neue Zeilen in eurer web.config entdecken:</p>
<p><a href="http://server.bigbasti.com/uploads/uploads/179211125242222.png"><img src="http://server.bigbasti.com/uploads/uploads/179211125242222.png" alt="" width="606" height="402" /></a></p>
<p>Diese Arbeit blieb uns zum Glück erspart <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Da nun eigentlich schon alles konfiguriert ist können wir fröhlich ein paar Fehler erzeugen:</p>
<p><a href="http://server.bigbasti.com/uploads/uploads/1792111255544865.png"><img src="http://server.bigbasti.com/uploads/uploads/1792111255544865.png" alt="" width="487" height="314" /></a></p>
<p>Ich habe hier also eine URL aufgerufen für die kein Controller und keine View bestimmt werden konnte. Dass wir hier so “viele” Informationen angezeigt bekommen liegt daran, dass wir die Seite lokal aufrufen, würden wir das ganze von einem anderem System machen würden uns noch weniger Informationen zur Verfügung stehen.</p>
<p>Nun wollen wir mal gucken, was ELMAH für uns aufgezeichnet hat, das können wir machen, in dem wir diese Seite aufrufen: /elmah.axd</p>
<p><a href="http://server.bigbasti.com/uploads/uploads/1792111346775.png"><img src="http://server.bigbasti.com/uploads/uploads/1792111346775.png" alt="" width="522" height="342" /></a></p>
<p>Alle aufgetretenen Exceptions für uns übersichtlich dargestellt. Wenn Bedarf besteht kann man natürlich auch tiefer bohren und die Details aufklappen:</p>
<p><a href="http://server.bigbasti.com/uploads/uploads/179211133145525.png"><img src="http://server.bigbasti.com/uploads/uploads/179211133145525.png" alt="" width="521" height="422" /></a></p>
<p>Hier hat man nun den vollen Stacktrace und viele weitere Informationen wie z.B. die Servervariablen. Eine sehr coole Sache wie ich finde, da ihr nun auch von unterwegs eure Fehler untersuchen könnt.</p>
<p>Falls ihr nicht wollt, dass jeder eure Exceptions sehen kann ist dies <a href="http://stackoverflow.com/questions/1245364/securing-elmah-in-asp-net-website" target="_blank">natürlich auch möglich</a>.</p>
<p><span style="color: #800000;">UPDATE: Ich habe hier die normale Version von ELMAH genutzt, für ein MVC Projekt würde ich aber <a href="http://nuget.org/List/Packages/Elmah.MVC" target="_blank"><span style="color: #800000;">ELMAH.MVC </span></a>empfehlen (Ebenfalls auf NuGet verfügbar). Dieses integriert sich besser in eine MVC Umgebung da es einen AdminController anlegt und somit über /Admin/Elmah erreichbar ist.</span></p>
<p>ELMAH gibt es übrigens schon eine halbe Ewigkeit aber ich (Langschläfer) bin erst vor ein paar Wochen drüber gestolpert. Wie schaut es bei euch aus? Nutzt ihr ELMAH?</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1848&amp;md5=45f3beda6028dc0e54ae84e516d24d39" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/nice2know-errorlogging-mit-elmah/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Lokale Wetterdaten anzeigen mit der HTML5 Geolocation API und ASP.NET MVC</title>
		<link>http://blog.bigbasti.com/lokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc/</link>
		<comments>http://blog.bigbasti.com/lokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc/#comments</comments>
		<pubDate>Sun, 11 Sep 2011 20:50:28 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/lokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc/</guid>
		<description><![CDATA[Wenn man heutzutage hipp sein will mit seiner Webseite sollte man irgendwelche coolen Features von HTML5 nutzen. Deswegen möchte ich euch in diesem kleinem Tutorial zeigen, wie ihr auf eurer Seite dem aktuellen Besucher sein lokales Wetter anzeigen könnt.

Um dieses Ziel zu verwirklichen benötigen wir folgende Daten bzw. Dienste:

	Die physische Position des Besuchers
	Einen Dienst ...]]></description>
			<content:encoded><![CDATA[<p>Wenn man heutzutage hipp sein will mit seiner Webseite sollte man irgendwelche coolen Features von HTML5 nutzen. Deswegen möchte ich euch in diesem kleinem Tutorial zeigen, wie ihr auf eurer Seite dem aktuellen Besucher sein lokales Wetter anzeigen könnt.</p>
<p>Um dieses Ziel zu verwirklichen benötigen wir folgende Daten bzw. Dienste:</p>
<ol>
<li>Die physische Position des Besuchers</li>
<li>Einen Dienst der uns zu der Position des Besuchers die Wetterdaten liefert</li>
</ol>
<p>Der erste Punkt ist schnell abgehackt, denn hier werden wir eins der tollen neuen HTML5 Features namens Geolocation API benutzen. Diese API liefert uns, vorausgesetzt der Browser unterstützt es, Koordinaten des aktuellen Besuchers der Webseite. Alle aktuellen Browser, auch der IE ab Version 9 unterstützt diese API.</p>
<p>Das Ganze läuft so ab, dass wir als Webseite den Browser nach den Koordinaten fragen, aber dieser uns diese nicht sofort herausrückt, sondern erst den Benutzer fragt ob er einverstanden ist, das sieht je nach Browser unterschiedlich aus, hier ein Beispiel aus dem FireFox 6:</p>
<p><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px; border: 0px;" src="http://server.bigbasti.com/uploads/uploads/11921122493748.png" alt="" border="0" /></p>
<p>Wenn der Benutzer hier auf die “Zugriff erlauben” Schaltfläche klickt bekommen wir ein Objekt mit einem Haufen an Informationen rund um die Position des Benutzers. Für uns ist an dieser Stelle aber nur die Adresse des Nutzers von Bedeutung.</p>
<p><strong>Moment mal, woher weiß der Browser so ich bin?</strong></p>
<p>Tja, das ist eine gute Frage, auf magische Weise weiß der Browser wo wir uns aufhalten, auch wenn wir grad mit einem Desktopcomputer auf der Seite sind, der kein GPS Chip verbaut hat (im Vergleich zum Handy – wo das ja klar sein sollte) und das auch noch _ziemlich_ genau!</p>
<p>Im ersten Augenblick könnte man denken der Browser macht es über die IP Adresse, aber nein die IP ist _Viel_ zu ungenau im Vergleich mit den echten Koordinaten.</p>
<p>So sendet der Browser (Firefox) nach eurer Erlaubnis folgende Daten an Google unter dieser Adresse: <code><a href="https://www.google.com/loc/json">https://www.google.com/loc/json</a></code></p>
<pre>
<pre class="brush: javascript; ">

&quot;mac_address&quot;: &quot;01-23-45-67-89-ab&quot;,
&quot;signal_strength&quot;: 8,
&quot;age&quot;: 0,
&quot;SSID&quot;: &quot;MyAccessPoint&quot;
</pre>
</pre>
<p><a href="http://stackoverflow.com/questions/3041113/how-exactly-does-html5s-geolocation-work" target="_blank">Weitere Informationen</a></p>
<p>Als Google mit ihren StreetView Autos durch die Gegend gefahren ist haben die nämlich auch die Namen und die genauen Positionen von den WLAN Netzwerken gespeichert, an denen sie vorbeigefahren sind. An Hand dieser Informationen versucht Google euch nun zu orten.</p>
<p><strong>Wie komme ich nun an diese Informationen?</strong></p>
<p>Glücklicherweise gestaltet sich dies für uns sehr einfach:</p>
<pre>
<pre class="brush: javascript; ">

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(success, error);
} else {
  alert(&quot;Not Supported!&quot;);
}
</pre>
</pre>
<p>Wenn der Browser diese API kennt werden die statischen Klassen Navigator und geolocation aufgerufen und hier die Methode getCurrentPosition aufgerufen, diese bekommt als Parameter einen Verweis auf die Methode die ausgeführt werden soll. Wenn das Ganze fehlschlägt (Kein Browsersupport) soll die display_error-Methode aufgerufen werden.</p>
<p>Die Funktion success bekommt einen Parameter mit, der alle relevanten Informationen enthält:<br />
&lt;pre&gt;
<pre class="brush: javascript; ">

function success(position) {
alert(position.coords.latitude);
alert(position.coords.longitude);
alert(position.address.city);
}
</pre>
<p>Für uns ist für das weitere Vorgehen aber nur der Name der Stadt wichtig.</p>
<p><strong>Auslesen der Wetterinformationen</strong></p>
<p>Es gibt diverse offene APIs die uns die Wetterdaten zu einer angegebenen Stadt liefern können, ich habe mich an dieser Stelle für die von Google entschieden, da diese offen ist und keine Registrierung voraussetzt.</p>
<p>Die API ist unter folgender URL zu erreichen:</p>
<p><a href="http://www.google.com/ig/api?weather=[LOCATION]&amp;hl=[LANGUAGE]">http://www.google.com/ig/api?weather=[LOCATION]&amp;hl=[LANGUAGE</a>]</p>
<p>Hier müsst ihr lediglich die gewünschte Stadt und die gewünschte Sprache einsetzen. Als Antwort bekommt ihr eine XML, die die Wetterdaten enthält, und das nicht nur für jetzt, sondern für die gesamte nächste Woche, inklusive ausgeschriebener Formulierungen wie “Teils sonnig” oder “Meistens bewölkt”.</p>
<p>Und wenn euch das noch nicht genug ist, bietet Google auch gleich das passende Icon zu dem Wetter, dass ebenfalls aus dem XML.Status ausgelesen werden kann. Insgesamt gibt es 22 verschiedene Wetterzustände zu denen es jeweils auch ein passendes Icon gibt.</p>
<p><strong>Moment, wie komme ich nun an diese Daten?</strong></p>
<p>Es besteht nun nur noch ein kleines Problem. Die ganze Abfrage erfolgt beim Client, deswegen kennt nur der Client die Position des Benutzers. Wir müssen nun aber (im Hintergrund =&gt; Ajax) einen Request an den Google Dienst absenden um an die Wetterdaten zu kommen.</p>
<p>Leider können wir das nicht direkt aus dem Client machen, da die Browser es verbieten, Requests an andere Domains abzusenden als an die von der das Script geladen wurde. Das ganze schimpft sich “<a href="http://de.wikipedia.org/wiki/Same-Origin-Policy" target="_blank">Same Origin Policy</a>” und soll den Benutzer unter Anderem vor <a href="http://de.wikipedia.org/wiki/Cross-Site_Scripting" target="_blank">Cross-Site-Scripting</a>-Attaken schützen.</p>
<p>Das bedeutet, dass wir den Umweg über den Server gehen müssen und uns auf dem Server eine kleine API anlegen müssen die unserem Script auf Anfrage die passenden Daten liefert.</p>
<p>Dies kann man z.B so implementieren:</p>
<pre>
<pre class="brush: csharp; ">

private const string GOOGLE_WEATHER_API_URL =
	&quot;http://www.google.com/ig/api?weather={0}&amp;amp;amp;amp;amp;amp;amp;amp;hl=de&quot;;
public WeatherResult GetWeahterData(string city) {

    string api_url = string.Format(GOOGLE_WEATHER_API_URL, city);

    try {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(api_url);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream());

        string response = reader.ReadToEnd();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(response);

        string temp = xmlDoc.SelectSingleNode(&quot;xml_api_reply/weather/current_conditions/temp_c&quot;).Attributes[&quot;data&quot;].Value;
        string icon = xmlDoc.SelectSingleNode(&quot;xml_api_reply/weather/current_conditions/icon&quot;).Attributes[&quot;data&quot;].Value;

        WeatherResult wRes = new WeatherResult(temp, city);
        wRes.Icon = icon;

        return wRes;
    } catch (Exception ex) {
        return null;
    }
}
</pre>
</pre>
<p>Für den Response habe ich mir eine kleine Klasse gebastelt, die ich zu Json serialisiere und als Antwort zurückgebe:</p>
<pre>
<pre class="brush: csharp; ">

    public class WeatherResult {
        public string Temperature { get; set; }
        public string City { get; set; }
        public string Icon { get; set; }

        public WeatherResult(string temp, string city) {
            Temperature = temp;
            City = city;
        }
    }
</pre>
</pre>
<p>Das Ganze wird von dem ApiController aufgerufen:</p>
<pre>
<pre class="brush: csharp; ">

    public class ApiController : Controller
    {
        //
        // GET: /Api/GetWeather

        public JsonResult GetWeather(string id)
        {

            WeatherResult res = new Tools.Weather.WeatherHelper().GetWeahterData(id);

            return Json(res, JsonRequestBehavior.AllowGet);
        }

    }
</pre>
</pre>
<p>Was wir nun noch machen müssen ist unsere neu geschaffene API über einen Ajax Request aufzurufen. Hier habe ich jQuery benutzt um das Ganze zu vereinfachen:</p>
<pre>
<pre class="brush: javascript; ">

function get_address(position) {
    var full_url = &quot;/Api/GetWeather/&quot; + position.address.city;

    $.ajax({
        url: full_url,
        success: get_weather,
        error: display_error
    });
}
</pre>
</pre>
<p><img class="alignleft" title="Ein mögliches Ergebnis" src="http://server.bigbasti.com/uploads/uploads/119211235337.png " alt="" width="106" height="103" />Die get_weather-Funktion auf die ich hier im Erfolgsfall verweise ist nun dafür verantwortlich die vom Server erhaltenen Daten anzuzeigen, und dank dem zu Json serialisiertem WeatherResult-Objekt kann dies auch bequem erfolgen. Hier habe ich ebenfalls jQuery genutzt um mir die benötigten Referenzen auf die DOM-Objekte zu besorgen. Ein mögliches Ergebnis des Ganzen könnte ihr hier rechts sehen.</p>
<pre>
<pre class="brush: javascript; ">

function get_weather(address) {

    $(&quot;.weather_info&quot;).html(address.Temperature == &quot;&quot; ? &quot;N/A&quot; : address.Temperature + &quot;°C&quot;);
    $(&quot;.location_info&quot;).html(address.City);

}
</pre>
</pre>
<p><strong>Sonst noch was?</strong></p>
<p>Im Grunde wars das auch schon. Aber eine Kleinigkeit ist mir noch aufgefallen, und zwar kann es vorkommen, dass ihr keine Adressdaten von der Geolocation API bekommt, sondern nur Koordinaten. (Falls Google diese Daten nicht gelistet hat oder ähnliches).</p>
<p>In diesem Fall müsst ihr ein Reverselookup machen und die Koordinaten in eine Adresse umwandeln, da die Google Wetter API nur Ortsnamen, aber keine Koordinaten annimmt.</p>
<p>Glücklicherweise stellt und Google auch dafür eine API zur Verfügung, diese könnt ihr unter folgender URL erreichen:</p>
<pre><a href="http://maps.google.com/maps/api/geocode/json?latlng=[KOORDINATEN]sensor=true">http://maps.google.com/maps/api/geocode/json?latlng=[KOORDINATEN]sensor=true </a></pre>
<p>Hier könnt ihr sogar als Parameter angeben, ob ihr XML oder Json als Antwort haben wollt. Diese könnt ihr z.B. so nutzen:</p>
<pre>
<pre class="brush: csharp; ">

private const string GOOGLE_MAPS_REVERSE_LOOKUP_URL =
	&quot;http://maps.google.com/maps/api/geocode/json?latlng={0}&amp;amp;amp;amp;amp;amp;amp;amp;sensor=true&quot;;
public static string GetCityFromCoords(string coords) {
    string api_url = String.Format(GOOGLE_MAPS_REVERSE_LOOKUP_URL, coords);

    try {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(api_url);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream());

        string response = reader.ReadToEnd();

        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

        dynamic obj = serializer.Deserialize(response, typeof(object));

        string city = obj.results[0].address_components[3].long_name;

        return city;
    } catch (Exception ex) {
        return &quot;&quot;;
    }
}
</pre>
</pre>
<p>Hier habe ich mir ein dynamic-Object generieren lassen aus dem übergebenen Json. Dazu habe ich <a href="http://stackoverflow.com/questions/3142495/deserialize-json-into-c-dynamic-object/3806407" target="_blank">diese Klasse hier</a> genutzt.</p>
<p>Falls dieser Fall eintreffen sollte, braucht ihr übrigens nicht mit genauen Koordinaten bzw. Adressdaten zu rechnen, aber für unseren Zweck reicht es allemal.</p>
<p><a href="http://dotnet-kicks.de/kick/?url=http%3a%2f%2fblog.bigbasti.com%2flokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc%2f"><img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.bigbasti.com%2flokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc%2f" border="0" alt="kick it on dotnet-kicks.de" /></a></p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1830&amp;md5=96a6ab6e3801a698608a010cac3474f8" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/lokale-wetterdaten-anzeigen-mit-der-html5-geolocation-api-und-asp-net-mvc/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ausgeben einer Meldung nach dem Anmelden des Benutzers an einer ASP.NET Webseite</title>
		<link>http://blog.bigbasti.com/ausgeben-einer-meldung-nach-dem-anmelden-des-benutzers-an-einer-asp-net-webseite-2/</link>
		<comments>http://blog.bigbasti.com/ausgeben-einer-meldung-nach-dem-anmelden-des-benutzers-an-einer-asp-net-webseite-2/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 11:15:46 +0000</pubDate>
		<dc:creator>Michael Bernhard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Visual Basic]]></category>
		<category><![CDATA[Anmeldung]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1805</guid>
		<description><![CDATA[Neulich habe ich auf einer meiner Seiten neben dem normalen Zugang für Benutzer auch einen Gastzugang eingerichtet.
Meldet sich jemand als Gast an meinem System an, stehen im alle Seiten des Adminbereiches zur Ansicht zur Verfügung, ein Speichern der Änderungen wird jedoch nicht erlaubt.
Um den Gastnutzer meiner Seite auf diese Einschränkungen und andere Besonderheiten hinzuweisen ...]]></description>
			<content:encoded><![CDATA[<p>Neulich habe ich auf einer meiner Seiten neben dem normalen Zugang für Benutzer auch einen Gastzugang eingerichtet.<br />
Meldet sich jemand als Gast an meinem System an, stehen im alle Seiten des Adminbereiches zur Ansicht zur Verfügung, ein Speichern der Änderungen wird jedoch nicht erlaubt.</p>
<p>Um den Gastnutzer meiner Seite auf diese Einschränkungen und andere Besonderheiten hinzuweisen - wollte ich eine Meldung ausgeben - sobald der Gast sich beim System angemeldet hat.</p>
<p>Ich verwende zur Anmeldung der Benutzer die vom Visual Studio 2010 automatisch generierte Seite LogIn.aspx.</p>
<p>Im Folgenden möchte ich zeigen wie man diese automatisch generierte Seite abändern muss um oben beschriebenes umzusetzen zu können.</p>
<p>Die Meldung möchte ich als ModalPopup ausgeben. Hierfür erweiterte ich die LogIn.aspx um den Code für das ModalPopup</p>
<pre>
<pre class="brush: html; ">

...
&lt;div style=&quot;display:none;&quot;&gt;
    &lt;asp:Button ID=&quot;ButtonGastLogIn&quot; runat=&quot;server&quot; /&gt;
&lt;/div&gt;
&lt;asp:ToolkitScriptManager ID=&quot;ToolkitScriptManagerGastLogIn&quot; runat=&quot;server&quot;/&gt;
&lt;asp:ModalPopupExtender ID=&quot;ModalPopupExtenderGastLogInt&quot; runat=&quot;server&quot;
    TargetControlID=&quot;ButtonGastLogIn&quot;
    PopupControlID=&quot;PopupGastLogIn&quot;
    cancelControlID=&quot;ButtonClose&quot;
    backgroundcssclass=&quot;ModalPopupBG&quot;&gt;
&lt;/asp:ModalPopupExtender&gt;
&lt;div id=&quot;PopupGastLogIn&quot; runat=&quot;server&quot;&gt;
...
    &lt;asp:imageButton ID=&quot;ImageButtonOK&quot; runat=&quot;server&quot; ImageUrl=&quot;~/image.png&quot; /&gt;
&lt;/div&gt;
</pre>
</pre>
<p>Zu beachten ist hier, dass der Button zum Anzeigen des Popup nicht sichtbar ausgeführt wird.<br />
Immerhin soll das Popup, abhängig davon ob sich ein normaler Benutzer oder ein Gast anmeldet, angezeigt werden oder eben nicht.</p>
<p>Die Codebehind-Datei wird wie folgt erweitert.</p>
<pre>
<pre class="brush: vb; ">

Protected Sub LoginUser_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles LoginUser.Authenticate
    If ClassLogIn.CheckUser(Me.LoginUser.UserName, Me.LoginUser.Password)  String.Empty Then
        &#039;Anmeldung ok
        FormsAuthentication.RedirectFromLoginPage(Me.LoginUser.UserName, True)
    Else
        &#039;Anmeldung fehlgeschagen
        e.Authenticated = False
    End If
End Sub
</pre>
</pre>
<p>Diese Sub wird mit dem Drücken des Anmelden Buttons ausgeführt.<br />
ClassLogIn.CheckUser ist eine von mir geschriebene Funktion die die Benutzereingaben prüft.<br />
Sie werden vermutlich eine ähnliche Vorgehensweise gewählt haben, entscheidend für die Authentifizierung des Benutzers ist FormsAuthentication.RedirectFromLoginPage(…).<br />
Dadurch wird der Benutzer angemeldet (authentication) und an die Ursprungsseite weitergeleitet.</p>
<p>Dieses Vorgehen wollen wir, für alle normalen Benutzer unseres Systems, weiterhin nutzen.</p>
<p>Es gilt nun zwischen „normalen Nutzern“ und „Gästen“ zu unterscheiden.<br />
Da FormsAuthentication.RedirectFromLoginPage(..) den Response an die Ursprungsseite weiterleitet eignet sich dieses Vorgehen, zum Anmelden, für das Anzeigen eines ModalPopup nicht.</p>
<p>FormsAuthentication.SetAuthCookie(..) erfüllt unsere Bedürfnisse nach einer Authentifizierung ohne Weiterleitung perfekt. Zu beachten ist hier aber das die Authentifizierung erst vollständig ausgeführt wurde wenn ein Response stattgefunden hat.</p>
<p>Wir teilen die notwendigen Schritte also in zwei Teile auf.<br />
Im ersten Schritt ändern wir unsere Sub von oben ein wenig ab.</p>
<pre>
<pre class="brush: vb; ">

Protected Sub LoginUser_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles LoginUser.Authenticate
    If ClassLogIn.CheckUser(Me.LoginUser.UserName, Me.LoginUser.Password)  String.Empty Then
        &#039;Anmeldung ok
        If ClassLogIn.IsGast(Me.LoginUser.UserName) = True Then
            FormsAuthentication.SetAuthCookie(Me.LoginUser.UserName, True)
            Me.ModalPopupExtenderGastLogInt.Show()
        Else
            FormsAuthentication.RedirectFromLoginPage(Me.LoginUser.UserName, True)
        End If
    Else
        &#039;Anmeldung fehlgeschagen
        e.Authenticated = False
    End If
End Sub
</pre>
</pre>
<p>Eine weitere Funktion prüft ob sich ein Gast oder ein normaler User am System anmelden will.<br />
Handelt es sich um einen Gast, führen wir den ersten Teil der Authentifizierung aus und zeigen das ModalPopup an.</p>
<p>Wird das ModalPopup geschlossen leiten wir den Response an eine andere Seite unseres Systems weiter.<br />
Damit wird der Anmeldevorgang abgeschlossen.</p>
<pre>
<pre class="brush: vb; ">

Protected Sub ImageButtonOK_Click(sender As Object, e As System.Web.UI.ImageClickEventArgs) Handles ImageButtonOK.Click
    Server.Transfer(&quot;~/Default.aspx&quot;)
End Sub
</pre>
</pre>
<p>Einen Nachteil hat das Ganze, ein Gast wird – im Gegensatz zu einem normalen Benutzer - immer auf eine bestimmte Seite (hier Default.aspx) weitergeleitet.</p>
<h3>Über den Autor</h3>
<p><img class="alignleft" src="http://server.bigbasti.com/uploads/uploads/86211149149524767.png" alt="" width="134" height="100" /></p>
<p><strong>Michael   Bernhard</strong><br />
Hobby-Programmierer von VB.NET, C# und   ASP.NET Anwendungen. Hauptberuflich als Inbetriebnehmer bei der <a href="http://www.boewe-systec.de/">Böwe Systec GmbH</a> beschäftigt. Vorzeigbare Projekte – <a href="http://timezonenotifier.free-file-download.de/">TimeZone Notifier</a> und <a href="http://www.tsv-neusaess-junioren.de/">TSV Neusäß Junioren</a>.</p>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1805&amp;md5=872e5d6663ea998c552d53186dc554d1" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/ausgeben-einer-meldung-nach-dem-anmelden-des-benutzers-an-einer-asp-net-webseite-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Anonyme Threaduebergreifende Eventhandler</title>
		<link>http://blog.bigbasti.com/anonyme-threaduebergreifende-eventhandler/</link>
		<comments>http://blog.bigbasti.com/anonyme-threaduebergreifende-eventhandler/#comments</comments>
		<pubDate>Mon, 08 Aug 2011 09:16:20 +0000</pubDate>
		<dc:creator>Sebastian Gross</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.bigbasti.com/?p=1787</guid>
		<description><![CDATA[Jeder von uns uns hatte schon mit Events und den dazugehörigen Handlern zu tun. Jeder Button auf einem Formular hat z.B. einen eigenen Eventhandler, der irgendwo in der Form.Designer.cs definiert und registriert wird. Dieser sieht dann meist ca so aus:

//Registrierung
this.button1.Click += new System.EventHandler(this.button1_Click);
//Verweis / Nutzung
private void button1_Click(object sender, EventArgs e) { }

So wird jedes ...]]></description>
			<content:encoded><![CDATA[<p>Jeder von uns uns hatte schon mit Events und den dazugehörigen Handlern zu tun. Jeder Button auf einem Formular hat z.B. einen eigenen Eventhandler, der irgendwo in der Form.Designer.cs definiert und registriert wird. Dieser sieht dann meist ca so aus:</p>
<pre>
<pre class="brush: csharp; ">

//Registrierung
this.button1.Click += new System.EventHandler(this.button1_Click);
//Verweis / Nutzung
private void button1_Click(object sender, EventArgs e) { }
</pre>
</pre>
<p>So wird jedes Mal wenn des Click-Event der Button-Instanz ausgelöst wird die registrierte Methode button1_Click Ausgeführt. Eigentlich ein schönes und einfaches System, aber wenn man eigene Klassen hat und teilweise viele Instanzen davon bildet ist es unschön, da dabei sehr viele Methoden in der Klasse entstehen und somit  die Übersicht mit der Zeit verloren geht.</p>
<p>Deswegen gibt es für uns die Möglichkeit so genannte anonyme Methoden als EventHandler zu verwenden. Diese benötigen keine Deklaration und haben keine Referenz, somit gehen diese auch verloren, sobald diese zu Ende gelaufen sind. Benutzen kann man diese so:</p>
<pre>
<pre class="brush: csharp; ">

this.button1.Click += delegate(object sender, EventArgs e) {
    //hier steht mein Code
};
</pre>
</pre>
<p>Wie man sieht ist der Code um einiges übersichtlicher geworden und kürzer geworden. Wir übergeben nun eine anonyme Methode als Handler.</p>
<p>Was das ganze noch etwas interessanter macht, ist dass es noch mehr Ersparnis und noch mehr Übersicht bei Threadübergreifenden EventHandlern gibt. Schauen wir uns mal an wie es normalerweise ausschaut:</p>
<pre>
<pre class="brush: csharp; ">

//Registrierung des EventHandler zum anderen Thread
man.NewInformationUpdate += new NewInformationUpdateArrived(update_received);

//Handlermethode
public void update_received(object sender, TestInformationUpdateEventArgs ev) {
    //Aufruf zu dem eigenen Thread deligieren
    this.BeginInvoke(new delegateupdate(update), new object[] { ev });
}

//Definition der delegaten Methode
public delegate void delegateupdate(TestInformationUpdateEventArgs ev);

//Eigentliche Methode zum Verarbeiten des Events
private void update(TestInformationUpdateEventArgs msg) {
//...
}
</pre>
</pre>
<p>Wir haben nun drei Methoden definiert, nur um ein Event zu behandeln, dies ist von Nöten, da wir hier Events verarbeiten, <a title="MSDN" href="http://msdn.microsoft.com/de-de/library/ms171728.aspx">die aus einem anderen Thread kommen</a>.</p>
<p>Hier können wir ebenfalls viel einsparen wenn wir mit delegates und anonymen Methoden arbeiten:</p>
<pre>
<pre class="brush: csharp; ">

fd1.CompletionInformation += delegate(object se, CompletionInformationArgs ci) {
    this.BeginInvoke(new EventHandler(delegate(object obj, EventArgs ea) {
        CompletionInformationArgs cea = (CompletionInformationArgs)ea;

        //Unser verabeitungs Code hier

    }), new object[] { se, ci });
};
</pre>
</pre>
<p>Hier haben wir wieder aus drei Methoden eine gemacht, naja eine richtige zumindest <img src='http://blog.bigbasti.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  und zwei anonyme. Ich finde diese Variante deutlich lesbarer und übersichtlicher, da alle wichtigen Information an einer Stelle sind.</p>
<p>Doch Vorsicht, diese Methode hat einen gravierenden Nachteil, da wir hier anonyme Methoden benutzen haben wir keine Referenz darauf und können somit das registrierte Event nie wieder un-registrieren. Mit anderen Worten, man muss abwegen wann man diese Abkürzung gehen kann und wann nicht.</p>
<p>Meiner Erfahrung nach wird der Fall überwiegen wo man diesen Weg leider nicht gehen kann, aber dann kann man versuchen ein Zwischenweg zu finden:</p>
<pre>
<pre class="brush: csharp; ">

    var handler = new EventHandler(delegate(object o, EventArgs e)
    {
        //handler Logik
    };

    Subject.NewEvent += handler;

    //Diesen können wir später dann auch entfernen
    Subject.NewEvent -= handler;
</pre>
</pre>
<p>Auf diese Weise haben wir immernoch eine Ersparnis und behalten die volle Kontrolle über unsere Handler.</p>
<p>Als kleine (unschöne) Alternative können wir auch anonyme Handler loswerden, indem wir alle Handler entfernen:</p>
<pre>
<pre class="brush: csharp; ">

        public event EventHandler SomeEvent;

        public void ClearEventHandlers() {
            Delegate[] delegates = SomeEvent.GetInvocationList();
            foreach (Delegate delegate in delegates) {
                SomeEvent -= (EventHandler) delegate;
            }
        }
</pre>
</pre>
<p class="wp-flattr-button"></p> <p><a href="http://blog.bigbasti.com/?flattrss_redirect&amp;id=1787&amp;md5=ae87c359471bece49be12972a6e9a395" title="Flattr" target="_blank"><img src="http://blog.bigbasti.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigbasti.com/anonyme-threaduebergreifende-eventhandler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

