<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:easybase="http://www.easybase.de/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
<channel>
	<title>Thomas goes .NET - Blog</title>
	<link>http://blog.thomasbandt.de/</link>
	<description />
	<language>de-de</language>
	<copyright><![CDATA[2008 Thomas Bandt]]></copyright>
	<generator><![CDATA[EasyBase 7.5.1]]></generator>
	
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ThomasGoesNet" /><feedburner:info uri="thomasgoesnet" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item>
<title>Sony Vaio VPCS12V9E/B Review</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2361/de/blog/sony-vaio-vpcs12v9eb-review.html</guid>
<pubDate>Thu, 12 Aug 2010 23:33:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/OGobbgqU5q4/sony-vaio-vpcs12v9eb-review.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="0_Show_Content" class="BlogPostContainer"&gt;
	

    
            &lt;div style="padding-bottom:5px;margin-top:15px;"&gt;
        
            &lt;div style="float: left"&gt;
                &lt;a rel="lightbox[1d035ce1-8670-46a5-8588-e5aea87db370]" title="" href="http://blog.thomasbandt.de/Library/Media/CMS/vaio/IMG_0849_zoomview.JPG"&gt;&lt;img alt=" " title=" " src="http://blog.thomasbandt.de/Library/Media/CMS/vaio/IMG_0849.JPG" style="border-width:0px;height:448px;width:600px;" /&gt;&lt;/a&gt;
             &lt;/div&gt; 
        
           &lt;/div&gt;
           &lt;div style="clear:both"&gt;&lt;/div&gt;
        
    
    &lt;p&gt;Ich schreibe diesen Beitrag auf einem brandneuen Sony Vaio VPCS12V9E/B. Zwar bin ich mit meinem MacBook Late 2008 (13", 2,4 GHz Core2Duo, OCZ Vertex SSD) für den täglichen Gebrauch mehr als zufrieden, in der ein oder anderen Situation habe ich mir dann aber inzwischen doch schon etwas schnellere Hardware gewünscht. Dass ich nun aber schon mehr als anderthalb Jahre das gleiche Notebook besitze (wer mich kennt, weiß, dass das seeeeehr lang ist), rührt aber vor allem daher, dass Apple die Messleite einfach so unglaublich hoch gelegt hat. Ich habe bisher einfach keine brauchbare Alternative bei ähnlicher Qualität gefunden.&lt;/p&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Der Zufall wollte es, dass ich letzte Woche bei Twitter auf eben jedes Sony Vaio aufmerksam wurde. Die Spezifikationen laßen sich prima, also sah ich es mir am Samstag im Laden an. Ersteindruck: hm. Ist halt Plastik. Also ließ ich es stehen und dachte noch ein wenig darüber nach. Vorgestern bestellte ich es dann doch, da ich mir einfach mal direkt ein Bild machen wollte. Nun steht es vor mir. Ich gehe es mal im Detail durch, soweit das nach einer Stunde möglich ist.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Optik&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Definitiv Geschmackssache. Stünde es nur alleine vor mir und hätte ich noch nie ein MacBook gesehen, ich würde sagen es ist okay. Durch die Magnesiumlegierung und die Riffelung der Oberfläche der vorderen Handauflageflächen sieht es schon ganz gut aus. Stellt man es allerdings neben ein MacBook, fällt auf, dass es doch ganz schön dick ist, im Verhältnis zur Größe (13 Zoll).&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Verarbeitung&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Es ist un bleibt Plastik, Punkt. Gegen das Unibody-Gehäuse des MacBooks kann es einfach nicht anstinken. Der Displayrahmen ist nicht richtig versteift, die rechte Handauflagefläche lässt sich durchdrücken und mit einem nervösen Finger kann man durch beharrliches Tippen auf die DVD-Laufwerks-Abdeckung seine Umwelt gehörig Nerven kosten.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Tastatur&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Optisch nicht ganz so straight wie die des Macs, allerdings von Verarbeitung, Anschlag und auch der Beleuchtung her top. Insbesondere die Größen der Tasten sagen mir zu, mit zehn Fingern tippt es sich jedenfalls wunderbar. Und als Windows-User auch nicht zu verachten: ein Windows-Layout ;-).&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Display&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Für mich eine einzige Enttäuschung, da von den blumigen Werbeversprechen nicht viel übrig bleibt. Die Blickwinkelstabilität ist nicht existent, die Helligkeit nur dann in Ordnung, wenn man keinen direkten Vergleich hat.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;img src="http://blog.thomasbandt.de/Library/Media/CMS/vaio/IMG_0850.JPG" alt="" /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Touchpad&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;Man weiß beim Multitouchpad des MacBooks erst, was man an ihm hat, wenn man mal wieder ein gewöhnliches Trackpad benutzen muss. Zwar kann das Sony wohl auch Gestensteuerrung, allerdings ist das in der Qualität nicht annähernd zu vergleichen. Alleine ein Doppelklick mit zwei Fingern oder das Scrollen damit fehlt mir - hier habe ich am wenigsten Lust, mich umzugewöhnen.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Die gefühlte Performance ist schlecht. Das ist allerdings rein subjektiv und mag daran liegen, dass ich sowohl im MacBook als auch meinem "richtigen" Rechner im Büro seit mehr als einem Jahr mit SSDs arbeite. Festplatten waren, sind und bleiben einfach die Flaschenhälse. Für den Alltag ist es einfach völlig wurscht wieviel Power die CPU theoretisch hat, wenn das Starten des Systems aufgrund der lahmen Platte ein Vielfaches der Zeit eines Systems mit SSD braucht. Das ist dann auch der Grund, warum mir mein bald knapp zwei Jahre altes MacBook aus dem Stand noch schneller vorkommt. Bei CPU- und Speicher-lastigen Sachen wie Spielen wird sich der Eindruck natürlich nicht halten können.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Emissionen&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Der für mich bei jedem Notebook definitiv wichtigste Punkt (gleich neben dem Design ;-)) sind die Emissionen. Weniger die Wärmeentwicklung, die kann ich an vielen Stellen verschmerzen. Wichtiger ist mir die Geräuschentwicklung. Nach mehr als 15 Minuten CPU-Dauerauslastung durch Prime95 lässt sich sagen: Aufgabe bestanden. Der Lüfter sprang sofort an und lief hörbar, aber nicht störend. Nachdem ich Prime95 stoppte, fuhr er auch sofort wieder herunter.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Während ich das tippe ist das Gerät nun seit einigen Minuten im normalen Betriebsmodus. Hier muss ich leider sagen, dass der Lüfter ständig leicht zu hören ist - nicht so beim MacBook.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Fazit&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Für 1.200 EUR brutto erhält man ein solides Business-Notebook mit einer akzeptablen Verarbeitung und insgesamt doch sehr ordentlichem Preis-/Leistungsverhältnis. Für mich jedoch sind die Vorteile nicht überzeugend genug, um mich vom MacBook zu lösen. Ich hätte einfach das Gefühl einen Rückschritt zu machen, nicht zuletzt bei Verarbeitung (Unibody, Alu) und Design. Daher wandert das Sony nun wieder zurück in die Kiste und zum Händler. Ich muss wohl noch länger suchen und dann wohl auch tiefer in die Tasche greifen - oder einfach auf die nächste MacBook-Generation warten.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;Aber einen Versuch war es wert.&lt;/div&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2361/de/blog/sony-vaio-vpcs12v9eb-review.html&amp;title=Sony+Vaio+VPCS12V9E%2fB+Review"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2361%2fde%2fblog%2fsony-vaio-vpcs12v9eb-review.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2361/de/blog/sony-vaio-vpcs12v9eb-review.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=1d035ce1-8670-46a5-8588-e5aea87db370" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2361/de/blog/sony-vaio-vpcs12v9eb-review.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/OGobbgqU5q4" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2361/de/blog/sony-vaio-vpcs12v9eb-review.html</feedburner:origLink></item> 
<item>
<title>Windows wins</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2360/de/blog/windows-wins.html</guid>
<pubDate>Tue, 10 Aug 2010 21:43:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/zGckeMuh_m0/windows-wins.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="1_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Es gab da vor vier Jahren einen Moment, in dem ich am liebsten alle Microsoft-Produkte weggeschmissen hätte. Das war die Zeit vor dem Launch von Windows Vista, als man in Redmond intensiv darüber nachdachte eine Art Wegwerf-Lizenz zu entwickeln, mit der man sein Windows nach einem Kauf nur noch 3x aktivieren konnte. Meine Wut darüber ging sogar soweit, dass ich mich kurz mit Java als Alternative zu .NET beschäftigte (von Mono war damals noch nicht wirklich zu sprechen) ;-).&lt;/p&gt;
&lt;p&gt;Microsoft knickte nach einem Sturm der Entrüstung ein und veröffentlichte Vista schließlich unter einer Lizenz, wie man sie kannte. Was ihnen freilich auch nicht viel half – denn Vista war einfach nur träge, bunt und kein wirklicher Fortschritt. Der einzige Grund, warum ich es durchgängig einsetzte, war die Tatsache, dass Windows XP einfach schon steinalt und unsicher war.&lt;/p&gt;
&lt;p&gt;So machte es mir Microsoft mit Vista Ende 2008 auch einigermaßen leicht, einen Blick nach Cupertino zu werfen. Mein erster Versuch anno 2006 war mehr oder minder kläglich gescheitert, aber durch die Liebe auf den zweiten Blick für das Alu MacBook bekam Apple seine zweite Chance.&lt;/p&gt;
&lt;p&gt;Immer noch von dem Gedanken der Unabhängigkeit von Microsoft beseelt fing ich dann auch an OS X aktiv und intensiv als mein primäres Betriebssystem zu Hause und unterwegs zu verwenden. Wenn ich nun schon einen Mac hatte, wollte ich schließlich auch Mac OS verwenden. Das klappte auch – zwar musste ich für allerhand unter Windows gratis zu habende Utilities einiges zahlen, aber unterm Strich war ich fast eineinhalb Jahre sehr zufrieden.&lt;/p&gt;
&lt;p&gt;Nun wurde in dieser Zeit das unglückliche Windows Vista durch Windows 7 abgelöst, auch auf all meinen Rechnern. Nutzte ich es anfangs auch auf dem MacBook zunächst via VM und später via Bootcamp noch parallel zu OS X, kam dann vor ein paar Monaten der Zeitpunkt, Apple wieder tschüss zu sagen.&lt;/p&gt;
&lt;p&gt;Ich kann bis heute die Ursache nicht genau benennen, aber irgendwie vertrug meine OS-X-Installation das bootcampen nicht und ich war gezwungen alle paar Tage ein Backup (via TimeMachine ein Traum) einzuspielen. Irgendwann riss mir dann die Hutschnur und ich beschloss nur noch Windows 7 zu verwenden.&lt;/p&gt;
&lt;p&gt;Nun bin ich immer noch durch meine Entwicklung mit .NET und Visual Studio sehr „Windows-addicted“ und das auch während der Nutzung von OS-X die ganze Zeit gewesen. Aber wie bereits geschrieben fand ich den Gedanken mehrgleisig zu fahren immer sehr reizvoll.&lt;/p&gt;
&lt;p&gt;Das relativierte sich dann mit Windows 7 immer mehr. Heute bin ich an dem Punkt wo ich sage: Windows 7 ist nicht nur das beste Betriebssystem, dass Microsoft je veröffenlticht hat, es ist auch das bessere System im Vergleich zu Snow Leopard.&lt;/p&gt;
&lt;p&gt;Dabei sind es vor allem die kleinen Dinge, die meine Produktivität einfach unglaublich steigern. Ob es das im Vergleich zu allen Mac-Lösungen viel funktionsreichere und effizientere Startmenü ist, der Windows Explorer mit seinen Favoriten (der Finder ist furchtbar umständlich im Vergleich) oder die Vorschau in der Windows-Taskleiste sowie die darüber erreichbaren gruppierten Instanzen einzelner Anwendungen (auch hier: das Dock löst das furchtbar umständlich!).&lt;/p&gt;
&lt;p&gt;Es sind Kleinigkeiten die das Leben leichter machen – wie so oft. &amp;nbsp;Natürlich bleiben Schattenseiten. Etwa die Höhe der Lizenzkosten, hier stellt sich Apple einfach viel geschickter gegenüber Privatkunden an (allerdings verdienen sie mit Software auch nicht ihr Geld, Microsoft schon). Und auch ein paar Features werde ich vermissen, beispielsweise das angesprochene Time Machine. Zwar nutze ich inzwischen Acronis 2010, was eine funktionierende „Nonstop Backup“-Funktion mitbringt, aber so bequem wie mit Time Machine ist es nunmal nicht.&lt;/p&gt;
&lt;p&gt;Aber trotzdem: Windows wins. Zumindest in dieser Runde – und ich bin mir sicher, es werden noch viele folgen.&lt;/p&gt;
&lt;p&gt;P.s.: Ich finde fast nichts peinlicher als Microsoft-Fanboys, wollte das aber mal gesagt haben ;-).&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2360/de/blog/windows-wins.html&amp;title=Windows+wins"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2360%2fde%2fblog%2fwindows-wins.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2360/de/blog/windows-wins.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=c038f749-1a5b-4c79-8bb5-9f42fe28ebba" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2360/de/blog/windows-wins.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/zGckeMuh_m0" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2360/de/blog/windows-wins.html</feedburner:origLink></item> 
<item>
<title>IIS 7.x - Uploadlimits konfigurieren</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2359/de/blog/iis-7x-uploadlimits-konfigurieren.html</guid>
<pubDate>Fri, 06 Aug 2010 16:19:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/FqB9z7-mkcI/iis-7x-uploadlimits-konfigurieren.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="2_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Auch so ein Thema, dass mich mit jeder neuen Technologie-Generation für kleine Aufgaben stellt, solange ich denken kann, ist das Uploaden von Dateien auf den Webserver. Die Zeiten, in denen man dafür COM-Komponenten benötigte (Classic ASP) sind zum Glück vorbei, aber Microsoft lässt sich immer wieder was Neues einfallen, damit es auch spannend bleibt.&lt;/p&gt;
&lt;p&gt;Da mit den Internet Information Services 7&amp;nbsp;die Konfiguration größtenteils in die Machine.config und Web.config gewandert ist, muss die maximale Größe für Dateiuploads pro Request (= Upload) nun auch dort eingestellt werden. Und zwar an zwei Stellen. Einmal in Bytes und einmal in ... genau, Kilobytes.&lt;/p&gt;
&lt;p&gt;Nehmen wir also an, das Limit läge bei 100 MB. Dann sähe die Config wie folgt aus:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="UTF-8"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.web&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;httpRuntime&lt;/span&gt; &lt;span class="attr"&gt;maxRequestLength&lt;/span&gt;&lt;span class="kwrd"&gt;="102400"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.web&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.webServer&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestFiltering&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestLimits&lt;/span&gt; &lt;span class="attr"&gt;maxAllowedContentLength&lt;/span&gt;&lt;span class="kwrd"&gt;="104857600"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;requestFiltering&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.webServer&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Da wusste die linke Hand wohl nicht, was die rechte ...&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2359/de/blog/iis-7x-uploadlimits-konfigurieren.html&amp;title=IIS+7.x+-+Uploadlimits+konfigurieren"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2359%2fde%2fblog%2fiis-7x-uploadlimits-konfigurieren.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2359/de/blog/iis-7x-uploadlimits-konfigurieren.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=356af2c7-144f-4269-b370-387fdae90694" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2359/de/blog/iis-7x-uploadlimits-konfigurieren.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/FqB9z7-mkcI" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2359/de/blog/iis-7x-uploadlimits-konfigurieren.html</feedburner:origLink></item> 
<item>
<title>Installationsbefehl: Visual Studio Productivity Power Tools</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2358/de/blog/installationsbefehl-visual-studio-productivity-power-tools.html</guid>
<pubDate>Thu, 05 Aug 2010 22:52:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/aMcS5iBJCkE/installationsbefehl-visual-studio-productivity-power-tools.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="3_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Ich bin gerade beim Abarbeiten meiner abonnierten RSS-Feads an einem Post von Scott Guthrie hängengeblieben, in dem er die Productivity Power Tools vorstellt. Irgendwo hatte ich davon neulich schon etwas aufgeschnappt, also habe ich sie mal installiert und nochmal Visual Studio gestartet.&lt;/p&gt;
&lt;p&gt;Schon nach einigen Sekunden stand mir der Mund weit offen. Ehrlich gesagt verstehe ich gerade nicht, wie ich bisher darauf verzichten konnte!? Bisher dachte ich dass Jetbrains mit ReSharper das Maß aller Dinge hinsichtlich Visual-Studio-Erweiterungen darstellt, aber hier hat Microsoft selbst nochmal einen rausgehauen, der es in sich hat.&lt;/p&gt;
&lt;p&gt;Lieblingsfeatures: Der Solution Navigator (wow!), Das Verschieben ganzer Code-Zeilen oder Fragmente per ALT+Pfeiltasten, der durchsuchbare Add-Reference-Dialog, pinnbare und farblich markierte Tabs. Scott hat es alles schon schön vorgestellt, daher spare ich mir die Details und verweise auf seine Posts:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2010/08/04/some-nice-code-editor-features-provided-by-the-vs-2010-power-tool-extensions.aspx"&gt;Some nice code editor features provided by the VS 2010 Power Tool Extensions&lt;/a&gt; &lt;/li&gt;
    &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2010/06/09/visual-studio-2010-productivity-power-tool-extensions.aspx"&gt;Visual Studio 2010 Productivity Power Tool Extensions&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2010/07/19/vs-2010-productivity-power-tools-update-with-some-cool-new-features.aspx"&gt;VS 2010 Productivity Power Tools Update (with some cool new features)&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://visualstudiogallery.msdn.microsoft.com/en-us/d0d33361-18e2-46c0-8ff2-4adea1e34fef"&gt;Installieren und staunen&lt;/a&gt;! :-)&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2358/de/blog/installationsbefehl-visual-studio-productivity-power-tools.html&amp;title=Installationsbefehl%3a+Visual+Studio+Productivity+Power+Tools"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2358%2fde%2fblog%2finstallationsbefehl-visual-studio-productivity-power-tools.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2358/de/blog/installationsbefehl-visual-studio-productivity-power-tools.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=6515eaea-7444-46f1-9cf7-ab353892426d" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2358/de/blog/installationsbefehl-visual-studio-productivity-power-tools.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/aMcS5iBJCkE" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2358/de/blog/installationsbefehl-visual-studio-productivity-power-tools.html</feedburner:origLink></item> 
<item>
<title>ASP.NET MVC - Wiederverwendbarer Pager</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2357/de/blog/aspnet-mvc-wiederverwendbarer-pager.html</guid>
<pubDate>Thu, 05 Aug 2010 15:34:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/96ByBzDiZXk/aspnet-mvc-wiederverwendbarer-pager.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="4_Show_Content" class="BlogPostContainer"&gt;
	

    
            &lt;div style="padding-bottom:5px;margin-top:15px;"&gt;
        
            &lt;div style="float: left"&gt;
                &lt;a rel="lightbox[74d7b696-9892-49c6-8095-4986e7f7b39e]" title="" href="http://blog.thomasbandt.de/Library/Media/CMS/pager_zoomview.PNG"&gt;&lt;img alt=" " title=" " src="http://blog.thomasbandt.de/Library/Media/CMS/pager.PNG" style="border-width:0px;height:305px;width:600px;" /&gt;&lt;/a&gt;
             &lt;/div&gt; 
        
           &lt;/div&gt;
           &lt;div style="clear:both"&gt;&lt;/div&gt;
        
    
    &lt;p&gt;Das Thema Paging (Deutsch: "Blättern") ist wohl so alt wie das World Wide Web, schließlich kann man den Usern&amp;nbsp;große Listen von Daten so gut wie nie in einem Rutsch zumuten. Im aktuellen Projekt war es dann auch mal wieder so weit, Daten wollten seitenweise angezeigt und durchnavigiert werden.&lt;/p&gt;
&lt;p&gt;Jetzt stand ich vor der Wahl ein noch aus WebForms-Zeiten stammendes, gut funktionierendes, Custom-Control zu verwenden, oder es "im MVC Style" zu machen. Irgendwie müssen ja Custom-Controls dann doch nicht mehr sein ;-). Ich stieß auf &lt;a href="http://code-inside.de/blog/2008/04/01/aspnet-mvc-paging-implementieren/"&gt;einen alten Beitrag von Robert von 2008&lt;/a&gt;. Seine Lösung gefielt mir damals gar nicht, irgendwie sah der Code etwas nach Nudeltopf aus. Allerdings habe ich mit dieser Art von Spaghetti-Code zu leben gelernt und finde ihn inzwischen nicht mehr wirklich schlimm. Zumindest nicht schlimmer als klassische Server-Controls mit ihren fünfhundert Templates, Attributen usw. Und die Grundlage, das Snippet von Rob Conery, habe ich so auch &lt;a href="http://blog.thomasbandt.de/39/2218/de/blog/linq-to-sql-pager-extension.html"&gt;bereits verwendet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also habe ich seinen Code als Basis hergenommen und so modifiziert, dass ich einen im gesamten Projekt wiederverwendbaren Pager bekommen habe, den ich als Partial View überall einsetzen kann.&lt;/p&gt;
&lt;p&gt;Erste Änderung: Die Properties sind aus der PagedList- in eine PagerInfo-Klasse gewandert. Somit lassen sie sich losgelöst von den eigentlichen Daten für die Generierung des Pagers verwenden, und zwar unabhängig vom verwendeten Typ der Objekte in der Liste.&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PagedList&amp;lt;T&amp;gt; : List&amp;lt;T&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; PagedList(IQueryable&amp;lt;T&amp;gt; source, &lt;span class="kwrd"&gt;int&lt;/span&gt; index, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        PagerInfo = &lt;span class="kwrd"&gt;new&lt;/span&gt; PagerInfo();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        PagerInfo.TotalCount = source.Count();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        PagerInfo.PageSize = pageSize;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        PagerInfo.PageIndex = index;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        PagerInfo.TotalPages = PagerInfo.TotalCount / pageSize;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (PagerInfo.TotalCount % pageSize &amp;gt; 0)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            PagerInfo.TotalPages++;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        AddRange(source.Skip((index - 1) * pageSize).Take(pageSize).ToList());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; PagerInfo PagerInfo { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PagerInfo&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalPages { get; set; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalCount { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PageIndex { get; set; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PageSize { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasPreviousPage { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (PageIndex &amp;gt; 1); } }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasNextPage { get { &lt;span class="kwrd"&gt;return&lt;/span&gt; (PageIndex * PageSize) &amp;lt;= TotalCount; } }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Als zweites habe ich einen entsprechenden Partial View angelegt, der das Rendern des Pagers übernimmt:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="pager"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (Model.PagerInfo.HasPreviousPage) { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="previous"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="&amp;lt;%= Url.Action(Model.Action, Model.Controller, new { page = Model.PagerInfo.PageIndex - 1 }) %&amp;gt;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;« Zurück&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; } &lt;span class="kwrd"&gt;else&lt;/span&gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="previous-off"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;« Zurück&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; } &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; page = 1; page &amp;lt;= Model.PagerInfo.TotalPages; page++) {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (page == Model.PagerInfo.PageIndex) { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="active"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;=page.ToString()&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; } &lt;span class="kwrd"&gt;else&lt;/span&gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="&amp;lt;%= Url.Action(Model.Action, Model.Controller, new { page }) %&amp;gt;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= page &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        } &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (Model.PagerInfo.HasNextPage) { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="next"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="&amp;lt;%= Url.Action(Model.Action, Model.Controller, new { page = Model.PagerInfo.PageIndex + 1 }) %&amp;gt;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Weiter »&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; } &lt;span class="kwrd"&gt;else&lt;/span&gt; { &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="next-off"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Weiter »&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; } &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Das Model beinhaltet nicht nur die "PagerInfo" sondern auch die Namen des Controllers und der Action, so dass das Ganze wiederverwendbar wird:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PagerViewModel&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; PagerInfo PagerInfo { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Controller { get; set; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Action { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Das war's im Prinzip schon, das Ergebnis kann man oben sehen. Zum Stylen kann ich genau wie Robert damals&amp;nbsp;&lt;a href="http://woork.blogspot.com/2008/03/perfect-pagination-style-using-css.html"&gt;auf diesen Blogpost verweisen&lt;/a&gt; :-).&lt;/p&gt;
&lt;p&gt;Anbei das Ganze als ausführbare MVC2-App.&lt;/p&gt;


    
            &lt;h2&gt;Downloads&lt;/h2&gt;
            &lt;ul&gt;
        
           &lt;li&gt;
                &lt;a id="4_ListDownloads_ctl01_LinkDownload" href="http://blog.thomasbandt.de/Download.ashx?File=9827720d-a82e-4474-841b-ce80f3bca822"&gt;MvcPaging.zip&lt;/a&gt; (35,1 KB)
                
            &lt;/li&gt;
        
            &lt;/ul&gt;
        
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2357/de/blog/aspnet-mvc-wiederverwendbarer-pager.html&amp;title=ASP.NET+MVC+-+Wiederverwendbarer+Pager"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2357%2fde%2fblog%2faspnet-mvc-wiederverwendbarer-pager.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2357/de/blog/aspnet-mvc-wiederverwendbarer-pager.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=74d7b696-9892-49c6-8095-4986e7f7b39e" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2357/de/blog/aspnet-mvc-wiederverwendbarer-pager.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/96ByBzDiZXk" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2357/de/blog/aspnet-mvc-wiederverwendbarer-pager.html</feedburner:origLink></item> 
<item>
<title>ASP.NET MVC - Formulare per Ajax verarbeiten</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2356/de/blog/aspnet-mvc-formulare-per-ajax-verarbeiten.html</guid>
<pubDate>Wed, 28 Jul 2010 12:03:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/mJbdO5IjpC8/aspnet-mvc-formulare-per-ajax-verarbeiten.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="5_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Disclaimer: Ich bin kein Ajax-Entwickler. Als das Thema vor 5 Jahren auf den Tisch kam, hatte ich schon einige Jahre mit XmlHttpRequest im Internet Explorer gearbeitet, aber mich eigentlich schwerpunktmäßig immer auf die Serverseite konzentriert. Das hat sich auch bis heute noch nicht groß geändert - ich arbeite zwar mit jQuery, mootools und auch noch klassisch nativem JavaScript, aber meist wirklich nur für das Nötigste.&lt;/p&gt;
&lt;p&gt;In normalen Formularen gehe ich was die Überprüfung der Eingaben angeht&amp;nbsp;bislang recht klassisch vor - die&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2327/de/blog/validierung-gehoert-in-den-business-layer.html"&gt;Validierung findet im Service&lt;/a&gt; und damit auf der Serverseite statt. Sicherheit geht nunmal über alles. Entsprechend stiefmütterlich habe ich dann aber auch die clientseitige Validierung bisher behandelt.&lt;/p&gt;
&lt;p&gt;Nun bin ich aber gestern zu einem Punkt gekommen, bei dem ich nur zwei Alternativen habe:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Eine vernünftige Lösung mit Ajax und/oder einem&amp;nbsp;Client-Validation-Framework&amp;nbsp;bauen.
    &lt;li&gt;Etwas serverseitiges und für den User schlecht benutzbares zusammenfrickeln. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Es geht um einen Dateiupload, genauer einen Multi-File-Upload, wie man ihn z.B. mit&amp;nbsp;&lt;a href="http://swfupload.org/"&gt;swfupload&lt;/a&gt; oder&amp;nbsp;&lt;a href="http://www.uploadify.com/"&gt;uploadify&lt;/a&gt; verwirklichen kann. Dieser Upload ist in ein normales Formular eingebettet, was einige Pflichtfelder besitzt. Wählt der Nutzer nun also Dateien aus und vergisst aber eines der Pflichtfelder auszufüllen und schickt das Formular ab - dann sind nach dem Roundtrip zum Server die ausgewählten Dateien wieder weg.&lt;/p&gt;
&lt;p&gt;Keine gute Sache für den User. Also sollte der Workflow so aussehen:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Formular ausfüllen
    &lt;li&gt;Dateien auswählen
    &lt;li&gt;Formular überprüfen
    &lt;li&gt;Ggf. Eingaben korrigieren
    &lt;li&gt;Bei erfolgreichem Ausfüllen Formular abschicken und&amp;nbsp;Hauptdatensatz anlegen
    &lt;li&gt;Anschließend die Dateien hochladen und dem Hauptdatensatz zuordnen &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dafür gibt es zwei brauchbare Wege (die mir einfallen):&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ajax&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Validierung und Erzeugung des Hauptdatensatzes erfolgt per Ajax. Wenn dies geklappt hat, wird der Upload der ausgewählten Dateien angestoßen. Vorteil: die ID des Datensatzes steht hier vor dem Upload bereits zur Verfügung.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Client-Validation-Framework&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Die Validierung erfolgt zusätzlich zur Serverseite, wo sie weiter obligatorisch bleibt,&amp;nbsp;clientseitig, zum Beispiel mit dem &lt;a href="http://docs.jquery.com/Plugins/Validation"&gt;jQuery-Validation-Plugin&lt;/a&gt;&amp;nbsp;oder den Tools, die ASP.NET MVC dafür bereits mitbringt. Nachteile: doppelte Konfiguration (vernachlässigbar), im Zweifel verschieden aussehende Ausgaben der Fehler client-/serverseitig&amp;nbsp;(vernachlässigbar), die ID des Hauptdatensatzes steht hier beim Dateiupload noch nicht zur Verfügung, da erst die Dateien hochgeladen müssen und dann der POST erfolgen kann.&lt;/p&gt;
&lt;p&gt;Ein schwieriges Thema, bei dem wirklich hunderttausende Wege nach Rom führen. In Sachen Ajax stört mich der meist enorme Overhead. Ich habe relativ wenig Lust die Ausgabe der Fehler "zu synchronisieren".&lt;/p&gt;
&lt;p&gt;Ein brauchbarer Weg erschien mir aber der von Jarrett Vance in seinem Post "&lt;a href="http://jvance.com/blog/2010/02/20/MakingAnAjaxFormWithJQueryInASPdotNETMVC.xhtml"&gt;Making an Ajax Form with jQuery in ASP.NET MVC&lt;/a&gt;" aufgezeigte. Vorteil: die Ausgabe bleibt exakt die gleiche, man muss sie nicht doppelt pflegen. Zudem braucht es auch keinen großen Aufwand auf der Client-Script-Seite. Nachteil: die Formulare müssen in PartialViews ausgelagert werden.&lt;/p&gt;
&lt;p&gt;Ich habe es allerdings mal als Grundlage für eine Demo genommen und seinen Ansatz für meine Zwecke erweitert.&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;[HttpPost]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;[ValidateAntiForgeryToken]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult CreateTask(TaskViewModel model)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="rem"&gt;// DEMO - Validierung wird im Service/BLL ausgeführt&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(model.Name))&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        ModelState.AddModelError(&lt;span class="str"&gt;"Name"&lt;/span&gt;, &lt;span class="str"&gt;"Bitte geben Sie einen Namen an."&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(model.Text))&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        ModelState.AddModelError(&lt;span class="str"&gt;"Text"&lt;/span&gt;, &lt;span class="str"&gt;"Bitte geben Sie einen Text an."&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ModelState.IsValid)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;        TempData[&lt;span class="str"&gt;"Success"&lt;/span&gt;] = &lt;span class="str"&gt;"Task erfolgreich angelegt."&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt;(Request.IsAjaxRequest())&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt;(ModelState.IsValid)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Json(&lt;span class="kwrd"&gt;new&lt;/span&gt; AjaxOperationResultInfo { Successfull = &lt;span class="kwrd"&gt;true&lt;/span&gt;, RedirectUrl = Url.Action(&lt;span class="str"&gt;"index"&lt;/span&gt;) });&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; PartialView(&lt;span class="str"&gt;"CreateTaskForm"&lt;/span&gt;, model);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt;(ModelState.IsValid)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; RedirectToAction(&lt;span class="str"&gt;"index"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; View(model);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Nur wenn es ein Ajax-Request ist, wird der PartialView zurückgegeben. Ansonsten, also in allen Fällen, in denen JavaScript im Browser deaktiviert ist, gibt es den normalen View zurück. Damit funktioniert der Spaß auch bei deaktiviertem JavaScript.&lt;/p&gt;
&lt;p&gt;Nun ein Kompromiss:&lt;/p&gt;
&lt;p&gt;Wenn ein Fehlerauftritt, wird der PartialView zurückgegeben. Wenn die Sache allerdings erfolgreich war, gebe ich ein JSON-Ergebnis zurück. Das ist zwar nicht astrein, erlaubt mir dann aber auf der Clientseite weitere Entscheidungen zu treffen. Im Beispiel übergebe ich die Ziel-URL, auf die nach erfolgreichem Verarbeiten des Formulars weitergeleitet werden soll. In meinem Praxisfall würde ich noch die ID des angelegten Datensatzes übergeben, damit diese beim Upload der Dateien gleich verwendet würden könnte.&lt;/p&gt;
&lt;p&gt;Der JS-Code bleibt übersichtlich:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;$(document).ready(function () {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    $(&lt;span class="str"&gt;'#ajaxForm form'&lt;/span&gt;).live(&lt;span class="str"&gt;'submit'&lt;/span&gt;, function () {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        $.post($(&lt;span class="kwrd"&gt;this&lt;/span&gt;).attr(&lt;span class="str"&gt;'action'&lt;/span&gt;), $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).serialize(), function (result) {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; ($.isString(result)) {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                $(&lt;span class="str"&gt;"#ajaxForm"&lt;/span&gt;).replaceWith($(result));&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (result[&lt;span class="str"&gt;"Successfull"&lt;/span&gt;]) {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                window.location.href = result[&lt;span class="str"&gt;"RedirectUrl"&lt;/span&gt;];&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;            }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                alert(&lt;span class="str"&gt;'Es ist ein Fehler aufgetreten. Bitte benachrichtigen Sie den Codemonkey.'&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        });&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    });&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;});&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;jQuery.isString = function (o) {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;typeof&lt;/span&gt; o === &lt;span class="str"&gt;"string"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Die komplette Projektmappe habe ich mal angehangen.&lt;/p&gt;
&lt;p&gt;Unterm Strich bleibt es ein scheinbar brauchbarer Weg, richtig glücklich bin ich damit aber noch nicht. Ich werde als nächstes mal jQuery Validation testen&amp;nbsp;sowie die DataAnnotations wieder ausgraben, rein für die clientseitige-Validierung.&lt;/p&gt;


    
            &lt;h2&gt;Downloads&lt;/h2&gt;
            &lt;ul&gt;
        
           &lt;li&gt;
                &lt;a id="5_ListDownloads_ctl01_LinkDownload" href="http://blog.thomasbandt.de/Download.ashx?File=613b5301-079e-47d4-a899-b04d24d5c7ff"&gt;MvcApplication8.zip&lt;/a&gt; (110,72 KB)
                
            &lt;/li&gt;
        
            &lt;/ul&gt;
        
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2356/de/blog/aspnet-mvc-formulare-per-ajax-verarbeiten.html&amp;title=ASP.NET+MVC+-+Formulare+per+Ajax+verarbeiten"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2356%2fde%2fblog%2faspnet-mvc-formulare-per-ajax-verarbeiten.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2356/de/blog/aspnet-mvc-formulare-per-ajax-verarbeiten.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=2cf12906-c026-469c-bfc6-ee45ca132e36" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2356/de/blog/aspnet-mvc-formulare-per-ajax-verarbeiten.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/mJbdO5IjpC8" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2356/de/blog/aspnet-mvc-formulare-per-ajax-verarbeiten.html</feedburner:origLink></item> 
<item>
<title>ASP.NET MVC - TextBox für mobile Browser anpassen</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2355/de/blog/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html</guid>
<pubDate>Thu, 22 Jul 2010 13:29:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/aO83ZBL8MiI/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="6_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Im Vorgriff auf HTML 5 unterstützen viele mobile Browser bereits die neuen Input Types für Formular-Elemente, z.B. &lt;a href="http://www.w3.org/TR/html-markup/input.email.html"&gt;type="email"&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Solange man nur für Desktop-Browser Websites erstellt, spielt das bislang keine Rolle.Interessant wird es für alle Szenarien, in denen keine physische Tastatur zur Verfügung steht - also z.B. für die Nutzer des iPad oder von Smartphones. Der Grund: je nach angegebenem Input Type wechselt das Tastaturlayout der Bildschirmtastatur. &lt;/p&gt;
&lt;p&gt;Beispiel: hier sind die 3 verschiedene Felder eines Formulars aufgezeigt. Das erste ist ein Standard-Textfeld, das zweite erwartet eine E-Mail-Adresse und das dritte eine Telefonnummer, entsprechend sind auch die Input Types gesetzt (text, email, number).&lt;/p&gt;
&lt;img alt="" src="http://blog.thomasbandt.de/Library/Media/CMS/mobilekeyboard.png" /&gt;
&lt;p&gt;Eine wirkliche Erleichterung für den Nutzer, da das Umschalten zwischen den einzelnen Ebenen der Tastatur nerven kann und es umso praktischer ist, wenn man die sowieso benötigten Zeichen, wie eben das @-Zeichen für E-Mail-Adressen oder Zahlen für Telefonnummern standardmäßig eingeblendet hat.&lt;/p&gt;
&lt;p&gt;Die dargestellte Website läuft (noch) mit ASP.NET MVC 1.0, weshalb ich hierfür eine entsprechende Erweiterung geschrieben habe, die Textboxen mit beliebigen Input Types (als String) verarbeiten kann.&lt;/p&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MobileTextBox(&lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper html, &lt;span class="kwrd"&gt;string&lt;/span&gt; name, &lt;span class="kwrd"&gt;string&lt;/span&gt; inputType, &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;object&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt; htmlAttributes)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (html.ViewData.ModelState.ContainsKey(name))&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        &lt;span class="kwrd"&gt;value&lt;/span&gt; = html.ViewData.ModelState.Single(s =&amp;gt; s.Key == name).Value.Value.AttemptedValue;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    TagBuilder tagBuilder = &lt;span class="kwrd"&gt;new&lt;/span&gt; TagBuilder(&lt;span class="str"&gt;"input"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    tagBuilder.MergeAttribute(&lt;span class="str"&gt;"name"&lt;/span&gt;, name);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    tagBuilder.MergeAttribute(&lt;span class="str"&gt;"type"&lt;/span&gt;, inputType);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    tagBuilder.MergeAttribute(&lt;span class="str"&gt;"value"&lt;/span&gt;, (&lt;span class="kwrd"&gt;string&lt;/span&gt;)&lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    tagBuilder.MergeAttributes(&lt;span class="kwrd"&gt;new&lt;/span&gt; RouteValueDictionary(htmlAttributes));&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; tagBuilder.ToString(TagRenderMode.SelfClosing);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Anwendung:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= Html.MobileTextBox(&lt;span class="str"&gt;"email"&lt;/span&gt;, &lt;span class="str"&gt;"email"&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; { @&lt;span class="kwrd"&gt;class&lt;/span&gt; = &lt;span class="str"&gt;"CssTextInput"&lt;/span&gt; })&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= Html.MobileTextBox(&lt;span class="str"&gt;"telephone"&lt;/span&gt;, &lt;span class="str"&gt;"number"&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; { @&lt;span class="kwrd"&gt;class&lt;/span&gt; = &lt;span class="str"&gt;"CssTextInput"&lt;/span&gt; })&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2355/de/blog/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html&amp;title=ASP.NET+MVC+-+TextBox+f%c3%bcr+mobile+Browser+anpassen"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2355%2fde%2fblog%2faspnet-mvc-textbox-fuer-mobile-browser-anpassen.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2355/de/blog/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=6750f6d1-dfaf-403a-bbae-15a0c8850dc1" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2355/de/blog/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/aO83ZBL8MiI" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2355/de/blog/aspnet-mvc-textbox-fuer-mobile-browser-anpassen.html</feedburner:origLink></item> 
<item>
<title>iPhone 4 Review</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2354/de/blog/iphone-4-review.html</guid>
<pubDate>Tue, 20 Jul 2010 00:46:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/EaHwxXNMq7I/iphone-4-review.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="7_Show_Content" class="BlogPostContainer"&gt;
	

    
            &lt;div style="padding-bottom:5px;margin-top:15px;"&gt;
        
            &lt;div style="float: left"&gt;
                &lt;a rel="lightbox[8756ac44-7c89-4362-a0cf-42d1e9c7f028]" title="" href="http://blog.thomasbandt.de/Library/Media/CMS/IMG_1941_zoomview.JPG"&gt;&lt;img alt=" " title=" " src="http://blog.thomasbandt.de/Library/Media/CMS/IMG_1941.JPG" style="border-width:0px;height:450px;width:600px;" /&gt;&lt;/a&gt;
             &lt;/div&gt; 
        
           &lt;/div&gt;
           &lt;div style="clear:both"&gt;&lt;/div&gt;
        
    
    &lt;p&gt;Da ist es also nun, das neue iPhone. Dieses Windows Vista unter den Telefonen mit furchtbaren Empfangsproblemen ... &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Das Äußere&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Als Besitzer eines iPhone 3G ist die neue Form für mich zunächst ungewohnt gewesen und der Funke mochte nicht sofort überspringen. Es ist wie bereits auf den Bildern zu sehen kantiger und liegt nicht mehr so geschmeidig in der Hand, wie noch die beiden Vorgängermodelle. &lt;/p&gt;
&lt;p&gt;Dazu ist es gefühlt etwas schwerer als das 3G. Aber was erst im direkten Vergleich mit beiden Geräten in den Händen auffällt: es ist merklich kleiner und dünner geworden.&lt;/p&gt;
&lt;p&gt;Und für sich betrachtet ist es aber ein echtes Schmuckstück und optisch insgesamt mit den verbauten Materialien mal wieder ein echter Meilenstein, wenn auch auf den zweiten Blick (wie es die Alu-MacBooks z.B. auch sind/waren).&lt;/p&gt;
&lt;p&gt;Bei Apple hat einfach jeder Knopf eine Funktion und weniger ist hier im Vergleich zum HTC Desire beispielsweise wirklich mehr. Dazu kommt die Rückseite aus Glas, die es wirklich edel erscheinen lässt.&lt;/p&gt;
&lt;p&gt;Was ich nicht so ganz testen mag ist die Kratzempfindlichkeit der Rückseite. Mein 3G hat nur einen gröberen Kratzer davongetragen, ansonsten hat das Plastik in den letzten 2 Jahren gute Dienste geleistet. Beim iPhone 4 wird wohl eine Hülle fällig, aber Apple verschenkt sie ja in Kürze ... ;-)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Empfangsprobleme&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Keine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Emissionen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Das Ding wird warm. Das wurde zwar das 3G auch schon, aber jetzt habe ich das Gefühl bei etwas intensiverer Nutzung – ich rede nicht von 3D-Spielen, sondern Musik, E-Mail und Browsen – sofort einen Temperaturanstieg zu spüren. Richtig störend war es aber noch nicht.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Das Display&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nur ein Wort: Wahnsinn. Das Display vom HTC Desire hat mir schon richtig gut gefallen, das des iPhone 4 steht ihm in nichts nach. Gestochen scharfe Darstellung, insbesondere bei Text ein nicht zu unterschätzender Fortschritt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Die Geschwindigkeit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nur ein Wort: Wahnsinn. Insbesondere das (verkappte) Multitasking, dass die verbliebenen aber reduzierten Gedenksekunden beim Start einzelner Apps drastisch reduziert, zeigt Wirkung. Ob E-Mail, SMS, Kontakte, Browsen oder das Durchblättern meiner 12GB Musik darauf – es geht einfach alles „sofort“.&lt;/p&gt;
&lt;p&gt;Im Vergleich zum 3G ein absoluter Quantensprung. Zum 3G S hingegen sicher eher eine kleinere Veränderung.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browsen&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Der Vorteil des iPhone war 2007 bzw. 2008, dass es einen vollwertigen Browser mitbrachte, der neue Standards setzte. Endlich war es theoretisch möglich, das ganz normale Web auf dem Browser zu nutzen. Neben der limitierten Auflösung des Displays waren es aber vor allem der langsame Prozessor und der geringe Arbeitsspeicher, die das Surfen über nicht-mobile Websites unerträglich langsam machten. Das ist nun Geschichte, ob mit UMTS oder W-LAN, auch normale Websites werden benutzbar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Die Software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nun musste ich notgedrungen durch die Nötigung zum Jailbreak auf 3.1.3 bleiben, womit 4.0.1 nun für mich neu ist. Hintergrundbilder und Ordner sind nett, sonst ist nichts zu bemerken. Aber es tut eben alles, was ich konkret benötige (Stichwort Synchronisation von Kontakten und Terminen aus zwei Quellen und deren Zusammenführung auf dem Gerät) und ist natürlich nichts Neues zum 3G.&lt;/p&gt;
&lt;p&gt;Der Umstieg war übrigens super einfach. Anschließen an den Rechner, iTunes starten, Backup des alten Telefons einspielen. Bis auf die Passwörter, die ich neu setzen musste, waren alle Apps und Einstellungen wieder vorhanden. Prima!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Die Kamera&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Die Kamera ist besser als die des 3G, aber meine Canon PowerShot SX200 IS wird sie nicht ablösen. Der Digitalzoom ist natürlich Quatsch, auch der LED-Blitz ist eher von beschränkter Wirkung – aber besser als nix und für den Schnappschuss zwischendurch auf jeden Fall geeignet.&lt;/p&gt;
&lt;p&gt;Die Videofunktion habe ich auf dem 3G natürlich vermisst – jetzt habe ich sie. Die Qualität erscheint mir ganz gut, es läuft alles flüssig und es ist ein Grund, die 32-GB-Variante zu nehmen ;-).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tethering&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Noch so eine Sache, mit der mich T-Mobile gequält hat, war mein UMTS-Stick, den unter Windows zu betreiben besonders viele Nerven kostet. Das Ding kann nun zu eBay, ich brauche ihn nicht mehr. Stattdessen setze ich einfach auf Tethering, dass am iPhone selbst innerhalb von Sekunden eingerichtet ist und auch mit Windows per USB problemlos klappt (Tethering an, iPhone andocken, iTunes starten, schon ist die Verbindung hergestellt). Ein Traum (und ein Grund mehr für O2 ...).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fazit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Es sind jetzt erst 4 Tage, aber ich möchte es nicht mehr hergeben. Softwareseitig erfüllt es exakt meine Ansprüche, es ist schnell, schick und werthaltig. Für mich persönlich eine absolut gelungene Investition, da das mobile Arbeiten jetzt noch flüssiger wird.&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2354/de/blog/iphone-4-review.html&amp;title=iPhone+4+Review"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2354%2fde%2fblog%2fiphone-4-review.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2354/de/blog/iphone-4-review.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=8756ac44-7c89-4362-a0cf-42d1e9c7f028" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2354/de/blog/iphone-4-review.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/EaHwxXNMq7I" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2354/de/blog/iphone-4-review.html</feedburner:origLink></item> 
<item>
<title>TDD in der (meiner) Praxis – Wunsch und Wirklichkeit</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2353/de/blog/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html</guid>
<pubDate>Sat, 17 Jul 2010 14:59:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/DPPaojnOogE/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="8_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Zunächst einmal: Test Driven Development, wozu ich insbesondere „test first“ zähle, hat für mich einen gewissen Charme. Es ist zweifelsfrei so, dass dadurch die Architektur der eigenen Anwendung verbessert wird und viele kleine Fehler vermieden werden können. Der Teufel steckt ja bekanntlich im Detail. Umso besser, wenn man nun ein wirksames Werkzeug gegen ihn hat. &lt;/p&gt;
&lt;p&gt;Die Frage ist nur: zu welchem Preis?&lt;/p&gt;
&lt;p&gt;Nehmen wir mal eine Situation aus meinem Alltag. Ein potentieller Kunde fragt bei mir die Erstellung einer Webapplikation an, die ein wenig vom Standard abweicht, den ich mit meinen Komponenten abdecken kann. Individualprogrammierung ist also gefragt.&lt;/p&gt;
&lt;p&gt;Nun kann ich den Aufwand in Stunden kalkulieren, ein paar Prozent Puffer draufschlagen und das Ganze mit meinem Stundensatz multiplizieren und erhalte in etwa den Preis, den ich dem Kunden machen kann. &lt;/p&gt;
&lt;p&gt;Üblicherweise bewegen sich die Aufwände in meinen Alltagsprojekten dann zwischen 40 und 120 Stunden. Setze ich nun strikt auf TDD, muss ich hier von Anfang an mehr Zeit einkalkulieren – trotz inzwischen fast zweijähriger Praxis würde ich diesen Mehraufwand irgendwo zwischen 10 und 30% ansetzen.&lt;/p&gt;
&lt;p&gt;Sind wir bei 100 Stunden und einem fiktiven Stundensatz von 80 EUR also bei 8.000 EUR, lande ich mit einer realistischen Kalkulation und TDD schon bei 10.000 EUR.&lt;/p&gt;
&lt;p&gt;Nun ist das eine schöne Milchmädchenrechnung. Was zählt ist aber die reale Welt – und in dieser konkurriere ich mit meist gleich mehreren Marktteilnehmern, deren Qualitätsansprüche an die eigene Software ich nur erahnen kann (In diesen Budgetregionen konkurriert man im Zweifel auch häufiger mit PHP-Scriptern). Und klar gibt es Ausnahmesituationen in denen es keinen Sinn für den Kunden macht wg. 2.000 EUR zu entscheiden, da sollten andere Kriterien mehr zählen – aber nicht jeder Kunde tickt so.&lt;/p&gt;
&lt;p&gt;Dann kommt zwangsläufig die Frage auf: welchen Wert hat es für mich, auf TDD zu beharren? Oder es gar selbst zu finanzieren, also auf die 30% Aufschlag zu verzichten und es „einfach zu machen“? &lt;/p&gt;
&lt;p&gt;Von einem gebauchpinselten Ego kann ich mir am Ende des Monats nichts kaufen. Und den wesentlich besseren Code, den ich durch TDD ohne Frage erhalte, sehe ich in 80 von 100 Fällen sowieso nie wieder, da in diesen Fällen im Lebenszyklus der Anwendung höchstens einmal kosmetische Anpassungen fällig werden – bis die App nach ein paar Jahren verrichteten Dienstes einfach weggeworfen wird. Und selbst dort, wo die Anwendung kontinuierlich weiterentwickelt wird und Refactoring an der Tagesordnung ist, kann es sein, dass der Kunde Hautausschlag bekommt, wenn auf der Rechnung dafür auch nur irgendetwas mit „Test“ draufsteht – O-Ton: „Das ist für mich selbstverständlich!“.&lt;/p&gt;
&lt;p&gt;Und wenn man die Augen aufmacht und mal sieht was es alles so an Technologien da draußen gab, gibt und geben wird, mit denen Software entwickelt wird – da muss man sich doch wirklich fragen, ob man nicht auf einem etwas zu hohen Ross sitzt? Schließlich werden auch heute noch Anwendungen mit Access, Filemaker, und was es nicht sonsts noch so an Verbrechen gibt, erstellt, betreut und von den Kunden begeistert oder wenigstens zufrieden verwendet. Obwohl es jedem von uns vermutlich den Magen umdreht, wenn man mal unter die Haube schaut.&lt;/p&gt;
&lt;p&gt;Und nicht zuletzt muss man auch sagen, dass früher ja nun nicht alles schlecht war. Ich habe auch vor der Verwendung von TDD bereits robuste und gute Software entwickelt und ich kann nicht sagen, dass ich bei jedem Projekt im Anschluss erstmal lange Zeit für Bugfixing benötigt habe. Natürlich ist der ein oder andere Fehler erst beim Klicken durch die (Web-) Anwendung aufgetaucht – aber, so what?&lt;/p&gt;
&lt;p&gt;Und den Versuch die Architektur meiner Anwendungen zu verbessern, unternehme ich auch nicht erst seit TDD. Sicher arbeite ich nun mit wesentlich weniger Koppelungen, mache mir noch mehr Gedanken im Detail – aber ich mache noch immer Fehler oder treffe (Design-)Entscheidungen, die ich so schon beim nächsten Projekt nicht mehr treffen würde. Das Rad dreht sich eben ständig weiter. Das heißt der alte Spruch „Bitte lass mich mit meinem Code von vor zwei Jahren in Ruhe“ wird so auch mit TDD nicht an Gültigkeit verlieren. &lt;/p&gt;
&lt;p&gt;Zum Abschluss noch etwas Konkretes. Aufgabe: in der Datenbank werden Aufgabenlisten zu einem Projekt gespeichert. Es soll ein Formular erstellt werden, über welches diese Listen erzeugt werden. Die Aufgabenlisten sind wirklich simpel:&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TaskList : EntityBase&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ProjectID { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Description { get; set; }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Ohne TDD wäre das vermutlich eine Sache von 10-15 Minuten. Mit TDD und der damit verbundenen Zeremonien ... tja, ich glaube es war etwas mehr als eine dreiviertel Stunde.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Controller Tests (70 Lines of Code)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;[TestFixture]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;[Category(&lt;span class="str"&gt;"Blubr.App.Areas.Project.Controllers.TasksController"&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Wenn_eine_Aufgabenliste_angelegt_werden_soll : &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    ConcernOfTasksController&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; ITaskService TaskService;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Setup()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;            &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;base&lt;/span&gt;.Setup();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        TaskService = MockRepository.DynamicMock&amp;lt;ITaskService&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        Sut = &lt;span class="kwrd"&gt;new&lt;/span&gt; TasksController(TaskService);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        Sut.SetCurrentProject(&lt;span class="kwrd"&gt;new&lt;/span&gt; Domain.Model.Project { ID = 69 });&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt;(MockRepository.Record())&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;            Expect.Call(TaskService.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.Name == &lt;span class="str"&gt;"Valid"&lt;/span&gt;), &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;                Arg&amp;lt;IValidationState&amp;gt;.Is.Anything)).Return(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;            Expect.Call(TaskService.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.Name == &lt;span class="str"&gt;"Invalid"&lt;/span&gt;), &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;                Arg&amp;lt;IValidationState&amp;gt;.Is.Anything)).Return(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_der_Name_gemappt()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        Sut.CreateList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskListViewModel { Name = &lt;span class="str"&gt;"testname"&lt;/span&gt; });&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;        TaskService.AssertWasCalled(s =&amp;gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;            s.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.Name == &lt;span class="str"&gt;"testname"&lt;/span&gt;), &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;            Arg&amp;lt;IValidationState&amp;gt;.Is.Anything));&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_Beschreibung_gemappt()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;        Sut.CreateList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskListViewModel { Description = &lt;span class="str"&gt;"desc"&lt;/span&gt; });&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;        TaskService.AssertWasCalled(s =&amp;gt; &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;            s.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.Description == &lt;span class="str"&gt;"desc"&lt;/span&gt;), &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;            Arg&amp;lt;IValidationState&amp;gt;.Is.Anything));&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_ProjektID_gemappt()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;        Sut.CreateList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskListViewModel { Description = &lt;span class="str"&gt;"desc"&lt;/span&gt; });&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;        TaskService.AssertWasCalled(s =&amp;gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;            s.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.ProjectID == 69), &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;            Arg&amp;lt;IValidationState&amp;gt;.Is.Anything));&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_zur_Übersicht_weitergeleitet_wenn_alles_geklappt_hat()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;        var result = (RedirectToRouteResult) Sut.CreateList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskListViewModel { Name = &lt;span class="str"&gt;"Valid"&lt;/span&gt; });&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;        Assert.AreEqual(&lt;span class="str"&gt;"index"&lt;/span&gt;, result.RouteValues[&lt;span class="str"&gt;"action"&lt;/span&gt;]);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_das_Model_zurückgegeben_wen_nein_Fehler_aufgetreten_ist()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;        var result = (ViewResult)Sut.CreateList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskListViewModel { Name = &lt;span class="str"&gt;"Invalid"&lt;/span&gt; });&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;        Assert.AreEqual(&lt;span class="str"&gt;"Invalid"&lt;/span&gt;, ((TaskListViewModel) result.ViewData.Model).Name);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Controller Implementierung (16 LOC)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;[HttpPost]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;[ValidateAntiForgeryToken]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult CreateList(TaskListViewModel model)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    var taskList = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    taskList.ProjectID = CurrentProject.ID;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    taskList.Name = model.Name;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    taskList.Description = model.Description;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (TaskService.CreateTaskList(taskList, &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewModelValidationState(ModelState)))&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; RedirectToAction(&lt;span class="str"&gt;"index"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; View(model);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Service Tests (99 LOC)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="preproc"&gt;#region&lt;/span&gt; Wenn eine Aufgabenliste validiert wird&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;[TestFixture]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[Category(&lt;span class="str"&gt;"Blubr.Domain.Services.TaskService"&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Wenn_eine_Aufgabenliste_validiert_wird : ConcernOf&amp;lt;TaskService&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Setup()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        Sut = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskService(Arg&amp;lt;ITaskRepository&amp;gt;.Is.Anything);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Darf_der_Name_nicht_NullOrWhitespace_sein()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        var validationState = &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        Sut.ValidateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="str"&gt;""&lt;/span&gt; }, validationState);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        Assert.IsTrue(validationState.ContainsKey&amp;lt;TaskList&amp;gt;(l =&amp;gt; l.Name));&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    [ExpectedException(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentException))]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Muss_die_ProjektID_angegeben_sein()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        var validationState = &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        Sut.ValidateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 0 }, validationState);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Darf_die_Beschreibung_nicht_länger_als_500_Zeichen_lang_sein()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotImplementedException();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Darf_der_Name_nicht_länger_als_100_Zeichen_lang_sein()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotImplementedException();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;        &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;}&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;&lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;&lt;span class="preproc"&gt;#region&lt;/span&gt; Wenn eine Aufgabenliste angelegt werden soll&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;[TestFixture]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;[Category(&lt;span class="str"&gt;"Blubr.Domain.Services.TaskService"&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Wenn_eine_Aufgabenliste_angelegt_werden_soll : ConcernOf&amp;lt;TaskService&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; ITaskRepository TaskRepository;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Setup()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;        TaskRepository = MockRepository.DynamicMock&amp;lt;ITaskRepository&amp;gt;();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;        MockRepository.ReplayAll();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;        Sut = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskService(TaskRepository);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_true_zurückgegeben_wenn_alles_geklappt_hat()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;        var result = Sut.CreateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="str"&gt;"Valid"&lt;/span&gt; }, &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;        Assert.IsTrue(result);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_übergebene_Liste_validiert()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;        var validationState = &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;        Sut.CreateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="kwrd"&gt;null&lt;/span&gt; }, validationState);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;        Assert.IsTrue(validationState.ContainsKey&amp;lt;TaskList&amp;gt;(l =&amp;gt; l.Name));&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  75:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  76:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_false_zurückgegeben_wenn_ein_Fehler_aufgetreten_ist()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  78:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  79:  &lt;/span&gt;        var result = Sut.CreateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="kwrd"&gt;null&lt;/span&gt; }, &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState());&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  80:  &lt;/span&gt;        Assert.IsFalse(result);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  81:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  82:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  83:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  84:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_das_Erstellungsdatum_gesetzt_wenn_alles_ok_ist()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  85:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  86:  &lt;/span&gt;        Sut.CreateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="str"&gt;"Valid"&lt;/span&gt; }, &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  87:  &lt;/span&gt;        TaskRepository.AssertWasCalled(r =&amp;gt; r.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Matches(l =&amp;gt; l.Created.Date == Sut.DateTime.Date)));&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  88:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  89:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  90:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  91:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_Liste_im_Repository_gespeichert_wenn_alles_ok_ist()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  92:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  93:  &lt;/span&gt;        Sut.CreateTaskList(&lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList { ProjectID = 1, Name = &lt;span class="str"&gt;"Valid"&lt;/span&gt; }, &lt;span class="kwrd"&gt;new&lt;/span&gt; MockValidationState());&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  94:  &lt;/span&gt;        TaskRepository.AssertWasCalled(r =&amp;gt; r.CreateTaskList(Arg&amp;lt;TaskList&amp;gt;.Is.Anything));&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  95:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  96:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  97:  &lt;/span&gt;}&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  98:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  99:  &lt;/span&gt;&lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Service Implementierung (37 LOC)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TaskService : ServiceBase, ITaskService&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; TaskService(ITaskRepository taskRepository)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        TaskRepository = taskRepository;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; ITaskRepository TaskRepository;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ValidateTaskList(TaskList taskList, IValidationState validationState)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (taskList.ProjectID == 0)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException(&lt;span class="str"&gt;"Projekt-ID nicht gesetzt"&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(taskList.Name))&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;            validationState.AddError&amp;lt;TaskList&amp;gt;(l =&amp;gt; l.Name, &lt;span class="str"&gt;"Bitte wählen Sie einen Namen für die Aufgabenliste."&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; validationState.IsValid;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; CreateTaskList(TaskList taskList, IValidationState validationState)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!ValidateTaskList(taskList, validationState))&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;        taskList.Created = DateTime;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;        taskList.ID = TaskRepository.CreateTaskList(taskList);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;            &lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Repository Tests (66 LOC)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="preproc"&gt;#region&lt;/span&gt; Wenn eine Aufgabenliste angelegt wird&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;[TestFixture]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;[Category(&lt;span class="str"&gt;"Blubr.Domain.Data.SqlServer.TaskRepository"&lt;/span&gt;)]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Wenn_eine_Aufgabenliste_angelegt_wird : ConcernOfSqlServerRepository&amp;lt;TaskRepository, Model.TaskList, TaskList&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; FixtureSetUp()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        Sut = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskRepository();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        InitializeDatabase();&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Model.TaskList DummyTaskList()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        var list = &lt;span class="kwrd"&gt;new&lt;/span&gt; Model.TaskList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        list.Description = &lt;span class="str"&gt;"Text"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        list.Name = &lt;span class="str"&gt;"Name"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        list.ProjectID = 69;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        list.Created = DateTime.Now;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; list;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_ID_zurückgegeben()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;        var id = Sut.CreateTaskList(DummyTaskList());&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;        Assert.AreNotEqual(0, id);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_der_Name_gespeichert()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;        var id = Sut.CreateTaskList(DummyTaskList());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;        var list = Sut.Database.TaskLists.Single(l =&amp;gt; l.ID == id);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;        Assert.AreEqual(&lt;span class="str"&gt;"Name"&lt;/span&gt;, list.Name);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_Beschreibung_gespeichert()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;        var id = Sut.CreateTaskList(DummyTaskList());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;        var list = Sut.Database.TaskLists.Single(l =&amp;gt; l.ID == id);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;        Assert.AreEqual(&lt;span class="str"&gt;"Text"&lt;/span&gt;, list.Description);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_die_ProjektID_gespeichert()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;        var id = Sut.CreateTaskList(DummyTaskList());&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;        var list = Sut.Database.TaskLists.Single(l =&amp;gt; l.ID == id);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;        Assert.AreEqual(69, list.FKProjectID);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;    [Test]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wird_das_Erstellungsdatum_gespeichert()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;        var dummy = DummyTaskList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;        var id = Sut.CreateTaskList(dummy);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;        var list = Sut.Database.TaskLists.Single(l =&amp;gt; l.ID == id);&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;        Assert.AreEqual(dummy.Created, list.Created);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;}&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;&lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Repository Implementierung (21 LOC)&lt;/strong&gt;&lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TaskRepository : RepositoryBase&amp;lt;Model.TaskList, TaskList&amp;gt;, ITaskRepository&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; CreateTaskList(Model.TaskList taskList)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        var newTaskList = &lt;span class="kwrd"&gt;new&lt;/span&gt; TaskList();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        newTaskList.Created = taskList.Created;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        newTaskList.Name = taskList.Name;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        newTaskList.FKProjectID = taskList.ProjectID;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        newTaskList.Description = taskList.Description;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        Database.TaskLists.InsertOnSubmit(newTaskList);&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        Database.SubmitChanges();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; newTaskList.ID;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; Model.TaskList Map(TaskList source)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotImplementedException();&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Mein (Zwischen-)Fazit:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TDD ist cool, TDD ist nützlich, TDD verhilft zu besserer Software. Aber ist TDD auch alltagstauglich? Sollte ich es konsequent für alle Projekte, die jenseits von C:\Development\Tests\WebsiteProject12 hinausgehen einsetzen? Oder sollte ich zu alter Produktivität zurückkehren, ein paar mehr Fehler in Kauf nehmen? Die Antwort muss ich euch schuldig bleiben - mir schwirrt da vieles durch den Kopf, eine Entscheidung habe ich noch nicht getroffen.&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2353/de/blog/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html&amp;title=TDD+in+der+(meiner)+Praxis+%e2%80%93+Wunsch+und+Wirklichkeit"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2353%2fde%2fblog%2ftdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2353/de/blog/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=0944f45e-8c71-403c-9c98-d71757f4733e" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2353/de/blog/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/DPPaojnOogE" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2353/de/blog/tdd-in-der-meiner-praxis-wunsch-und-wirklichkeit.html</feedburner:origLink></item> 
<item>
<title>iPhone 4: Da ist das Ding</title>
<guid isPermaLink="false">http://blog.thomasbandt.de/39/2352/de/blog/iphone-4-da-ist-das-ding.html</guid>
<pubDate>Fri, 16 Jul 2010 20:59:00 +0200</pubDate>
<link>http://feedproxy.google.com/~r/ThomasGoesNet/~3/RfnjhYZaxwU/iphone-4-da-ist-das-ding.html</link>
<author><![CDATA[Thomas Bandt]]></author>
<description>&lt;div id="9_Show_Content" class="BlogPostContainer"&gt;
	

    
    
    &lt;p&gt;Nachdem ich &lt;a href="http://blog.thomasbandt.de/39/2348/de/blog/selbst-ist-der-kunde.html"&gt;vor knapp einem Monat&lt;/a&gt; von der Telekom zu O2 wechselte und von letzterer quasi zum Jailbreak genötigt wurde, habe ich dann nicht mehr groß überlegt und noch am selben Wochenende die Konsequenz für mich ganz persönlich gezogen: da ich weder Lust auf die Gängelung der Telekom hatte noch eine &lt;a href="http://blog.thomasbandt.de/39/2336/de/blog/htc-desire-review.html"&gt;Alternative&lt;/a&gt; zum iPhone 4 sah, bestellte ich es mir einfach in England.&lt;/p&gt;
&lt;p&gt;Das geht, weil dort die Exklusivbindung an einen Provider nicht (mehr) existiert und man das Gerät wie jedes andere &lt;a href="http://store.apple.com/uk/browse/home/shop_iphone/family/iphone?mco=OTY2ODA2OQ"&gt;einfach im Shop kaufen&lt;/a&gt; kann. Einziges Problem: Apple verlangt zwingend eine Lieferadresse in Großbritannien. Schon vorher bin ich über den Dienstleister &lt;a href="https://www.borderlinx.com/m/"&gt;Borderlinx&lt;/a&gt; aufmerksam geworden. Und nach einiger Recherche mit beruhigenden Ergebnissen (unter anderem hatten viele bereits das Nexus One Anfang des Jahres aus den USA darüber bestellt) habe ich mich dann kurzerhand entschlossen es einfach zu wagen.&lt;/p&gt;
&lt;p&gt;Also bei Borderlinx registriert, individuelle Adresse in UK bekommen und diese bei der Bestellung einfach angegeben. Der Shop meckerte zwar und wollte eine seltsame Alternativadresse vorschlagen, aber man kann bei seiner bleiben. Als Rechnungsadresse wählte ich übrigens meine deutsche Büroadresse.&lt;/p&gt;
&lt;p&gt;Das alles war am 19. Juni - die Lieferung wurde für den 14-16. Juli angekündigt. Tatsächlich war ich mir nicht sicher, ob Apple die Bestellung nicht doch noch stornieren würde - aber es geschah: nichts. Stattdessen kam am 6. Juli die Meldung, dass meine Sendung verschickt wurde, am 9. Juli folgte die Rechnung. Es dauerte bis zum 12. als die Sendung, wohl direkt aus dem Werk in China, in England eintraf. &lt;/p&gt;
&lt;p&gt;Zumindest entnahm ich das aus dem TNT-Tracking. Borderlinx selbst zeigte keine Regung. Über Twitter erhielt ich dann den Tipp es mal mit nem Chat mit dem Support zu probieren. Und tatsächlich, das half (dringende Bestellung ;););)). Am 13. Juli wurde das Paket dann bei Borderlinx eingebucht. Nun musste ich die Weiterleitung noch bezahlen und wählte als Option Express-Lieferung.&lt;/p&gt;
&lt;p&gt;Leider scheint Borderlinx eine etwas andere Definition von Expres zu besitzen, als ich es tue. Es tat sich jedenfalls anderthalb Tage nichts. Daraufhin chattete ich wieder mit dem Support, der mir diesmal aber nicht konkret helfen wollte. Mein Paket würde heute rausgehen (Agent 1) bzw. in 24-48h bearbeitet (Agent 2).&lt;/p&gt;
&lt;p&gt;Ich lehnte mich schließlich zurück und ließ die Dinge laufen. Auf ein oder zwei Tage mehr oder weniger kam es jetzt ja auch nicht mehr an. Allerdings ging es dann doch relativ schnell: gestern Morgen um 9 meldete Borderlinx die Übergabe an DHL, 24h später schrieb mir der Empfang in meinem Büro, dass ein Paket für mich angenommen wurde.&lt;/p&gt;
&lt;p&gt;Fazit also:&lt;/p&gt;
&lt;p&gt;Wer das Gerät in Deutschland für 1.000 bis 1.200 EUR kauft, hat nicht mehr alle Tassen im Schrank. Für insgesamt rund 750 EUR für das 32GB-Gerät kann man getrost auf die Bestellung über Borderlinx zurückgreifen, etwas Geduld und eine Kreditkarte vorausgesetzt.&lt;/p&gt;
&lt;p&gt;Ich bin jedenfalls froh das gemacht zu haben, auch wenn ich jetzt erstmal rund 500 EUR ärmer bin, als ich es bei einer Vertragsverlängerung bei T-Mobile gewesen wäre. Dafür amortisiert sich das Ganze durch meine extrem gesunkenen laufenden Kosten bei O2 auf 2 Jahre gesehen, und ich habe die Option im nächsten Jahr mit geringem Verlust direkt auf die nächste Variante upgraden zu können oder gar zu einem Android- oder Windows-Phone-Device zu wechseln. Nicht zu vergessen das günstigere (Daten-)Roaming, dass durch den fehlenden Netlock möglich wird.&lt;/p&gt;


    
    
    


&lt;/div&gt;






&lt;hr /&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://blog.thomasbandt.de/39/2352/de/blog/iphone-4-da-ist-das-ding.html&amp;title=iPhone+4%3a+Da+ist+das+Ding"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fblog.thomasbandt.de%2f39%2f2352%2fde%2fblog%2fiphone-4-da-ist-das-ding.html" border="0" alt="kick it on dotnet-kicks.de" style="vertical-align:middle" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blog.thomasbandt.de/39/2352/de/blog/iphone-4-da-ist-das-ding.html#Comments"&gt;&lt;img src="http://blog.thomasbandt.de/CommentCounter.ashx?ArticleID=40ed4884-9aaf-4bfa-9f6b-fc39310163aa" style="border:solid 0px black" /&gt;&lt;/a&gt; | &lt;a href="http://blog.thomasbandt.de/39/2352/de/blog/iphone-4-da-ist-das-ding.html#AddComment"&gt;Kommentieren&lt;/a&gt; | &amp;copy; 2010 &lt;a href="http://blog.thomasbandt.de/"&gt;Thomas Bandt&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/ThomasGoesNet/~4/RfnjhYZaxwU" height="1" width="1"/&gt;</description>
<feedburner:origLink>http://blog.thomasbandt.de/39/2352/de/blog/iphone-4-da-ist-das-ding.html</feedburner:origLink></item> 
</channel>
</rss>
