<?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:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>klaus_b@.NET</title>
    <description>Das private Weblog von Klaus Bock über alles was an .NET und C# Spass macht.</description>
    <link>http://blog.klaus-b.net/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 2.5.2.69</generator>
    <language>de-DE</language>
    <blogChannel:blogRoll>http://blog.klaus-b.net/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://blog.klaus-b.net/syndication.axd</blogChannel:blink>
    <dc:creator>Klaus Bock</dc:creator>
    <dc:title>klaus_b@.NET</dc:title>
    <geo:lat>48.195000</geo:lat>
    <geo:long>12.389000</geo:long>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/klaus_b" /><feedburner:info uri="klaus_b" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>48.1950548503461</geo:lat><geo:long>12.3890697956085</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.0/</creativeCommons:license><item>
      <title>Warum fragmentiert die binäre Serialisierung</title>
      <description>&lt;p&gt;&lt;img title="fragmented2" class="leftImg" alt="fragmented2"  src="http://blog.klaus-b.net/image.axd?picture=fragmented2.png" width="150" height="113" /&gt;... oder; die Krux mit den automatischen Größen von Streams.     &lt;br /&gt;Da in der heutigen Zeit, vor allem in der Welt von verwaltetem Code, kaum noch eigene proprietäre Dateiformate Anwendung finden, werden die Allerwenigsten auf dieses Problem stoßen. Auch die Tatsache, dass für beinahe jede Anforderung ein Framework oder eine Bibliothek vorhanden ist, trägt mit Sicherheit dazu bei, solche elementaren Probleme von der Bildfläche verschwinden zu lassen. Für eine ganze Reihe von Entwicklern hört der Gedanke an binäre Serialisierung auf, wenn sie ein Framework wie &lt;a title="Binary JSON" href="http://bsonspec.org/"&gt;BSON&lt;/a&gt; oder &lt;a title="Projekt ProtoBuf" href="http://code.google.com/p/protobuf/"&gt;Protocol Buffers&lt;/a&gt; zur Anwendung bringen können. Dies soll keine Kritik und schon gar keine negative sein. Ganz im Gegenteil. Diese Frameworks erleichtern die tägliche Arbeit in vielerlei Hinsicht. Verbergen leider aber auch die eigentliche Problematik der Serialisierung. Für mich gehört dieses Thema nach wie vor zu einem der interessantesten in der Softwareentwicklung. Jetzt aber zurück zum eigentlichen Thema.&lt;/p&gt;  &lt;p&gt;Für ein aktuelles Projekt verwende ich ein eigenes binäres Dateiformat, in das Datenblöcke in serialisierter und komprimierter Form als &lt;a title="Byte Struktur" href="http://msdn.microsoft.com/yyb1w04y.aspx" rel="msdn nofollow"&gt;byte&lt;/a&gt;-Arrays geschrieben werden. Während der Testphase auf einem Livesystem stellte ich fest, dass die Dateigröße überproportional zum Inhalt anwuchs. Zunächst maß ich dem Verhalten keine besondere Bedeutung bei, da ein ähnliches Verhalten auch bei Formaten wie etwa den Access Datenbankdateien oder den Dateien der Windows Registrierung ebenfalls auftritt. Insgesamt ließ mich das “Problem” aber nicht in Ruhe. Nachdem ich mir eine der Dateien im Hex-Format angesehen hatte, war schnell klar, was dem Problem zugrunde lag:     &lt;br /&gt;Zwischen den einzelnen Datenblöcken wurde immer eine ganze Menge an 0-Byte-Zeichen geschrieben.&lt;/p&gt;  &lt;p&gt;&lt;img title="hexview11" class="centerImg"  alt="hexview11"  src="http://blog.klaus-b.net/image.axd?picture=hexview11.png" width="520" height="493" /&gt;&lt;/p&gt;  &lt;p&gt;Das Resultat war ersichtlich. Aber woher kam dieses Verhalten?    &lt;br /&gt;Wie bereits Eingangs erwähnt, werden die Datenblöcke nach dem serialisieren auch komprimiert. Dazu wird die Klasse &lt;a title="DeflateStream Klasse" href="http://msdn.microsoft.com/0y917bht.aspx" rel="msdn nofollow"&gt;DeflateStream&lt;/a&gt; der Frameworks verwendet. Diese Klasse komprimiert den Inhalt eines &lt;a title="Stream Klasse" href="http://msdn.microsoft.com/8f86tw9e.aspx" rel="msdn nofollow"&gt;Stream&lt;/a&gt; in einen anderen. Genau da entstand das Problem.     &lt;br /&gt;Das Problem ist vielmehr eine Eigenart der DeflateStream Klasse in Verbindung mit einem &lt;a title="MemoryStream Klasse" href="http://msdn.microsoft.com/9a84386f.aspx" rel="msdn nofollow"&gt;MemoryStream&lt;/a&gt;. Das Verhalten lässt sich am einfachsten mit einem kleinen Beispiel verdeutlichen. Folgend wird eine Liste aus zufälligen Zeichenfolgen in ein Byte-Array serialisiert und anschließend komprimiert. Mit der Variablen &lt;strong&gt;numberOfEntries&lt;/strong&gt; kann die Anzahl der Einträge in der Liste und dadurch indirekt die Länge des komprimierten Datenblocks gesteuert werden. In der Variablen &lt;strong&gt;realLength&lt;/strong&gt; wird die Anzahl der tatsächlich verwertbaren Bytes im Array ausgegeben. Bei einer geringen Anzahl von Einträgen in der temporären Liste, ist der Wert von &lt;strong&gt;realLength&lt;/strong&gt; immer deutlich kleiner als die Länge des erzeugten Arrays &lt;strong&gt;output&lt;/strong&gt;. Erst ab etwa 130 Einträge in der temporären Liste tritt dieses Verhalten nicht mehr auf. Ab dieser Größe wird die Ausgabe ohne nachgestellte 0-Byte-Zeichen erzeugt.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:ecc0177b-3955-4856-9ccc-c9690bb1d1a9" class="wlWriterEditableSmartContent"&gt;&lt;pre class="c#" title="code"&gt;var numberOfEntries = 10;
var chars = &amp;quot;abcdefghijklmnopqrstuvwxyz&amp;quot;;
var tempList = new List&amp;lt;string&amp;gt;(numberOfEntries);
var random = new Random();
for (int i = 0; i &amp;lt; numberOfEntries; i++)
{
    var start = random.Next(0, chars.Length - 1);
    var length = random.Next(start + 1, chars.Length) - start;
    var entry = chars.Substring(start, length);
    tempList.Add(entry);
}
var buffer = Encoding.Default.GetBytes(string.Join(&amp;quot;|&amp;quot;, tempList));
byte[] output = null;
using (var instream = new MemoryStream(buffer))
{
    using (var outStream = new MemoryStream())
    {
        using (var compress = new DeflateStream(outStream, CompressionMode.Compress))
        {
            instream.CopyTo(compress);
        }
        output = outStream.GetBuffer();
    }
}
// Die Länge des Ausgabe-Arrays
// Unter 130 Einträgen wird fast immer eine Länge von 256 erzeugt.
var arrayLength = output.Length;
// Die tatsächliche Anzahl an verwertbaren Bytes im Array
var realLength = output.Count(b =&amp;gt; b &amp;gt; byte.MinValue);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Im obigen Beispiel, wird im zweiten using-Block der MemoryStream für die Ausgabe initialisiert, der nach dem Verlassen des innersten using-Blocks die komprimierten Daten enthält. Initial wird hier ein leerer Stream mit Capacity und Length 0 erzeugt. Der DeflateStream kopiert seinen Inhalt in diesen Stream und legt dabei so lange eine Länge von 256 Bytes fest, bis diese Größe überschritten wird. Erst dann wird der Ausgabestream mit der korrekten Länge des Inhalts des DeflateStream erzeugt. Das bedeutet als Resultat für die, aus den Ergebnissen erzeugte, Datei:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je mehr Datenblöcke aus Inhalten mit geringer Größe erzeugt werden, desto fragmentierter ist das Ergebnis&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Zur Lösung dieses “Problems”, oder besser unschönen Verhaltens, stehen jetzt zwei Ansatzpunkte zur Auswahl:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Am Anfang des Prozesses, in dem der Konstruktor des Ausgabestreams mit einer kleineren Kapazität initialisiert wird. &lt;/li&gt;
  &lt;li&gt;Am Ende des Prozesses, in dem die Ausgabe bearbeitet wird. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Den ersten Ansatzpunkt habe ich verworfen, da die Größe des komprimierten Inhalts nicht genau vorhergesagt werden kann. Auch beim Versuch der Initialisierung mit einer Kapazität die klein genug ist, wurde im Test oft genug die Ausgabe mit 256 Bytes im &lt;a title="Array Klasse" href="http://msdn.microsoft.com/czz5hkty.aspx" rel="msdn nofollow"&gt;Array&lt;/a&gt; erzeugt.&lt;/p&gt;
&lt;p&gt;Zur Umsetzung des zweiten Ansatzpunkts, habe ich mich für eine Erweiterungsmethode entschieden, die ähnlich wie die &lt;a title="String.TrimEnd Methode" href="http://msdn.microsoft.com/64zz6w66.aspx" rel="msdn nofollow"&gt;TrimEnd&lt;/a&gt;-Methode der String-Klasse, alle nachgestellten 0-Byte-Zeichen aus dem Ausgabe-Array entfernt.&lt;/p&gt;
&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4a55c3f7-7ed8-40ad-8614-bb6d8a4a691f" class="wlWriterEditableSmartContent"&gt;&lt;pre class="c#" title="code"&gt;internal static byte[] TrimEnd(this byte[] bytes)
{
    var startLength = bytes.GetLength(0);
    var startPos = startLength - 1;
    var trimPos = startPos;
    for (int i = startPos; i &amp;gt; -1; i--)
    {
        if (bytes[i] &amp;gt; byte.MinValue)
        {
            trimPos = i;
            break;
        }
    }
    if (trimPos == startPos)
    {
        return bytes;
    }
    var trimmedLength = trimPos + 1;
    var trimmed = new byte[trimmedLength];
    Array.Copy(bytes, trimmed, trimmedLength);
    return trimmed;
}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Wenn jetzt beim Abruf des Inhalts diese Erweiterungsmethode aufgerufen wird, ist das Ergebnis jedes mal wie erwartet. Das Problem der Fragmentierung innerhalb der Datei hat sich somit erledigt.&lt;/p&gt;
&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:04e1348d-0980-4449-b5c1-7d6e0ff68574" class="wlWriterEditableSmartContent"&gt;&lt;pre class="c#" title="code"&gt;output = outStream.GetBuffer().TrimEnd();&lt;/pre&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;Fazit:&lt;/h3&gt;
&lt;p&gt;Der bewusste Verzicht auf bestehende Frameworks und Bibliotheken ist oft mit einem, manchmal deutlichem, Mehraufwand verbunden. Besonders dann, wenn unvorhergesehene Probleme oder Eigenarten auftauchen. 
  &lt;br /&gt;Andererseits verschaffen mir gerade diese unvorhersehbaren Situationen einen tieferen Einblick in die jeweilige Materie und somit meist ein besseres Verständnis für das eigentliche Problem. 
  &lt;br /&gt;Wie ich bereits weiter oben gesagt habe: Frameworks für spezielle Anforderungen sind eine feine Sache und meist auch eine große Arbeitserleichterung. 
  &lt;br /&gt;Dennoch wird es immer wieder Entwickler geben die einfach aus Neugier, was ohne sie machbar ist, darauf verzichten.&lt;/p&gt;
&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:dd005640-5935-4b0e-a0c9-a31b24564563" class="wlWriterSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/clr" rel="tag"&gt;clr&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt; | &lt;a href="http://technorati.com/tags/serialization" rel="tag"&gt;serialization&lt;/a&gt; | &lt;a href="http://technorati.com/tags/binary" rel="tag"&gt;binary&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=oe1AWFM0yVM:pb9Uy3G571E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=oe1AWFM0yVM:pb9Uy3G571E:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=oe1AWFM0yVM:pb9Uy3G571E:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/oe1AWFM0yVM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/oe1AWFM0yVM/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2013/05/03/Warum-fragmentiert-die-binare-Serialisierung.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=ea488e2b-8958-4f43-b5f6-e6b6622859ce</guid>
      <pubDate>Fri, 03 May 2013 15:49:00 +0200</pubDate>
      <category>CLR</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=ea488e2b-8958-4f43-b5f6-e6b6622859ce</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=ea488e2b-8958-4f43-b5f6-e6b6622859ce</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2013/05/03/Warum-fragmentiert-die-binare-Serialisierung.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=ea488e2b-8958-4f43-b5f6-e6b6622859ce</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=ea488e2b-8958-4f43-b5f6-e6b6622859ce</feedburner:origLink></item>
    <item>
      <title>Crawler, Spider, Bot und Co.</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="crawler - ©2011-2013 ~Turisas(deviantArt)" alt="crawler - ©2011-2013 ~Turisas(deviantArt)" src="http://blog.klaus-b.net/image.axd?picture=crawler.png" width="200" height="160" /&gt;oder die oft unterschätzte Verschwendung von Ressourcen.     &lt;br /&gt;Viele Webseitenbetreiber sind sich wahrscheinlich gar nicht im Klaren darüber, wie viele Ressourcen, wie etwa: Datenbankzugriffe, Bandbreite, unnötige Anfragen und Fehlerbehandlungen, von &lt;a title="Erklärung Webcrawler in der Wikipedia" href="http://de.wikipedia.org/wiki/Webcrawler" rel="wiki bofollow"&gt;Webcrawler&lt;/a&gt; &amp;amp; Co. verursacht werden. Anders kann ich mir die wenigen Suchergebnisse zu diesem Thema nicht erklären.     &lt;br /&gt;Eine andere Möglichkeit besteht eventuell darin, dass nur mich die oben genannte Verschwendung meiner Server-Ressourcen beschäftigt und andere Blog- und Seitenbetreiber sich nicht weiter daran stören. Sei es wie es wolle, mich stört das hemmungslose Verhalten vieler Crawler und daher habe ich mich etwas eingehender mit dem Thema auseinandergesetzt.&lt;/p&gt;  &lt;p&gt;Zunächst einmal galt es zu verstehen, was wollen die &lt;a title="Erklärung Crawler in der Wikipedia" href="http://de.wikipedia.org/wiki/Crawler" rel="wiki nofollow"&gt;Crawler&lt;/a&gt;, oder Spider, auf meiner Webseite. Wer sollte schon Interesse am Inhalt meiner Seite haben, abgesehen von den üblichen Suchmaschinen natürlich.&lt;/p&gt;  &lt;p&gt;Das scheint eine ganze Menge zu sein. Allerdings haben die Wenigsten echtes Interesse an den Inhalten, als viel mehr an der Verlinkung oder Sichtbarkeit im Netz. Wobei spätestens ab hier jedem klar sein sollte worauf es hinaus läuft. Es geht mal wieder um &lt;a title="Erklärunf von Search Engine Optimization (SEO) in der Wikipedia" href="http://de.wikipedia.org/wiki/Suchmaschinenoptimierung" rel="wiki nofollow"&gt;SEO&lt;/a&gt; und &lt;a title="Erklärung Suchmaschinenmarketing (SEM) in der Wikipedia" href="http://de.wikipedia.org/wiki/Suchmaschinenmarketing" rel="wiki nofollow"&gt;SEM&lt;/a&gt;.     &lt;br /&gt;Spätestens seit die großen Suchmaschinen mit ihren gesammelten Daten nicht mehr so freizügig umgehen, mussten sich die diversen SEO Agenturen etwas Neues einfallen lassen. Das naheliegende war vermutlich, einen eigenen Index aufzubauen. Zwei der bekannteren Vertreter dieser Zunft dürften wohl SISTRIX mit ihrem &lt;a title="Offizielle Seite des SITRIX Crawler" href="http://crawler.sistrix.net/" rel="nofollow"&gt;SITRIX Crawler&lt;/a&gt; und 80legs mit ihrem Crawler &lt;a title="Seite des Crawler 008 von 80legs" href="http://www.80legs.com/webcrawler.html" rel="nofollow"&gt;008&lt;/a&gt; sein.     &lt;br /&gt;Beide Crawler benehmen sich gesittet, beachten im großen und ganzen die &lt;strong&gt;robots.txt&lt;/strong&gt; und halten sich, zumindest in Teilen, an den &lt;a title="Erklärung des Robots Exclusion Standard in der Wikipedia" href="http://de.wikipedia.org/wiki/Robots.txt" rel="wiki nofollow"&gt;Robots Exlusion Standard&lt;/a&gt;. Wer seine Seite nicht in einem Index der diversen SEO Agenturen wissen will, kann dem jeweiligen Bot in seiner &lt;strong&gt;robots.txt&lt;/strong&gt; einfach den Zugang verwehren. Sollte der angesprochene Bot sich nicht an das Verbot halten, kann man immer noch Kontakt mit der jeweiligen Agentur aufnehmen und um Unterlassung der Indexierung ersuchen.&lt;/p&gt;  &lt;p&gt;Ein ganz anderes Kaliber stellen die wirklich üblen Gesellen dar. Sie halten sich an keine Regeln oder Verbote und verfolgen konsequent ihr Ziel.    &lt;br /&gt;Einen eher harmlosen Zweig dieser Familie stellen die sogenannten &lt;strong&gt;Harvester&lt;/strong&gt; dar.     &lt;br /&gt;Harvester sind Crawler, die ganz gezielt nach Emailadressen suchen. Die erbeuteten Emailadressen landen dann direkt in Listen von Spammern, oder werden an solche verkauft. Diese Harvester zielen meist auf Seiten, die Impressum, Kontakt oder verwandte Synonyme im Namen enthalten.&lt;/p&gt;  &lt;p&gt;Als eher lästige, aber nicht wirklich gefährliche Zeitgenossen, kann man &lt;strong&gt;Comment Spammer&lt;/strong&gt; einordnen. Beinahe jeder Blog- oder Forenbetreiber dürfte sich schon das ein oder andere mal mit ihnen herumgeschlagen haben. Diese Kategorie von Bots versucht automatisiert Webseiten zu promoten, in dem sie mehr oder weniger sinnvolle Kommentare in Blogs und Foren verbreiten.     &lt;br /&gt;Zu dieser Kategorie würde ich auch die &lt;strong&gt;Registration Bots&lt;/strong&gt; zählen. Sie registrieren, vorwiegend in Foren, irgend welche Benutzer mit wirklich fantasievollen Namen. Der Nutzen hinter diesen Aktionen ist mir bisher verborgen geblieben, da nach der erfolgreichen Registrierung des Benutzers keine weiteren Aktionen erfolgen.&lt;/p&gt;  &lt;p&gt;Als am gefährlichsten erachte ich Bots, die Webseiten auf Schwachstellen abklappern. Für diese Kategorie konnte ich keinen gebräuchlichen Namen finden. Dieser Umstand macht sie aber nicht weniger gefährlich. Noch bis vor Kurzem konnte ich immer wieder Versuche verzeichnen, die auf eine &lt;a title="Beschreibung der ASP.NET ViewState Schwachstelle" href="http://blogs.technet.com/b/srd/archive/2010/09/17/understanding-the-asp-net-vulnerability.aspx"&gt;ASP.NET-Schwachstelle&lt;/a&gt; aus dem Jahr 2010 abzielen.     &lt;br /&gt;Auch auf &lt;a title="Erklärung von Cross Site Scripting (XSS) in der Wikipedia" href="http://de.wikipedia.org/wiki/Cross-Site-Scripting" rel="wiki nofollow"&gt;XSS&lt;/a&gt; (Cross Site Scripting) und &lt;a title="Erklärung des Begriffs SQL-Injection in der Wikipedia" href="http://de.wikipedia.org/wiki/SQL-Injection" rel="wiki nofollow"&gt;SQL-Injection&lt;/a&gt; wird immer wieder gerne abgeklopft. Zwar enden diese Versuche immer in Fehlern, erzeugen aber eine nicht unerhebliche Menge an Serverlast. Die Fehlerbehandlung kostet nun mal Zeit und Ressourcen.&lt;/p&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;Fazit:&lt;/h3&gt;  &lt;p&gt;Crawler, Spider und Bots verbrauchen einen nicht unerheblichen Anteil der zur Verfügung stehenden Ressourcen einer Webseite. Jeder sieht ein, dass die Crawler von Suchmaschinen benötigt werden. Gegen alle anderen kann und sollte man sich zur Wehr setzen. Aber das ist ein Thema für einen anderen Artikel.&lt;/p&gt;  &lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:a5250739-fc66-4cbd-be12-b4e60da4d4e3" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/searching" rel="tag"&gt;searching&lt;/a&gt; | &lt;a href="http://technorati.com/tags/crawler" rel="tag"&gt;crawler&lt;/a&gt; | &lt;a href="http://technorati.com/tags/spider" rel="tag"&gt;spider&lt;/a&gt; | &lt;a href="http://technorati.com/tags/bot" rel="tag"&gt;bot&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=S7dOziZ04Bs:JFgaMDVYFfY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=S7dOziZ04Bs:JFgaMDVYFfY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=S7dOziZ04Bs:JFgaMDVYFfY:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/S7dOziZ04Bs" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/S7dOziZ04Bs/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2013/03/29/Crawler-Spider-Bot-und-Co.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=493ff031-7d05-4e40-96d1-7ee3ab19b095</guid>
      <pubDate>Fri, 29 Mar 2013 18:03:21 +0200</pubDate>
      <category>Allgemeines</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=493ff031-7d05-4e40-96d1-7ee3ab19b095</pingback:target>
      <slash:comments>5</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=493ff031-7d05-4e40-96d1-7ee3ab19b095</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2013/03/29/Crawler-Spider-Bot-und-Co.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=493ff031-7d05-4e40-96d1-7ee3ab19b095</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=493ff031-7d05-4e40-96d1-7ee3ab19b095</feedburner:origLink></item>
    <item>
      <title>Binär, XML und JSON vs. Custom-Serializer</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="binärer Code" alt="binär code" src="http://blog.klaus-b.net/image.axd?picture=binary.png" /&gt;… oder; wenn du schnell sein willst musst du dich selbst darum kümmern.     &lt;br /&gt;Im &lt;a title="Binär, XML und JSON-Serialisierung im Vergleich" href="http://blog.klaus-b.net/post/2011/12/30/Binar-XML-und-JSON-Serialisierung-im-Vergleich.aspx"&gt;vorherigen Artikel&lt;/a&gt; wurden bisher nur Standardserialiserer und ihre Formate miteinander verglichen. Die Ergebnisse waren schon recht ordentlich und die Erkenntnisse aus den Vergleichen sehr lehrreich. Vor allem der Vergleich &lt;a title="Extensible Markup Language" href="http://de.wikipedia.org/wiki/XML" rel="wiki nofollow"&gt;XML&lt;/a&gt; vs. &lt;a title="JavaScript Object Notation" href="http://de.wikipedia.org/wiki/JSON" rel="wiki nofollow"&gt;JSON&lt;/a&gt; animierte mich dazu, die gewonnenen Erkenntnisse weiter zu führen. Meines Erachtens nach, resultiert der Vorteil von JSON gegenüber XML in der deutlich schlankeren Definition der erzeugten Daten. Während XML vom Klassennamen über die Namen der Enthaltenen Eigenschaften bis zum Typ des Inhalts von Kollektionen alles schreibt, beschränkt sich JSON auf den Namen der Eigenschaften und ihren Inhalt. Wenn ich diesen Gedankengang konsequent weiterführe, kann ich in einem angepassten Serialisierer selbst auf die Namen der Eigenschaften verzichten und statt dessen mittels &lt;a title="Indexer (C#)" href="http://msdn.microsoft.com/6x16t2tx.aspx" rel="msdn nofollow"&gt;Indexer&lt;/a&gt; auf den jeweiligen Wert des serialisierten Objekts zugreifen.     &lt;br /&gt;Als nächste Konsequenz kann die komplette Typbehandlung beim De/Serialisieren entfallen, da der zu de/serialiserende Typ bekannt ist und nur dieser verwendet wird. Aber nun der Reihe nach.&lt;/p&gt;  &lt;p&gt;Der Anlass für die Vergleiche der verschiedenen Serialisierer, war eine Anforderung aus einem aktuellen Projekt über das ich in &lt;a title="Datensammlungen über HTTP serialisieren" href="http://blog.klaus-b.net/post/2011/12/27/Datensammlungen-uber-HTTP-serialisieren.aspx"&gt;diesem Artikel&lt;/a&gt; bereits geschrieben haben:     &lt;br /&gt;“&lt;em&gt;Eine Kollektion eines bekannten Typs in einem geschlossenen System schnell und effizient zu serialisieren und deserialisieren.&lt;/em&gt;”     &lt;br /&gt;Solange ich einen der Standardserialisierer verwende, werde ich immer die Typbehandlung des jeweiligen Serialisierer in Kauf nehmen müssen, da der Serialisierer mit beinahe jedem gängigen .NET Objekt umgehen muss. Warum also nicht die Serialisierung auf das notwendige beschränken? Das Notwendige ist per Definition alleinig der Inhalt der öffentlichen Eigenschaften.&lt;/p&gt;  &lt;p&gt;Wie könnte so eine serialisierte Zeichenfolge aussehen, die den Inhalt der öffentlichen Eigenschaften darstellt?    &lt;br /&gt;Da eine Kollektion serialisiert werden soll, muss als erstes zwischen den einzelnen Einträgen der Auflistung getrennt werden. Als nächstes muss eine Trennung zwischen den einzelnen Eigenschaften eines Eintrags her. Am einfachsten erschien mir ein Muster nach folgendem Beispiel:     &lt;br /&gt;&lt;strong&gt;[#|#|#…]&lt;/strong&gt;     &lt;br /&gt;Die eckigen Klammern umschließen eine Klasse, also einen Eintrag in der Auflistung. Mit einem oder-Operator (&lt;strong&gt;|&lt;/strong&gt;) wird zwischen den einzelnen Eigenschaften abgegrenzt. Zur Darstellung eines &lt;a title="Array Klasse" href="http://msdn.microsoft.com/czz5hkty.aspx" rel="msdn nofollow"&gt;Array&lt;/a&gt; oder einer anderen Auflistung habe ich mich für folgendes Muster entschieden:     &lt;br /&gt;&lt;strong&gt;(n,n,n…)&lt;/strong&gt;     &lt;br /&gt;Kombiniert ergibt sich für die Klasse &lt;em&gt;TestNode&lt;/em&gt;, aus &lt;a title="Datensammlungen über HTTP serialisieren" href="http://blog.klaus-b.net/post/2011/12/27/Datensammlungen-uber-HTTP-serialisieren.aspx"&gt;diesem Artikel&lt;/a&gt;, das endgültige Muster:     &lt;br /&gt;&lt;strong&gt;[#|#|#|(n,n,n…)]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Zum erzeugen der Zeichenfolge, habe ich mich für eine Überladung der &lt;a title="Object.ToString Methode" href="http://msdn.microsoft.com/library/7bxwbwt2.aspx" rel="msdn nofollow"&gt;ToString&lt;/a&gt;-Methode entschlossen, die eine Zeichenfolge als Format erwartet.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7e456edc-6f0b-4a7c-9d6c-8bc9711d919b" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[46]"&gt;internal string ToString(string format)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        "[{0}|{1}|{2}|({3})]",
        this.Name,
        this.MessagingUrl,
        this.Token,
        string.Join(
            ",",
            (this.Ranges
                .Select(i =&amp;gt; i.ToString(CultureInfo.InvariantCulture)))
                .ToArray()));
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Für diesen Benchmark wird der Parameter &lt;em&gt;format&lt;/em&gt; noch nicht ausgewertet. Später könnten hier Werte wie etwa “C” für Custom oder “J” für JSON angegeben und entsprechend verarbeitet werden.&lt;/p&gt;

&lt;p&gt;Die eigentliche Serialisierung in einem &lt;em&gt;CustomFormatter&lt;/em&gt; ist eher trivial. Es wird lediglich die Auflistung durchlaufen, für jedes Element die überladene ToString(&lt;a title="String Klasse" href="http://msdn.microsoft.com/s1wwdcbf.aspx" rel="msdn nofollow"&gt;string&lt;/a&gt;)-Methode aufgerufen und die zurückgegebene Zeichenfolge in einen &lt;a title="StreamWriter Klasse" href="http://msdn.microsoft.com/library/3ssew6tk.aspx"&gt;StreamWriter&lt;/a&gt; geschrieben.&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:2f625958-4fdd-48c8-a4b1-b4695c123211" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[12]"&gt;public void Serialize(HttpResponse response, List&amp;lt;TestNode&amp;gt; data)
{
    response.ContentType = "application/json";

    using (var writer = new StreamWriter(response.OutputStream))
    {
        foreach (var entry in data)
        {
            writer.Write(entry.ToString(null));
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Die Deserialisierung ist ähnlich einfach. Der empfangene &lt;a title="Stream Klasse" href="http://msdn.microsoft.com/8f86tw9e.aspx" rel="msdn nofollow"&gt;Stream&lt;/a&gt; wird in einen &lt;a title="StreamReader Klasse" href="http://msdn.microsoft.com/6aetdk20.aspx" rel="msdn nofollow"&gt;StreamReader&lt;/a&gt; gelesen und die enthaltene Zeichenfolge, dem vorher beschriebenen Muster entsprechend, aufgeteilt und die erzeugten Fragmente jeweils einer neuen Instanz der Klasse &lt;em&gt;TestNode&lt;/em&gt; bzw. den Eigenschaften zugewiesen.&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7808fb75-5bb7-46e7-a698-4dd119874ecc" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[30]"&gt;public List&amp;lt;TestNode&amp;gt; Deserialize(Stream responseStream)
{
    var list = new List&amp;lt;TestNode&amp;gt;();
    var rawSeparator = new char[] { '[', ']' };
    var propertySeparator = new char[] { '|' };
    var rangeSeparator = new char[] { '(', ')', ',' };

    using (var reader = new StreamReader(responseStream))
    {
        var rawData = reader.ReadToEnd()
            .Split(rawSeparator, StringSplitOptions.RemoveEmptyEntries);

        foreach (var entry in rawData)
        {
            var properties = entry.Split(
                propertySeparator,
                StringSplitOptions.RemoveEmptyEntries);

            if (properties.Length &amp;lt; 1)
            {
                continue;
            }

            var ranges = properties[3]
                .Split(rangeSeparator, StringSplitOptions.RemoveEmptyEntries)
                .Select(s =&amp;gt; int.Parse(s, CultureInfo.InvariantCulture));

            var node = new TestNode
            {
                Name = properties[0],
                MessagingUrl = properties[1],
                Token = properties[2],
                Ranges = new List&amp;lt;int&amp;gt;(ranges)
            };

            list.Add(node);
        }
    }

    return list;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Die Erzeugung der temporären Variablen &lt;em&gt;ranges&lt;/em&gt;, ist nur der Übersicht halber im Code enthalten. Das Aufteilen und parsen der Zeichenfolge kann auch im Konstruktor von &lt;a title="List(T) Klasse" href="http://msdn.microsoft.com/library/6sh2ey19.aspx" rel="msdn nofollow"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt; für die Eigenschaft &lt;em&gt;Ranges&lt;/em&gt; erfolgen.&lt;/p&gt;

&lt;p&gt;Nach dem die Methodik stand wollte ich natürlich wissen, ob auch der erwartete Effekt eintrat bzw. eine verbesserte Leitung gegenüber den bisher verwendeten Serialisierern messbar ist.&lt;/p&gt;

&lt;p&gt;Der Benchmark wurde um die Messung der Deserialisierung erweitert. So kann ein besseres Gesamtbild des jeweiligen Serialisierers wiedergegeben werden. 
  &lt;br /&gt;Die Werte der Spalten &lt;em&gt;Response&lt;/em&gt;, &lt;em&gt;Deseria&lt;/em&gt;. und &lt;em&gt;Complete&lt;/em&gt; sind jeweils in Millisekunden dargestellt. &lt;em&gt;Count&lt;/em&gt; gibt die Anzahl der Elemente in der übertragenen Auflistung wieder und &lt;em&gt;Transfered&lt;/em&gt; die Anzahl der übertragenen Bytes.&lt;/p&gt;

&lt;p&gt;Ich habe kurzerhand die beschriebene Methodik als &lt;em&gt;CustomFormatter&lt;/em&gt; mit dem Kürzel &lt;em&gt;custom&lt;/em&gt; dem Benchmark hinzugefügt und dieses laufen lassen. 

  &lt;br /&gt;Was soll ich sagen; die Zahlen sprechen für sich.&lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="536"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="63" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="76" align="right"&gt;
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;968 
        &lt;br /&gt;559&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;423 
        &lt;br /&gt;364&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;219 
        &lt;br /&gt;269&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;148 
        &lt;br /&gt;246&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;5&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;5&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;148 
        &lt;br /&gt;246&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="70" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="63" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;101 
        &lt;br /&gt;209&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="535"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="62" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;2.581 
        &lt;br /&gt;1.372&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;4 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;3.494 
        &lt;br /&gt;947&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;2.300 
        &lt;br /&gt;813&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.590 
        &lt;br /&gt;773&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;3 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.590 
        &lt;br /&gt;773&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.129 
        &lt;br /&gt;723&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="535"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="62" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;3 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;29 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;32 
        &lt;br /&gt;4&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;18.611 
        &lt;br /&gt;8.831&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;3&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;33.649 
        &lt;br /&gt;6.312&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;2 
        &lt;br /&gt;3&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;3 
        &lt;br /&gt;4&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;23.005 
        &lt;br /&gt;5.713&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;6 
        &lt;br /&gt;6&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;7 
        &lt;br /&gt;8&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;15.905 
        &lt;br /&gt;5.397&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;2 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;3 
        &lt;br /&gt;3&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;15.905 
        &lt;br /&gt;5.397&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100 
        &lt;br /&gt;100&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;1 
        &lt;br /&gt;1&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1 
        &lt;br /&gt;2&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;11.304 
        &lt;br /&gt;5.125&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="535"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="62" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;11 
        &lt;br /&gt;20&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;42 
        &lt;br /&gt;26&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;53 
        &lt;br /&gt;46&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;177.927 
        &lt;br /&gt;80.243&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;5 
        &lt;br /&gt;15&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;8 
        &lt;br /&gt;10&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;13 
        &lt;br /&gt;25&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;329.784 
        &lt;br /&gt;59.224&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;6 
        &lt;br /&gt;13&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;23 
        &lt;br /&gt;26&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;29 
        &lt;br /&gt;39&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;229.068 
        &lt;br /&gt;53.906&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;11 
        &lt;br /&gt;18&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;61 
        &lt;br /&gt;65&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;72 
        &lt;br /&gt;83&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;158.068 
        &lt;br /&gt;50.626&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;5 
        &lt;br /&gt;11&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;19 
        &lt;br /&gt;21&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;24 
        &lt;br /&gt;32&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;158.068 
        &lt;br /&gt;50.626&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;1.000 
        &lt;br /&gt;1.000&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2 
        &lt;br /&gt;8&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;7 
        &lt;br /&gt;5&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;9 
        &lt;br /&gt;13&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;112.067 
        &lt;br /&gt;47.624&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="535"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="62" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;125 
        &lt;br /&gt;210&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;528 
        &lt;br /&gt;215&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;653 
        &lt;br /&gt;425&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.770.091 
        &lt;br /&gt;793.997&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;47 
        &lt;br /&gt;148&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;114 
        &lt;br /&gt;114&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;161 
        &lt;br /&gt;262&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;3.284.950 
        &lt;br /&gt;587.571&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;53 
        &lt;br /&gt;143&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;377 
        &lt;br /&gt;267&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;430 
        &lt;br /&gt;410&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;2.287.996 
        &lt;br /&gt;535.119&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;113 
        &lt;br /&gt;177&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;651 
        &lt;br /&gt;711&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;764 
        &lt;br /&gt;888&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.577.996 
        &lt;br /&gt;502.584&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;47 
        &lt;br /&gt;112&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;211 
        &lt;br /&gt;254&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;258 
        &lt;br /&gt;366&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.577.996 
        &lt;br /&gt;502.584&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;10.000 
        &lt;br /&gt;10.000&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;27 
        &lt;br /&gt;77&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;48 
        &lt;br /&gt;72&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;75 
        &lt;br /&gt;149&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;1.117.995 
        &lt;br /&gt;472.300&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;table border="1" cellspacing="0" cellpadding="2" width="535"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="62" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;&lt;strong&gt;Comp&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="76" align="center"&gt;&lt;strong&gt;Deseria&lt;/strong&gt;.&lt;/td&gt;

      &lt;td valign="top" width="85" align="center"&gt;&lt;strong&gt;Complete&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;&lt;strong&gt;Transfered&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;bin&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1.389 
        &lt;br /&gt;2.255&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;11.064 
        &lt;br /&gt;8.115&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;12.453 
        &lt;br /&gt;10.370&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;17.701.551 
        &lt;br /&gt;7.887.661&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;xml&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;457 
        &lt;br /&gt;1.424&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;916 
        &lt;br /&gt;1.161&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1.373 
        &lt;br /&gt;2.585&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;32.890.892 
        &lt;br /&gt;5.876.977&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsondata&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;523 
        &lt;br /&gt;1.300&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;2.594 
        &lt;br /&gt;2.772&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;3.117 
        &lt;br /&gt;4.072&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;22.887.368 
        &lt;br /&gt;5.349.086&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonweb&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;1.116 
        &lt;br /&gt;1.781&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;6.676 
        &lt;br /&gt;6.692&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;7.792 
        &lt;br /&gt;8.743&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;15.787.368 
        &lt;br /&gt;5.023.391&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;jsonnet&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="62" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;462 
        &lt;br /&gt;1.163&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;2.124 
        &lt;br /&gt;2.261&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;2.568 
        &lt;br /&gt;3.424&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;15.787.368 
        &lt;br /&gt;5.023.391&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td width="71" align="right"&gt;custom&lt;/td&gt;

      &lt;td valign="top" width="62" align="right"&gt;100.000 
        &lt;br /&gt;100.000&lt;/td&gt;

      &lt;td valign="bottom" width="63" align="center"&gt;gzip&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;221 
        &lt;br /&gt;842&lt;/td&gt;

      &lt;td valign="top" width="76" align="right"&gt;518 
        &lt;br /&gt;761&lt;/td&gt;

      &lt;td valign="top" width="85" align="right"&gt;739 
        &lt;br /&gt;1.603&lt;/td&gt;

      &lt;td valign="top" width="92" align="right"&gt;11.187.367 
        &lt;br /&gt;4.721.865&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Wie obige Zahlen zeigen, schlägt die kleinere Datenmenge sofort zu Buche. Das Fehlen jeglicher Typbehandlung ist in der Responsetime und der sehr kurzen Zeit für die Deserialisierung ebenfalls deutlich zu sehen.&lt;/p&gt;

&lt;p&gt;Die vorgestellte Methodik ist beileibe noch kein Produktivcode. Sie soll lediglich zeigen, dass auch einfache Ansätze zu guten Ergebnissen führen können.&lt;/p&gt;

&lt;p&gt;Der Beispielcode ist als Projekt &lt;a title="Repository bei Bitbucket" href="https://bitbucket.org/klaus_b/serializetesting" rel="cvs nofollow"&gt;SerializeTesting&lt;/a&gt; bei Bitbucket gehostet. Erweiterungen um eigene Ideen sind ausdrücklich erwünscht.&lt;/p&gt;

&lt;h4&gt;Fazit:&lt;/h4&gt;

&lt;p&gt;Es muss nicht immer ein Serialisierer mit der kompletten Funktionalität verwendet werden. 
  &lt;br /&gt;Wie bereits der Vergleich der gängigen Serialisierer untereinander gezeigt hat, kostet Overhead einfach Zeit. Ob nun das erzeugte Format oder die interne Verarbeitung der zu de/serialisierenden Objekte spielt dabei keine Rolle. Wenn konsequent auf jeglichen Overhead verzichtet wird, ist das daraus resultierende Ergebnis immer schlank und effizient. Wie weit die Entschlackung getrieben wird, ist jedem selbst überlassen.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:db4c629e-4166-45b5-a64d-7ece2600da3f" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/binary" rel="tag"&gt;binary&lt;/a&gt; | &lt;a href="http://technorati.com/tags/xml" rel="tag"&gt;xml&lt;/a&gt; | &lt;a href="http://technorati.com/tags/json" rel="tag"&gt;json&lt;/a&gt; | &lt;a href="http://technorati.com/tags/serialization" rel="tag"&gt;serialization&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=MSX0O23B1_Y:5if1hy1lzck:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=MSX0O23B1_Y:5if1hy1lzck:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=MSX0O23B1_Y:5if1hy1lzck:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/MSX0O23B1_Y" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/MSX0O23B1_Y/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2012/01/03/Binar-XML-und-JSON-vs-Custom-Serializer.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=b1b33280-710a-439c-9c96-01f01a703588</guid>
      <pubDate>Tue, 03 Jan 2012 14:22:30 +0200</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=b1b33280-710a-439c-9c96-01f01a703588</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=b1b33280-710a-439c-9c96-01f01a703588</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2012/01/03/Binar-XML-und-JSON-vs-Custom-Serializer.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=b1b33280-710a-439c-9c96-01f01a703588</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=b1b33280-710a-439c-9c96-01f01a703588</feedburner:origLink></item>
    <item>
      <title>Binär, XML und JSON-Serialisierung im Vergleich</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="binärer Code" alt="binär code" src="http://blog.klaus-b.net/image.axd?picture=binary.png" /&gt;In einem Kommentar zum &lt;a title="Datensammlungen über HTTP serialisieren" href="http://blog.klaus-b.net/post/2011/12/27/Datensammlungen-uber-HTTP-serialisieren.aspx"&gt;vorherigen Artikel&lt;/a&gt; hatte &lt;a title="Der-Albert.com sein Blog!" href="http://der-albert.com/" rel="met colleague"&gt;Albert Weinert&lt;/a&gt; angeregt, auch &lt;a title="JavaScript Object Notation" href="http://de.wikipedia.org/wiki/JSON" rel="wiki nofollow"&gt;JSON&lt;/a&gt; in den Vergleich mit einzubeziehen.     &lt;br /&gt;Da JSON, &lt;a title="JavaScript" href="http://de.wikipedia.org/wiki/JavaScript" rel="wiki nofollow"&gt;JavaScript&lt;/a&gt; und Konsorten wirklich nicht meine Welt sind, hat kurzer Hand Albert den Vergleich um drei verschiedene JSON Serialisierer ergänzt. Wer “den Albert” kennt, weis dass er keine halben Sachen macht. Ich schickte im ein kleines Testprojekt und erhielt ein komplettes Benchmark Programm zurück. Im Verlauf der Kommunikation brachte mir Albert auch JSON etwas näher und korrigierte damit meinen Blickwinkel. JSON bedeutet zwar namentlich &lt;strong&gt;JavaScript Object Notation&lt;/strong&gt; und in der &lt;a title="Wikipedia" href="http://www.wikipedia.org/" rel="wiki nofollow"&gt;Wikipedia&lt;/a&gt; steht in der Erläuterung dazu:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Jedes gültige JSON-Dokument soll ein gültiges JavaScript sein …&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Dies bedeutet aber nicht unbedingt, das JSON nur für JavaScript verwendet werden kann. Vielmehr stellt das JSON Format ein schlankes Textabbild des serialisierten Objekts ohne großen Overhead dar. Die gängigen JSON Serialisierer bieten alle sehr einfach zu handhabende Methoden zum Serialisieren und Deserialisieren von Objekten.&lt;/p&gt;  &lt;p&gt;Zum direkten Vergleich der Effektivität verschiedener Methoden und Formate der Serialisierung, sind jetzt insgesamt fünf Serialisierer am Start. Die im Benchmark verwendeten Formatkürzel sowie die entsprechenden Produkte sind wie folgt aufgeschlüsselt.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;bin:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/strong&gt;&lt;a title="BinaryFormatter Klasse" href="http://msdn.microsoft.com/library/y50tb888.aspx" rel="msdn nofollow"&gt;BinaryFormatter&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;xml:&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a title="XmlSerializer Klasse" href="http://msdn.microsoft.com/library/swxzdhc0.aspx" rel="msdn nofollow"&gt;XmlSerializer&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;jsondata:&lt;/strong&gt;&amp;#160; &lt;a title="DataContractJsonSerializer Klasse" href="http://msdn.microsoft.com/library/bb908432.aspx" rel="msdn nofollow"&gt;DataContractJsonSerializer&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;jsonweb:&lt;/strong&gt;&amp;#160; &lt;a title="JavaScriptSerializer Klasse" href="http://msdn.microsoft.com/library/bb337495.aspx" rel="msdn nofollow"&gt;JavaScriptSerializer&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;jsonnet:&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160; &lt;a title="Json.NET - Serialize all the things" href="http://json.codeplex.com/"&gt;Json.NET&lt;/a&gt; von &lt;a title="James Newton-King - No pressure, no diamonds" href="http://james.newtonking.com/" rel="colleague"&gt;James Newton-King&lt;/a&gt;. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Um einheitliche Testbedingungen zu schaffen, wird für jeden Durchgang die benötigte Anzahl an Datensätzen einmal erzeugt und für alle Serialisierer verwendet. Jeder Serialisierer wird zweimal, einmal mit und einmal ohne &lt;a title="gzip Kompression" href="http://de.wikipedia.org/wiki/Gzip" rel="wiki nofollow"&gt;GZip&lt;/a&gt; Komprimierung, verwendet und die benötigte Zeit in Millisekunden sowie die übertragene Datenmenge in Bytes erfasst. Es werden fünf Durchgänge mit 10, 100, 1.000, 10.000 und 100.000 Elementen ausgewertet.&lt;/p&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="500" align="center"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="82" align="center"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="71" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="116" align="center"&gt;&lt;strong&gt;Compression&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="112" align="center"&gt;&lt;strong&gt;Milliseconds&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="115" align="center"&gt;&lt;strong&gt;Bytes Transfered&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;bin&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10          &lt;br /&gt;10&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1          &lt;br /&gt;2&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;2.609          &lt;br /&gt;1.390&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;xml&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10          &lt;br /&gt;10&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1          &lt;br /&gt;2&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;3.638          &lt;br /&gt;972&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsondata&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10          &lt;br /&gt;10&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;2          &lt;br /&gt;3&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;2.318          &lt;br /&gt;844&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonweb &lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10          &lt;br /&gt;10&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;2&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;1.608          &lt;br /&gt;801&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonnet&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10          &lt;br /&gt;10&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;         &lt;br /&gt;1&lt;/td&gt;        &lt;td valign="top" width="116" align="right"&gt;1.608          &lt;br /&gt;801&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="500" align="center"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="82" align="center"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="71" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="116" align="center"&gt;&lt;strong&gt;Compression&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="112" align="center"&gt;&lt;strong&gt;Milliseconds&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="115" align="center"&gt;&lt;strong&gt;Bytes Transfered&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;bin&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100          &lt;br /&gt;100&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;2          &lt;br /&gt;3&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;18.559          &lt;br /&gt;8.832 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;xml&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100          &lt;br /&gt;100&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1          &lt;br /&gt;2&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;33.344          &lt;br /&gt;6.243 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsondata&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100          &lt;br /&gt;100&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1          &lt;br /&gt;3&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;22.934          &lt;br /&gt;5.717&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonweb &lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100          &lt;br /&gt;100&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;8          &lt;br /&gt;5&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;15.834          &lt;br /&gt;5.382 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonnet&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100          &lt;br /&gt;100&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1          &lt;br /&gt;2&lt;/td&gt;        &lt;td valign="top" width="116" align="right"&gt;15.834          &lt;br /&gt;5.382 &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="500" align="center"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="82" align="center"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="71" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="116" align="center"&gt;&lt;strong&gt;Compression&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="112" align="center"&gt;&lt;strong&gt;Milliseconds&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="115" align="center"&gt;&lt;strong&gt;Bytes Transfered&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;bin&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;1.000          &lt;br /&gt;1.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;16          &lt;br /&gt;21&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;177.939          &lt;br /&gt;80.238 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;xml&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;1.000          &lt;br /&gt;1.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;9          &lt;br /&gt;22&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;329.675          &lt;br /&gt;58.287 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsondata&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;1.000          &lt;br /&gt;1.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;9          &lt;br /&gt;14&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;228.905          &lt;br /&gt;53.838&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonweb &lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;1.000          &lt;br /&gt;1.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;17          &lt;br /&gt;22&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;157.905          &lt;br /&gt;50.209 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonnet&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;1.000          &lt;br /&gt;1.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;7          &lt;br /&gt;43&lt;/td&gt;        &lt;td valign="top" width="116" align="right"&gt;157.905          &lt;br /&gt;50.209 &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="500" align="center"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="82" align="center"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="71" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="116" align="center"&gt;&lt;strong&gt;Compression&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="112" align="center"&gt;&lt;strong&gt;Milliseconds&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="115" align="center"&gt;&lt;strong&gt;Bytes Transfered&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;bin&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10.000          &lt;br /&gt;10.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;125          &lt;br /&gt;214&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;1.772.619          &lt;br /&gt;795.178 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;xml&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10.000          &lt;br /&gt;10.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;69          &lt;br /&gt;185&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;3.298.716          &lt;br /&gt;580.353 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsondata&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10.000          &lt;br /&gt;10.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;62          &lt;br /&gt;130&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;2.290.386          &lt;br /&gt;536.307&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonweb &lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10.000          &lt;br /&gt;10.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;116          &lt;br /&gt;183&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;1.580.386          &lt;br /&gt;500.012 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonnet&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;10.000          &lt;br /&gt;10.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;51          &lt;br /&gt;116&lt;/td&gt;        &lt;td valign="top" width="116" align="right"&gt;1.580.386          &lt;br /&gt;500.012 &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;table border="2" cellspacing="0" cellpadding="2" width="500" align="center"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="82" align="center"&gt;&lt;strong&gt;Format&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="71" align="center"&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="116" align="center"&gt;&lt;strong&gt;Compression&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="112" align="center"&gt;&lt;strong&gt;Milliseconds&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="115" align="center"&gt;&lt;strong&gt;Bytes Transfered&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;bin&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100.000          &lt;br /&gt;100.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1.441          &lt;br /&gt;2.248&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;17.700.411          &lt;br /&gt;7.883.815 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;xml&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100.000          &lt;br /&gt;100.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;883          &lt;br /&gt;1.584&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;32.885.009          &lt;br /&gt;5.782.222 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsondata&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100.000          &lt;br /&gt;100.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;582          &lt;br /&gt;1.328&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;22.886.615          &lt;br /&gt;5.349.126&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonweb &lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100.000          &lt;br /&gt;100.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;1.151          &lt;br /&gt;1.833&lt;/td&gt;        &lt;td valign="top" width="115" align="right"&gt;15.786.615          &lt;br /&gt;4.987.282 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td width="82"&gt;jsonnet&lt;/td&gt;        &lt;td valign="top" width="71" align="right"&gt;100.000          &lt;br /&gt;100.000&lt;/td&gt;        &lt;td valign="bottom" width="116" align="right"&gt;gzip&lt;/td&gt;        &lt;td valign="top" width="112" align="right"&gt;570          &lt;br /&gt;1.156&lt;/td&gt;        &lt;td valign="top" width="116" align="right"&gt;15.786.615          &lt;br /&gt;4.987.282 &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Wie in obigen Tabellen ersichtlich, setzen sich die beiden JSON Serialisierer &lt;em&gt;JavaScriptSerializer&lt;/em&gt; und &lt;em&gt;Json.NET&lt;/em&gt; in der Datengröße deutlich ab. Interessant auch die Beobachtung, dass beide Serialisierer die exakt gleiche Datenmenge übertragen.     &lt;br /&gt;&lt;em&gt;Json.NET&lt;/em&gt; scheint, im Vergleich zum &lt;em&gt;JavaScriptSerializer,&lt;/em&gt; effizientere Methoden zur Serialisierung zu verwenden, da er die Daten zum Teil doppelt so schnell liefert.&lt;/p&gt;  &lt;p&gt;Interessierte können sich das Projekt gerne für eigene Tests herunterladen.&lt;/p&gt;  &lt;p&gt;&lt;a title="SerializeTesting.zip herunterladen" href="http://klaus-b.net/Downloads/Download.aspx?fileID=05b569a0-6bba-4717-9bb3-69931b58a6f0" rel="nofollow"&gt;SerializeTesting.zip&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;Fazit:&lt;/h3&gt;  &lt;p&gt;Wer, wie ich, bis dato JSON bei der Serialisierung immer übersehen hat, sollte dies schleunigst ändern. Man sollte einfach das JS für JavaScript in JSON nicht überbewerten. Beherzigt man diesen Rat, hat man ein schlankes und schnelles Format zur Serialisierung der meisten .NET Objekte.    &lt;br /&gt;An dieser Stelle möchte ich mich noch einmal besonders bei Alber Weinert für die tatkräftige Unterstützung und das zurechtrücken meiner Sichtweise bedanken.&lt;/p&gt;  &lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8eba222a-6268-4b9c-b1f4-ca98a47872ba" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/binary" rel="tag"&gt;binary&lt;/a&gt; | &lt;a href="http://technorati.com/tags/xml" rel="tag"&gt;xml&lt;/a&gt; | &lt;a href="http://technorati.com/tags/json" rel="tag"&gt;json&lt;/a&gt; | &lt;a href="http://technorati.com/tags/serialization" rel="tag"&gt;serialization&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=nqJ3vCbal58:m6t6mbnuY6Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=nqJ3vCbal58:m6t6mbnuY6Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=nqJ3vCbal58:m6t6mbnuY6Y:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/nqJ3vCbal58" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/nqJ3vCbal58/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/12/30/Binar-XML-und-JSON-Serialisierung-im-Vergleich.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=922cb5ce-cd31-44c9-83a1-6cee9c5e06bb</guid>
      <pubDate>Fri, 30 Dec 2011 15:21:03 +0200</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=922cb5ce-cd31-44c9-83a1-6cee9c5e06bb</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=922cb5ce-cd31-44c9-83a1-6cee9c5e06bb</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/12/30/Binar-XML-und-JSON-Serialisierung-im-Vergleich.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=922cb5ce-cd31-44c9-83a1-6cee9c5e06bb</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=922cb5ce-cd31-44c9-83a1-6cee9c5e06bb</feedburner:origLink></item>
    <item>
      <title>Datensammlungen über HTTP serialisieren</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="binär code" alt="binärer Code" src="http://blog.klaus-b.net/image.axd?picture=binary.png" width="294" height="172" /&gt;...aber in welchem Format?     &lt;br /&gt;Mein erster Kandidat - und heimlicher Favorit - war hier die binäre Serialisierung mit dem &lt;a title="BinaryFormatter Klasse" href="http://msdn.microsoft.com/library/y50tb888.aspx" rel="msdn nofollow"&gt;BinaryFormatter&lt;/a&gt;.     &lt;br /&gt;Für einen Vergleich habe ich den &lt;a title="XmlSerializer Klasse" href="http://msdn.microsoft.com/library/swxzdhc0.aspx" rel="msdn nofollow"&gt;XmlSerializer&lt;/a&gt; herangezogen, wobei ich Anfangs die binäre Serialisierung als klaren Favoriten ansah. Bei lokaler Verwendung, zum speichern von Kollektionen wie etwa &lt;a title="List(T) Klasse" href="http://msdn.microsoft.com/library/6sh2ey19.aspx" rel="msdn nofollow"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt; oder &lt;a title="Collection(T) Klasse" href="http://msdn.microsoft.com/library/ms132397.aspx" rel="msdn nofollow"&gt;Collection&amp;lt;T&amp;gt;&lt;/a&gt; in einer Datei, zeigte der BinaryFormatter immer sehr gute Ergebnisse. Die hohe Datendichte bei vergleichsweise kleiner Dateigröße ist einer seiner großen Vorteile gegenüber der Serialisierung in eine Datei im &lt;a title="Extensible Markup Language" href="http://de.wikipedia.org/wiki/XML" rel="wiki nofollow"&gt;XML&lt;/a&gt;-Format. Warum sollte dieser Vorteil nicht auch beim Transport über &lt;a title="Hypertext Transfer Protocol" href="http://de.wikipedia.org/wiki/Http" rel="wiki nofollow"&gt;HTTP&lt;/a&gt; zum tragen kommen?&lt;/p&gt;  &lt;p&gt;&lt;img class="rightImg" title="TestNode" alt="TestNode" src="http://blog.klaus-b.net/image.axd?picture=TestNode.png" width="259" height="223" /&gt;Nun aber der Reihe nach.     &lt;br /&gt;In einem aktuellem Projekt ist eine der Anforderungen, eine Auflistung von Informationen über einzelne Knoten eines Netzwerks bereitzustellen. Diese Auflistung ändert sich mit der Verfügbarkeit einzelner Knoten und soll an einem zentralen Ort, für alle Knoten zugänglich, bereitgestellt werden.     &lt;br /&gt;Die Funktionalität entspricht in etwa einem &lt;a title="rendezvous host" href="http://en.wikipedia.org/wiki/Bootstrapping_node" rel="wiki nofollow"&gt;Boostrapping Node&lt;/a&gt;, oder Rendezvous Host, eines &lt;a title="Peer-to-Peer P2P" href="http://de.wikipedia.org/wiki/Peer-to-Peer" rel="wiki nofollow"&gt;Peer-to-Peer&lt;/a&gt; Netzes. Wie an der Aufgabenstellung bereits ersichtlich, geht es hier um die Kommunikation zwischen Maschinen. HTTP wurde als Transportprotokoll gewählt, um Probleme mit der &lt;a title="Erklärung des Begriffs Firewall" href="http://de.wikipedia.org/wiki/Firewall" rel="wiki nofollow"&gt;Firewall&lt;/a&gt; der beteiligten Maschinen zu vermeiden.     &lt;br /&gt;Die Visualisierung der Daten in irgendwelchen UIs spielt keine Rolle und ist auch nicht vorgesehen. Auf die Befindlichkeiten von Benutzern braucht nicht eingegangen zu werden. Insofern kann auf die Notwendigkeit der Kompatibilität zu Formaten wie &lt;a title="JavaScript Object Notation" href="http://de.wikipedia.org/wiki/JSON" rel="wiki nofollow"&gt;JSON&lt;/a&gt; udgl. verzichtet werden.     &lt;br /&gt;Für die Testumgebung habe ich eine vereinfachte Klasse, siehe obige Grafik, verwendet, die sich auf wenige öffentliche Eigenschaften und die überschriebene Methode &lt;a title="Object.ToString Methode" href="http://msdn.microsoft.com/library/7bxwbwt2.aspx" rel="msdn nofollow"&gt;ToString&lt;/a&gt; beschränkt. Für eine Simulation und Begutachtung der Bedingungen ist dies vorerst vollkommen ausreichend.     &lt;br /&gt;Zum bereitstellen der Kollektion wird ein &lt;a title="IHttpHandler Interface" href="http://msdn.microsoft.com/library/7ezc17x8.aspx" rel="msdn nofollow"&gt;IHttpHandler&lt;/a&gt; in einer &lt;a title="ASP.NET" href="http://msdn.microsoft.com/library/bb400852.aspx" rel="msdn nofollow"&gt;ASP.NET&lt;/a&gt;-Anwendung verwendet, der die Auflistung in der benötigten Größe dynamisch erzeugt. Die Namen der Knoten werden mit dem Präfix &lt;em&gt;Node_&lt;/em&gt; durchnummeriert. Die MessagingUrl wird aus dem Namen erzeugt und mit einem fiktiven Handler ergänzt. Der Token wird mit der Zeichenfolgendarstellung einer &lt;a title="Guid Struktur" href="http://msdn.microsoft.com/cey1zx63.aspx" rel="msdn nofollow"&gt;Guid&lt;/a&gt; simuliert und die Liste der Eigenschaft Ranges wird in zufälliger Länge mit zufälligem Inhalt erzeugt.     &lt;br /&gt;Der Handler verarbeitet die beiden Parameter &lt;em&gt;format&lt;/em&gt; und &lt;em&gt;size&lt;/em&gt;. Mit &lt;em&gt;format&lt;/em&gt; wird entweder binäre oder XML serialisiert. &lt;em&gt;Size&lt;/em&gt; gibt die Anzahl der Elemente in der Auflistung an.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c9309851-0a86-4529-965b-e8b2ec7ca6e6" class="wlWriterEditableSmartContent" 0px?="0px?" padding-top:="padding-top:" none;="none;" float:="float:" inline;="inline;" display:="display:"&gt;&lt;pre name="code" class="c#:firstline[23]"&gt;public void ProcessRequest(HttpContext context)
{
    if (context == null)
    {
        return;
    }

    var format = context.Request.QueryString["format"];
    var size = int.Parse(
		context.Request.QueryString["size"],
		CultureInfo.InvariantCulture);
    this.data = this.data ?? SerializationHandler.CreateData(size);
    context.Response.ContentEncoding = Encoding.UTF8;

    switch (format)
    {
        case "bin":
            context.Response.ContentType = "application/octet-stream";
            var binFormatter = new BinaryFormatter();
            binFormatter.Serialize(context.Response.OutputStream, this.data);
            break;

        case "xml":
        default:
            context.Response.ContentType = "application/xml";
            var xmlFormatter = new XmlSerializer(typeof(List&amp;lt;TestNode&amp;gt;));
            xmlFormatter.Serialize(context.Response.OutputStream, this.data);
            break;
    }
}

private static List&amp;lt;TestNode&amp;gt; CreateData(int entriesCount)
{
    var list = new List&amp;lt;TestNode&amp;gt;(entriesCount);
    var i = 0;
    var lengthRandom = new Random();
    var contenRandom = new Random();

    while (i &amp;lt; entriesCount)
    {
        var node = new TestNode();
        node.Name = "Node_" + i.ToString("D6", CultureInfo.InvariantCulture);
        node.MessagingUrl = "http://node." + node.Name + ".net/messaging.axd";
        node.Token = Guid.NewGuid().ToString();
        var length = lengthRandom.Next(1, 10);
        node.Ranges = new List&amp;lt;int&amp;gt;(length);
        var j = 0;

        while (j &amp;lt; length)
        {
            node.Ranges.Add(contenRandom.Next(1, 254));
            j++;
        }

        list.Add(node);
        i++;
    }

    return list;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wie bereits weiter oben angesprochen, ist lediglich die Größe der übertragenen Daten von vorrangigem Interesse, da die Auflistung häufigen Änderungen unterworfen ist und oft abgerufen werden kann. Zur Bestimmung der Größe der übertragenen Daten bei der unterschiedlichen Anzahl der Einträge, verwende ich den Composer von &lt;a title="Fiddler - Http Debugging Proxy" href="http://www.fiddler2.com/fiddler2/" rel="nofollow"&gt;Fiddler&lt;/a&gt;, der sehr einfach die Änderung des &lt;a title="Erklärung Query String" href="http://de.wikipedia.org/wiki/Query_String" rel="wiki nofollow"&gt;Query-String&lt;/a&gt; und der &lt;a title="Erklärung der Request Header Felder" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.3" rel="nofollow"&gt;Request-Header&lt;/a&gt; zulässt.&lt;/p&gt;

&lt;p&gt;Für einen ersten Vergleich habe ich eine Auflistung jeweils binär und als XML serialisiert mit 100, 1.000, 10.000 und 100.000 Einträgen verglichen. (Siehe folgende Grafik)&lt;/p&gt;

&lt;p&gt;&lt;img class="centerImg" title="erster einfacher Test" alt="einfacher Test" src="http://blog.klaus-b.net/image.axd?picture=plainTest.png" width="528" height="266" /&gt;&lt;/p&gt;

&lt;p&gt;Wie erwartet, ist die übertragene Datenmenge der XML-serialisierten Auflistungen beinahe doppelt so groß wie die binär serialisierten. Auch interessant zu beobachten war die Tatsache, dass die XML-Serialisierung schneller als die binär-Serialisierung wurde, je weiter die Anzahl der Elemente stieg. Bei 1.000 Einträgen benötigte binär 92ms und XML 69ms für den Transport. 
  &lt;br /&gt;Bei 10.000 Einträgen 298ms zu 92ms und bei 100.000 Einträgen immerhin schon 1800ms zu 820ms.&lt;/p&gt;

&lt;p&gt;Als nächste Maßnahme zog ich die Kompression der übertragenen Daten via &lt;a title="gzip Kompression" href="http://de.wikipedia.org/wiki/Gzip" rel="wiki nofollow"&gt;GZip&lt;/a&gt; in Betracht. Die Kompression wird nicht vom &lt;a title="Microsoft Internet Information Services" href="http://de.wikipedia.org/wiki/Microsoft_Internet_Information_Services" rel="wiki nofollow"&gt;IIS&lt;/a&gt; , sondern von einem eigenem &lt;a title="IHttpModule Interface" href="http://msdn.microsoft.com/library/wc2zw2d4.aspx" rel="msdn nofollow"&gt;IHttpModule&lt;/a&gt; vorgenommen. Damit bleibt mehr Spielraum für weitere Optimierungen. 

  &lt;br /&gt;Mit der Kompression sollte XML einen Vorsprung erfahren, da sich erfahrungsgemäß Textinhalte besser komprimieren lassen als binäre Daten.&lt;/p&gt;

&lt;p&gt;&lt;img class="centerImg" title="Test mit Komprimierung" alt="Test der Komprimierung" src="http://blog.klaus-b.net/image.axd?picture=compressedTest.png" width="535" height="265" /&gt;&lt;/p&gt;

&lt;p&gt;Wie obige Grafik zeigt, lassen sich auch die binären Daten noch auf über die Hälfte ihrer ursprünglichen Größe komprimieren. XML zieht, in der reinen Größe der übertragenen Daten, mit einem Kompressionsfaktor von rund 5,8 deutlich vorbei. 
  &lt;br /&gt;Da die Kompression Zeit kostet, sind die Transportzeiten beinahe gleich. Erst bei 100.000 Einträgen macht XML mit rund 1,8s gegenüber 2,5s etwas Boden gut.&lt;/p&gt;

&lt;p&gt;Als vorläufig letzte Maßnahme, kommt noch ein &lt;a title="HttpResponse.Filter Eigenschaft" href="http://msdn.microsoft.com/library/xtzd8yzd.aspx" rel="msdn nofollow"&gt;HttpResponse.Filter&lt;/a&gt; zum Einsatz, der überflüssige Zeilenumbrüche und Leerzeichen aus dem generierten XML entfernt. Das Prinzip eines solchen Filters, habe ich schon einmal in einem &lt;a title="Nutzlosen Whitespace zur Laufzeit aus dem HTML entfernen" href="http://blog.klaus-b.net/post/2010/02/13/Nutzlosen-Whitespace-zur-Laufzeit-aus-dem-HTML-entfernen.aspx"&gt;früheren Artikel&lt;/a&gt; beschrieben. &lt;/p&gt;

&lt;p&gt;&lt;img class="centerImg" title="Test mit Komprimierung und Whitespace Filter" alt="Test mit Komprimierung und Filter" src="http://blog.klaus-b.net/image.axd?picture=compressedFilterTest.png" width="538" height="268" /&gt;&lt;/p&gt;

&lt;p&gt;Der Filter brachte noch einmal eine Ersparnis von rund 3.5% der übertragenen Datenmenge. 
  &lt;br /&gt;Allerdings auf Kosten der Zeit, denn das Filtern ist relativ zeitaufwendig. Bei 100.000 Datensätzen verlängerte sich die Transportzeit von 1,8s auf stolze 3,1s und somit langsamer als die binäre Serialisierung der gleichen Datensätze.&lt;/p&gt;

&lt;p&gt;Eine weitere Möglichkeit die Datenmenge zu reduzieren, besteht in der Minimierung des ausgegeben XML. Dabei werden die Namen der Tags durch entsprechend kurze Zeichenfolgen ersetzt. Z.B.: &amp;lt;MessagingUrl&amp;gt; durch &amp;lt;MU&amp;gt; oder &amp;lt;Token&amp;gt; durch &amp;lt;T&amp;gt;. Mit den Daten aus dem obigen Beispiel, können so noch einmal rund 8% eingespart werden. 
  &lt;br /&gt;Es darf dann nicht vergessen werden, beim Deserialisieren des XML, die Minimierung wieder rückgängig zu machen.&lt;/p&gt;

&lt;h3&gt;Fazit:&lt;/h3&gt;

&lt;p&gt;Die Einstellung zu meinem anfänglichem Favoriten hat sich geändert. Wenn eine überschaubare Menge an Daten einfach und effizient serialisiert werden sollen, ist der BinaryFormatter nach wie vor die erste Wahl. 
  &lt;br /&gt;Soll die Serialisierung maximal optimiert werden, bietet der XmlSerializer deutlich mehr Möglichkeiten ohne einen komplett eigenen Serializer entwickeln zu müssen.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b39fe043-017e-4d73-b9a6-8bb9f551d526" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/serialization" rel="tag"&gt;serialization&lt;/a&gt; | &lt;a href="http://technorati.com/tags/xml" rel="tag"&gt;xml&lt;/a&gt; | &lt;a href="http://technorati.com/tags/binary" rel="tag"&gt;binary&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" rel="tag"&gt;asp.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" rel="tag"&gt;c#&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=eayEb7JtMfY:ZiXGkSDntg0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=eayEb7JtMfY:ZiXGkSDntg0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=eayEb7JtMfY:ZiXGkSDntg0:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/eayEb7JtMfY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/eayEb7JtMfY/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/12/27/Datensammlungen-uber-HTTP-serialisieren.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=abd6251d-e15b-4f86-8eb9-37a65e009dac</guid>
      <pubDate>Tue, 27 Dec 2011 12:15:10 +0200</pubDate>
      <category>C#</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=abd6251d-e15b-4f86-8eb9-37a65e009dac</pingback:target>
      <slash:comments>5</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=abd6251d-e15b-4f86-8eb9-37a65e009dac</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/12/27/Datensammlungen-uber-HTTP-serialisieren.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=abd6251d-e15b-4f86-8eb9-37a65e009dac</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=abd6251d-e15b-4f86-8eb9-37a65e009dac</feedburner:origLink></item>
    <item>
      <title>404 Fehlerbehandlung in BlogEngine.NET 2.0</title>
      <description>&lt;p&gt;&lt;img  class="leftImg" title="BlogEngine.NET" alt="BlogEngine.NET" src="http://blog.klaus-b.net/image.axd?picture=logo.png" /&gt;&lt;/p&gt;  &lt;p&gt;Wie ich bereits in den beiden früheren Artikeln &lt;a title="BlogEngine.NET und 404 Fehler" href="http://blog.klaus-b.net/post/2010/02/19/BlogEngineNET-und-404-Fehler.aspx"&gt;BlogEngine.NET und 404 Fehler&lt;/a&gt; sowie &lt;a title="Eine bessere 404 Fehlerbehandlung in Blogengine.NET" href="http://blog.klaus-b.net/post/2010/03/06/Eine-bessere-404-Fehlerbehandlung-in-BlogengineNET.aspx"&gt;Eine bessere 404 Fehlerbehandlung in Blogengine.NET&lt;/a&gt; beschrieben habe, gibt die 404-Fehlerbehandlung von &lt;a title="Blogengine.NET. An innovative open source blogging platform developed with ASP.NET 2.0" href="http://www.dotnetblogengine.net/" rel="nofollow"&gt;BlogEngine.NET&lt;/a&gt; immer wieder Anlass zur Kritik. Auch in der aktuellen Version 2.0 hat sich daran kaum etwas geändert. Zwar wird per Standard in der &lt;em&gt;web.config&lt;/em&gt; richtigerweise die Methode &lt;em&gt;ResponseRewrite&lt;/em&gt; zur Weiterleitung auf die Fehlerseite angegeben, aber damit erschöpft es sich auch schon in einer sauberen Behandlung von 404-Fehlern.&lt;/p&gt;  &lt;p&gt;Als gröbsten Fehler sehe ich hier den zurückgelieferten Statuscode 200 OK an, wenn die Fehlerseite &lt;em&gt;error.aspx&lt;/em&gt; angezeigt wird. Für einen Benutzer mag das keine Rolle spielen, aber die Bots von Suchmaschinen sehen das ganz anders. Da wird die angezeigte Fehlerseite statt der falsch angeforderten Seite in den Index eingetragen. Für die Suchmaschinen ist demzufolge die eigentlich nicht vorhandene Seite sehr wohl vorhanden.     &lt;br /&gt;Dem kann leicht abgeholfen werden, in dem mit der Fehlerseite error404.aspx auch der Statuscode 404 ausgeliefert wird. Dazu einfach, am Ende der Methode &lt;a title="Control.Load Ereignis" href="http://msdn.microsoft.com/abk3yt37.aspx" rel="msdn nofollow"&gt;Page_Load&lt;/a&gt;, den Statuscode 404 an die Eigenschaft &lt;em&gt;StatusCode&lt;/em&gt; des &lt;em&gt;Response&lt;/em&gt;-Objekts übergeben.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:242d0512-243b-46b7-ae29-c10fc9746ca5" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;Page.Title += Server.HtmlEncode(" - " + "Seite nicht gefunden");
Response.StatusCode = (int)HttpStatusCode.NotFound;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Diese kleine Maßnahme zeigt sofort den gewünschten Effekt. Ohne 302-Weiterleitung wird sofort der Status 404 zurückgegeben.&lt;/p&gt;

&lt;p&gt;&lt;img class="centerImg" title="Statuscode 404 mit ResponseWrite" alt="Statuscode 404 mit ResponseWrite" src="http://blog.klaus-b.net/image.axd?picture=rewriteStatus404.png" width="520" height="162" /&gt;&lt;/p&gt;

&lt;p&gt;Eine weitere, sehr unschöne, Tatsache stellt der Versuch der Verwendung des Wertes &lt;em&gt;aspxerrorpath&lt;/em&gt; aus dem &lt;a title="HttpRequest.QueryString Eigenschaft" href="http://msdn.microsoft.com/ktw1eyx1.aspx" rel="msdn nofollow"&gt;QueryString&lt;/a&gt; dar. Dieser Wert wird bei der Verwendung der &lt;em&gt;ResponseWrite&lt;/em&gt; Methode von &lt;a title="ASP.NET" href="http://msdn.microsoft.com/bb400852.aspx" rel="msdn nofollow"&gt;ASP.NET&lt;/a&gt; nicht mehr erzeugt. Somit wurde ein sehr schönes Feature der Seite &lt;em&gt;error404.aspx&lt;/em&gt;, die Suche nach ähnlichen Seiten wie der angegebenen, komplett ausgehebelt. 

  &lt;br /&gt;Nun, mit einem kleinen Eingriff in die Fehlerseite &lt;em&gt;error404.aspx&lt;/em&gt; lässt sich dieser Umstand wieder beheben wie folgender Screenshot zeigt. Dabei wird bei der, aus obigem Screenshot, falsch angeforderten Seite &lt;em&gt;BlogEngine.NET Update auf Version 2.0.0.69&lt;/em&gt; die richtige Seite &lt;em&gt;BlogEngine.NET Update auf Version 2.0.0.66&lt;/em&gt; vorgeschlagen.&lt;/p&gt;

&lt;p&gt;&lt;img class="centerImg" title="Fehlerseite mit Titelvorschlag" alt="error404.aspx" src="http://blog.klaus-b.net/image.axd?picture=error404aspx.png" width="520" height="333" /&gt;&lt;/p&gt;

&lt;p&gt;Da, wie bereits oben angesprochen, der Eintrag &lt;em&gt;aspxerrorpath&lt;/em&gt; im QueryString nicht mehr zur Verfügung steht, muss der Pfad der falsch angeforderten Seite auf andere Weise ermittelt werden. Am besten eignet sich hierfür die Eigenschaft &lt;em&gt;Message&lt;/em&gt; der zuletzt geworfenen Ausnahme. Da ASP.NET auf die Fehlerseite eines 404-Fehlers umgeleitet hat, sollte auch ein solcher von der Methode &lt;a title="HttpServerUtility.GetLastError Methode" href="http://msdn.microsoft.com/066kfzc0.aspx" rel="msdn nofollow"&gt;GetLastError&lt;/a&gt; des &lt;em&gt;Server&lt;/em&gt;-Objekts der aktuellen Seite zurückgegeben werden. Jetzt muss nur noch der Pfad der nicht gefundenen Seite aus der Fehlernachricht extrahiert werden und der Ablauf kann erfolgen wie bisher. Um den Pfad der falsch angeforderten Seite für die gesamte Klasse zur Verfügung zu stellen, speichere ich diesen in einer klassenweiten Variablen. 

  &lt;br /&gt;Um die Änderungen ersichtlicher zu gestalten, habe ich den ursprünglichen Code nur auskommentiert. Als erstes wird die Methode &lt;em&gt;Page_Load&lt;/em&gt; angepasst:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:aa8066fb-abd8-4a1c-9616-3d0b810a753b" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[12]"&gt;/// &amp;lt;summary&amp;gt;
/// Hält den Pfad der falsch angeforderten Seite
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
private string errorPath;

protected void Page_Load(object sender, EventArgs e)
{
    this.errorPath = this.Request.QueryString["aspxerrorpath"];
    var ex = this.Server.GetLastError();

    if (string.IsNullOrEmpty(this.errorPath) &amp;amp;&amp;amp; ex != null)
    {
        var index = ex.Message.IndexOf("/post/");
        var temp = ex.Message.Substring(index);
        this.errorPath = temp.Substring(0, temp.IndexOf(" "));
    }

    //if (Request.QueryString["aspxerrorpath"] != null
    //  &amp;amp;&amp;amp; Request.QueryString["aspxerrorpath"].Contains("/post/"))
    if (!string.IsNullOrEmpty(this.errorPath) &amp;amp;&amp;amp; this.errorPath.Contains("/post/"))
    {
        DirectHitSearch();
        divDirectHit.Visible = true;
    }
    else if (Request.UrlReferrer == null)
    {
        divDirectHit.Visible = true;
    }
    else if (Request.UrlReferrer.Host == Request.Url.Host)
    {
        divInternalReferrer.Visible = true;
    }
    else if (GetSearchKey() != string.Empty)
    {
        SearchTerm = GetSearchTerm(GetSearchKey());
        BindSearchResult();
        divSearchEngine.Visible = true;
    }
    else if (Request.UrlReferrer != null)
    {
        divExternalReferrer.Visible = true;
    }

    Page.Title += Server.HtmlEncode(" - " + "Seite nicht gefunden");
    Response.StatusCode = (int)HttpStatusCode.NotFound;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Damit mögliche passende Seiten vorgeschlagen werden können, muss auch die Methode &lt;em&gt;DirectHitSearch&lt;/em&gt; eine kleine Änderung erfahren:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bcc4c13f-f896-40b7-8e3e-6fee5693b027" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[59]"&gt;private void DirectHitSearch()
{
    string from = this.errorPath; //Request.QueryString["aspxerrorpath"];
    int index = from.LastIndexOf("/") + 1;
    string title = from.Substring(index)
        .Replace(".aspx", string.Empty).Replace("-", " ");

    List&amp;lt;IPublishable&amp;gt; items = Search.Hits(title, false);
    if (items.Count &amp;gt; 0)
    {
        LiteralControl result = new LiteralControl(
            string.Format(
                "&amp;lt;li&amp;gt;&amp;lt;a href=\"{0}\"&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;",
                items[0].RelativeLink.ToString(),
                items[0].Title));
        phSearchResult.Controls.Add(result);
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Fazit:&lt;/h4&gt;

&lt;p&gt;Dies war bestimmt nicht die letzte Anpassung von Fehlerseiten unter BlogEngine.NET. 
  &lt;br /&gt;Für Heute oder Morgen war ursprünglich der Release Kandidat für BlogEngine.NET 2.5 angekündigt. Da im Moment das Repository auf &lt;a title="CodePlex - Open Source Project Hosting" href="http://www.codeplex.com/" target="_blank"&gt;CodePlex&lt;/a&gt; beschädigt ist, wird sich die Veröffentlichung ein wenig verzögern. 

  &lt;br /&gt;BlogEngine.NET hat sich seit der Veröffentlichung der Version 2.0 sehr zum Positiven verändert. Es wurde und wird viel für eine breitere Akzeptanz getan. Doch solange sich solche “Feature” im Code verbergen, wird sich an der breiten Meinung: “nur für .NET Bastler” nicht viel ändern.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:6a634984-6b6b-4c3c-b915-006c44248f37" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" title="blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" title="asp.net" rel="tag"&gt;asp.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/404+error" title="404 error" rel="tag"&gt;404 error&lt;/a&gt; | &lt;a href="http://technorati.com/tags/seo" title="seo" rel="tag"&gt;seo&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=KEDq3aR90aM:Bwqd80zhhpA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=KEDq3aR90aM:Bwqd80zhhpA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=KEDq3aR90aM:Bwqd80zhhpA:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/KEDq3aR90aM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/KEDq3aR90aM/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/19/404-Fehlerbehandlung-in-BlogEngineNET-20.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=6a9ea052-2934-427d-a5eb-4397a26e207c</guid>
      <pubDate>Sun, 19 Jun 2011 15:59:36 +0200</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=6a9ea052-2934-427d-a5eb-4397a26e207c</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=6a9ea052-2934-427d-a5eb-4397a26e207c</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/19/404-Fehlerbehandlung-in-BlogEngineNET-20.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=6a9ea052-2934-427d-a5eb-4397a26e207c</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=6a9ea052-2934-427d-a5eb-4397a26e207c</feedburner:origLink></item>
    <item>
      <title>Wie kann ich meine BlogEngine.NET Erweiterungen lokalisieren?</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="BlogEngine.NET" alt="BlogEngine.NET" src="http://blog.klaus-b.net/image.axd?picture=logo.png" /&gt;&lt;/p&gt;  &lt;p&gt;Die unter &lt;a title="Blogengine.NET. An innovative open source blogging platform developed with ASP.NET 2.0" href="http://www.dotnetblogengine.net/" rel="nofollow"&gt;BlogEngine.NET&lt;/a&gt; verwendeten &lt;a title="BlogEngine.NET Extensions" href="http://blogengine.codeplex.com/wikipage?title=Extensions&amp;amp;referringTitle=Documentation"&gt;Extensions&lt;/a&gt;, zum Erweitern des Funktionsumfangs, bieten keine der üblichen Möglichkeiten um die Textausgabe dieser Erweiterungen zu lokalisieren. Diese Erweiterungen sind im Normalfall Klassen, die mit dem Extension-Attribut versehen und im &lt;em&gt;App_Code&lt;/em&gt;-Ordner einer BlogEngine Installation im Unterordner &lt;em&gt;Extensions&lt;/em&gt; abgelegt werden. Eine klassenbezogene Lokalisierung ist im .NET Framework nicht vorgesehen.     &lt;br /&gt;BlogEngine bietet lediglich die Methode &lt;em&gt;Translate&lt;/em&gt; der &lt;em&gt;Utils&lt;/em&gt;-Klasse um Zeichenfolgen mit Hilfe der globalen Ressourcen zu übersetzen. Um diese Option zu nutzen, müssen alle zu verwendenden Zeichenfolgen in den globalen Ressourcen der Webanwendung vorhanden sein.     &lt;br /&gt;Also auch kein gangbarer Weg, da der Aufwand bei Aktualisierungen der globalen Ressourcen einfach zu groß währe.&lt;/p&gt;  &lt;p&gt;Ich entschied mich für die Verwendung von statischen Klassen als &lt;a title="Geschachtelte Typen (C#-Programmierhandbuch)" href="http://msdn.microsoft.com/library/ms173120.aspx" rel="msdn nofollow"&gt;geschachtelte Typen&lt;/a&gt; innerhalb meiner Erweiterungen. Eine anwendungsweite Lösung erschient mir nicht praktikabel, da gerade Erweiterungen oft einzeln verteilt und verwendet werden. Wenn jetzt noch jedes mal eine zusätzliche Assembly mit verteilt werden soll, kann die einfache Handhabung der Erweiterungen schnell unübersichtlich und unnötig kompliziert werden.&lt;/p&gt;  &lt;p&gt;In meinem Ansatz mache ich mir die Tatsache zu nutze, dass in den Einstellungen des Blog jederzeit die verwendete Spracheinstellung abrufbar ist. Von der ausgegebene Einstellung, z.B.: de-DE, verwende ich lediglich das Sprachschema. Auf die regionalen Unterschiede zwischen de-DE und de-AT habe ich bewusst verzichtet, da ich nur Zeichenfolgen darstellen will.    &lt;br /&gt;So kann in einem &lt;em&gt;switch/case&lt;/em&gt;-Block, entsprechend der eingestellten Sprache, die jeweils zugehörige Zeichenfolge ermittelt werden.     &lt;br /&gt;Da die geschachtelte Klasse als statisch deklariert ist, können die enthaltenen Eigenschaften, wie von der Resource-Klasse gewohnt, einfach direkt verwendet werden.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:685666bd-131f-403c-9dff-bfe2027e8094" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;/// &amp;lt;summary&amp;gt;
/// Konvertiert die Style-Attribute von Html-Images in
/// eine entsprechende CSS-Klasse.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
[Extension(
    "Converts the style attributes of Html-Images to the corresponding CSS class.",
    "1.5.0.0",
    "&amp;lt;a href=\"http://blog.klaus-b.net/\"&amp;gt;klaus_b&amp;lt;/a&amp;gt;")]
public class ConvertStyleToCss
{
    // Hier andere Member der Klasse
    #region Methods
    private static void InitialiceSettings()
    {
        var settings = new ExtensionSettings("ConvertStyleToCss") { IsScalar = true };
        settings.AddParameter(
            "leftImg",
            LocalResources.LeftImg,
            50,
            true,
            false,
            ParameterType.String);
        settings.AddValue("leftImg", "leftImg");
        settings.AddParameter(
            "rightImg",
            LocalResources.RightImg,
            50,
            true,
            false,
            ParameterType.String);
        settings.AddValue("rightImg", "rightImg");
        settings.AddParameter(
            "centerImg",
            LocalResources.CenterImg,
            50,
            true,
            false,
            ParameterType.String);
        settings.AddValue("centerImg", "centerImg");
        settings.AddParameter(
            "cleanWlwDivs",
            LocalResources.CleanWlwDivs,
            4,
            false,
            false,
            ParameterType.Boolean);
        settings.AddValue("cleanWlwDivs", false);
        // TODO: Hilfe erzeugen und einfügen
        ConvertStyleToCss.setting = ExtensionManager.InitSettings(
            "ConvertStyleToCss",
            settings);
    }
    #endregion Methods
    #region Nested Types
    /// &amp;lt;summary&amp;gt;
    /// Stellt lokalisierte Zeichenfolgen als Ressourcen bereit.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;remarks&amp;gt;Wird nur von der übergeordneten Klasse verwendet.&amp;lt;/remarks&amp;gt;
    private static class LocalResources
    {
        #region Fields
        /// &amp;lt;summary&amp;gt;
        /// Hält die eingestellte Kultur des Blogs.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
        private static readonly string blogCulture = BlogSettings.Instance.Culture;
        /// &amp;lt;summary&amp;gt;
        /// Hält die zu verwendende Sprache des Blogs.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
        private static readonly string culture = blogCulture.Substring(0, 2);
        /// &amp;lt;summary&amp;gt;
        /// Hält den zu verwendenden Hilfetext.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;remarks&amp;gt;n/a&amp;lt;/remarks&amp;gt;
        private static string helpText;
        #endregion Fields
        #region Properties
        internal static string CenterImg
        {
            get
            {
                switch (culture)
                {
                    case "de":
                        return "Die CSS-Klasse für zentrierte Bilder:";
                    default:
                        return "CSS class for centered images:";
                }
            }
        }
        internal static string CleanWlwDivs
        {
            get
            {
                switch (culture)
                {
                    case "de":
                        return "WLW DIVs bereinigen:";
                    default:
                        return "Clean WLW DIVS:";
                }
            }
        }
        internal static string HelpText
        {
            get
            {
                if (string.IsNullOrEmpty(helpText))
                {
                    switch (culture)
                    {
                        case "de":
                            helpText = CreateGermanHelpText();
                            break;
                        default:
                            helpText = CreateEnglishHelpText();
                            break;
                    }
                }
                return helpText;
            }
        }
        internal static string LeftImg
        {
            get
            {
                switch (culture)
                {
                    case "de":
                        return "Die CSS-Klasse für links ausgerichtete Bilder:";
                    default:
                        return "CSS class for left aligned images:";
                }
            }
        }
        internal static string RightImg
        {
            get
            {
                switch (culture)
                {
                    case "de":
                        return "Die CSS-Klasse für rechts ausgerichtete Bilder:";
                    default:
                        return "CSS class for right aligned images:";
                }
            }
        }
        #endregion Properties
        #region Methods
        private static string CreateEnglishHelpText()
        {
            var sb = new StringBuilder();
            // TODO: create english help text
            return sb.ToString();
        }
        private static string CreateGermanHelpText()
        {
            var sb = new StringBuilder();
            // TODO: deutschen Hilfetext erzeugen
            return sb.ToString();
        }
        #endregion Methods
    }
    #endregion Nested Types
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Im Moment habe ich die &lt;em&gt;switch/case&lt;/em&gt;-Blöcke so gestaltet, dass bei allen anderen Sprachen außer Deutsch, ein englischer Text ausgegeben wird. Da ich die Konfigurationsoberfläche meiner Erweiterungen gerne in der Sprache meines Blog darstelle, denke ich eine gangbare Lösung für Anwender meiner Erweiterungen gefunden zu haben, die andere Sprachen bevorzugen.&lt;/p&gt;

&lt;h4&gt;Fazit:&lt;/h4&gt;

&lt;p&gt;Die Lokalisierung von Oberflächen, Meldungen und anderen Textausgaben sollte eigentlich schon lange den Kinderschuhen entwachsen sein. Leider muss ich immer wieder feststellen, dass dem nicht so ist. Entweder liegt dieser Umstand an den jeweiligen Entwicklern die es nicht für nötig erachten ihre Anwendungen zu lokalisieren, oder aber die entsprechenden Technologien erscheinen zu kompliziert um in jeder Anwendung einfach verwendet werden zu können.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:380e97eb-bfc1-4350-b69d-f7ad3827771f" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" title="blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" title="asp.net" rel="tag"&gt;asp.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" title="c#" rel="tag"&gt;c#&lt;/a&gt; | &lt;a href="http://technorati.com/tags/localization" title="localization" rel="tag"&gt;localization&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=wFaHoT5NuuU:dHFwJctxtvI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=wFaHoT5NuuU:dHFwJctxtvI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=wFaHoT5NuuU:dHFwJctxtvI:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/wFaHoT5NuuU" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/wFaHoT5NuuU/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/15/Wie-kann-ich-meine-BlogEngineNET-Erweiterungen-lokalisieren.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=6d9840a0-c50c-4883-9561-f25c83f64e7d</guid>
      <pubDate>Wed, 15 Jun 2011 17:09:11 +0200</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=6d9840a0-c50c-4883-9561-f25c83f64e7d</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=6d9840a0-c50c-4883-9561-f25c83f64e7d</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/15/Wie-kann-ich-meine-BlogEngineNET-Erweiterungen-lokalisieren.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=6d9840a0-c50c-4883-9561-f25c83f64e7d</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=6d9840a0-c50c-4883-9561-f25c83f64e7d</feedburner:origLink></item>
    <item>
      <title>Erste deutschsprachige BlogEngine.NET Community</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="Deutsche BlogEngine.NET Community" alt="Deutsche BlogEngine.NET Community"  src="http://blog.klaus-b.net/image.axd?picture=blogengine-logo-de.png" /&gt;&lt;/p&gt;  &lt;p&gt;Am 07 Juni 2011 ging das erste &lt;a title="Deutschsprachiges BlogEgnine.NET Community Portal" href="http://www.dotnetblogengine.de/"&gt;deutschsprachige BlogEngine.NET Community Portal&lt;/a&gt; online.     &lt;br /&gt;Betreiber und Verantwortlicher der Webseite ist &lt;a title="Hans-Peter Schelian&amp;#39;s Weblog" href="http://blog.schelian.de/" rel="friend colleague"&gt;Hans-Peter Schelian&lt;/a&gt;. Als Moderatoren stehen ihm Roland Schumacher aka &lt;a title="GENiALi&amp;#39;s Blog - Inklusive Rechtschreibfehler" href="http://blog.geniali.ch/" rel="friend colleague"&gt;GENiALi&lt;/a&gt; und meine Wenigkeit zur Seite.&lt;/p&gt;  &lt;p&gt;Die Idee, oder besser der Entschluss das Portal zu eröffnen, entstand in einem Twitter-Gespräch zwischen Hans-Peter und mir, das in etwa so ablief:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;SchelianHP&lt;/em&gt;: Kennst du eine #BlogEngine Community außer der auf #CodePlex?     &lt;br /&gt;&lt;em&gt;klaus_b0&lt;/em&gt;: Nein, aber wenn du eine findest gib mir bitte Bescheid     &lt;br /&gt;&lt;em&gt;SchelianHP&lt;/em&gt;: Da gibt es wirklich nichts     &lt;br /&gt;&lt;em&gt;klaus_b0&lt;/em&gt;: Hättest du Interesse eine eigene Seite aufzuziehen?     &lt;br /&gt;&lt;em&gt;SchelianHP&lt;/em&gt;: Wäre eine Option, habe schon mal ein anderes Forum hochgezogen…     &lt;br /&gt;&lt;em&gt;klaus_b0&lt;/em&gt;: Ich helfe dir gerne moderieren, administrieren udgl.     &lt;br /&gt;&lt;em&gt;SchelianHP:&lt;/em&gt; Das habe ich gehofft. Oder soll ich sagen, das hoffe ich doch. Das kriegen wir…     &lt;br /&gt;&lt;em&gt;klaus-b0&lt;/em&gt;: Wenn das Forum konkret wird, Plattform, Bereiche udgl., schick mir einfach ne DM.&lt;/p&gt;  &lt;p&gt;Es folgten noch ein paar Mails hin und her. Darin beschlossen wir auch GENiALi zu fragen, ob er Interesse hätte mit an Board zu kommen. Roland erschien mir eine gute Wahl, da er einer der wenigen deutschsprachigen Entwickler ist die sich mit &lt;a title="Blogengine.NET. An innovative open source blogging platform developed with ASP.NET 2.0" href="http://www.dotnetblogengine.net/" rel="nofollow"&gt;BlogEngine.NET&lt;/a&gt; befassen und er auch schon die ein oder andere Anpassung an der Codebasis vorgenommen hat. Roland sagte zu und so stand das Basisteam fest.     &lt;br /&gt;Hans-Peter registrierte die Domäne &lt;strong&gt;dotnetblogengine.de&lt;/strong&gt;, in Anlehnung an den Original Domänennamen von &lt;a title="Gründer von BlogEngine.NET" href="http://www.dotnetblogengine.net/" rel="colleague"&gt;Mads Kristensen&lt;/a&gt; dem Gründer des Open Source Projekts, und stellte den Webserver zur Verfügung. Als Plattform für die Community-Seite wurde &lt;a title="DotNetNuke CMS für ASP.NET" href="http://www.dotnetnuke.com/" rel="nofollow"&gt;DotNetNuke&lt;/a&gt; gewählt, da Hans-Peter aus dieser Richtung kommt und einiges an Erfahrung mit der Plattform mitbringt. Mir war es egal welche Plattform verwendet wird. Hauptsache .NET basierend und für Anpassungen Zugang zum &lt;a title="Quelltext" href="http://de.wikipedia.org/wiki/Quellcode" rel="wiki nofollow"&gt;Quellcode&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Den Mittelpunkt des Portals wird ziemlich sicher das enthaltene Forum darstellen. In diesem Forum sollen die gängigsten Themen rund um BlogEngine.NET behandelt werden. Dabei ist der Schwerpunkt nicht auf Entwickler gerichtet, sondern auf den Endanwender. Egal ob Probleme bei der Installation auftreten, Themes, Widgets oder Erweiterungen angepasst werden sollen.    &lt;br /&gt;Entwickler die sich schon jetzt oder erst zukünftig mit BlogEngine.NET befassen wollen, sind natürlich herzlich Willkommen.&lt;/p&gt;  &lt;p&gt;Eine FAQ befindet sich gerade in Arbeit. In ihr werden die häufigsten Fragen zur BlogEngine zusammengetragen und beantwortet. Wenn ihr schon jetzt Fragen zur BlogEngine habt die euch unter den Nägeln brennen, scheut euch nicht sie im Forum zu stellen. Wenn ihr noch kein Mitgliederkonte eingerichtet habt, hier geht’s &lt;a title="Regisriere dich beim deutschsprachigen BlogEngine.NET Community Portal" href="http://www.dotnetblogengine.de/register.aspx"&gt;direkt zur Registrierung&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Als dringlichstes Ziel haben wir uns gesetzt, BlogEngine.NET als Blog-System bekannter und attraktiver zu machen. Mit Eröffnung der &lt;a title="BlogEngine.NET Gallery - Temes, Widgets und Erweiterungen für BlogEngine.NET" href="http://dnbegallery.org/cms"&gt;BlogEngine.NET Gallery&lt;/a&gt; ist von Seiten der BlogEngine Entwickler ein Schritt in die richtige Richtung getan. Die Gallery füllt sich stetig mit neuen Inhalten. Die einfache Installation der Themen, Widgets und Erweiterungen direkt in der Verwaltung eines Blog sollte uns in unserem Vorhaben unterstützen.&lt;/p&gt;  &lt;p&gt;Ein weiterer wichtiger Punkt den wir in Angriff nehmen, ist die Unterstützung bei der Portierung von bestehenden Blogs aus anderen System. Hier sehen wir noch dringenden Handlungsbedarf.    &lt;br /&gt;Das bloße Übertragen der bestehenden Artikel und Kommentare via &lt;a title="BlogML.NET" href="http://blogml.codeplex.com/" rel="nofollow"&gt;BlogML&lt;/a&gt; ist noch keine erfolgreiche Portierung. Bestehende Verknüpfungen dürfen nicht verloren gehen, sondern müssen auf die neue Linkstruktur weitergeleitet werden. Hier ist noch viel Arbeit nötig.&lt;/p&gt;  &lt;p&gt;Oft wird die schlechte Lokalisierung von BlogEngine Installationen mit Recht angeprangert. Auch hier soll Abhilfe geschaffen werden.    &lt;br /&gt;In Sachen &lt;a title="Search Engine Optimization (SEO)" href="http://de.wikipedia.org/wiki/Suchmaschinenoptimierung" rel="wiki nofollow"&gt;SEO&lt;/a&gt; ist die Engine nicht das was sie leisten könnte, obwohl mit kleinen Änderungen schon viel erreicht werden kann.     &lt;br /&gt;Die Leistung von BlogEngine basierenden Blogs lässt auch oft zu wünschen übrig. Auch hier kann geholfen werden.&lt;/p&gt;  &lt;p&gt;Wir sind uns noch nicht einig ob wir eine, für den deutschen Sprachraum, überarbeitete und dahingehend angepasste Version zur Verfügung stellen sollen. Die fortlaufenden Änderungen der originalen Version würden natürlich eingepflegt.    &lt;br /&gt;Bevor wir uns jedoch einen Haufen Arbeit auf die Schultern laden, könntet ihr uns einfach mitteilen ob überhaupt Interesse eurerseits besteht. Wenn ja, was stellt ihr euch vor?     &lt;br /&gt;Besucht uns auf unserem Portal und teilt uns eure Meinung mit.&lt;/p&gt;  &lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:95ef6167-95a4-4799-964e-19c22fc8b409" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/community" title="community" rel="tag"&gt;community&lt;/a&gt; | &lt;a href="http://technorati.com/tags/blogengine.net" title="blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=J4i6zGbruwI:luvRxtB4DDw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=J4i6zGbruwI:luvRxtB4DDw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=J4i6zGbruwI:luvRxtB4DDw:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/J4i6zGbruwI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/J4i6zGbruwI/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/14/Erste-deutschsprachige-BlogEngineNET-Community.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=7b903676-d1f4-4e06-8bb4-c154597b42a1</guid>
      <pubDate>Tue, 14 Jun 2011 10:37:22 +0200</pubDate>
      <category>Community</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=7b903676-d1f4-4e06-8bb4-c154597b42a1</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=7b903676-d1f4-4e06-8bb4-c154597b42a1</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/14/Erste-deutschsprachige-BlogEngineNET-Community.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=7b903676-d1f4-4e06-8bb4-c154597b42a1</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=7b903676-d1f4-4e06-8bb4-c154597b42a1</feedburner:origLink></item>
    <item>
      <title>Double Content durch Posts mit und ohne Datum</title>
      <description>&lt;p&gt;&lt;img  class="leftImg" title="BlogEngine.NET" alt="BlogEngine.NET"  src="http://blog.klaus-b.net/image.axd?picture=logo.png" /&gt;&lt;/p&gt;  &lt;p&gt;In letzter Zeit sind mit in den &lt;a title="Google Suchmaschiene" href="http://google.com/" rel="nofollow"&gt;Google&lt;/a&gt;&amp;#160;&lt;a title="Google Webmaster-Tools" href="http://www.google.com/webmasters/tools/home?hl=de" rel="nofollow"&gt;Webmaster-Tools&lt;/a&gt; vermehrt Warnungen zu doppelten Titeln und doppelter Beschreibung aufgefallen. Die Ursache ist im Verhalten von &lt;a title="Blogengine.NET. An innovative open source blogging platform developed with ASP.NET 2.0" href="http://www.dotnetblogengine.net/" rel="nofollow"&gt;BlogEngine.NET&lt;/a&gt; begründet, dass die URL zu einem Artikel sowohl mit angegebenem Datum als auch ohne dieses akzeptiert wird. Demzufolge wird für beide &lt;a title="Uniform Resource Locator" href="http://de.wikipedia.org/wiki/Uniform_Resource_Locator" rel="wiki nofollow"&gt;URLs&lt;/a&gt;, sowohl mit als auch ohne Datum, der selbe Inhalte zurückgegeben.&lt;/p&gt;  &lt;p&gt;Um BlogEngine.NET dieses Verhalten auszutreiben, ist nur ein kleiner Eingriff in die Methode &lt;em&gt;RewritePost&lt;/em&gt; der Klasse &lt;em&gt;UrlRewrite&lt;/em&gt; im Namensraum &lt;em&gt;BlogEngine.Core.Web.HttpModules&lt;/em&gt; nötig.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:8f14689d-a3cb-46fd-9356-74e522de0d6a" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:firstline[302]"&gt;if (post == null)
{
    return;
}
// HACK: um double content mit URLs ohne Datum zu vermeiden.
if (!haveDate &amp;amp;&amp;amp; !url.Contains("/FEED/"))
{
    context.Response.RedirectPermanent(
		post.AbsoluteLink.ToString(),
		true);
    return;
}
context.RewritePath(
    url.Contains("/FEED/")
        ? string.Format(
			"syndication.axd?post={0}{1}",
			post.Id,
			GetQueryString(context))
        : string.Format(
			"{0}post.aspx?id={1}{2}",
			Utils.ApplicationRelativeWebRoot,
			post.Id,
			GetQueryString(context)),
    false);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nach der Überprüfung, ob ein passender Artikel gefunden wurde, wird mit der Variablen &lt;em&gt;haveDate&lt;/em&gt; überprüft ob kein Datum im URL vorhanden ist und auch kein Feed angefordert wurde. Sind beide Bedingungen erfüllt, wird mittels 301 auf den URL mit Datum umgeleitet. Das Vorkommen von double Content, zwecks URL mit und ohne Datum, sollte sich mit dieser Maßnahme erledigt haben.&lt;/p&gt;

&lt;h4&gt;Fazit:&lt;/h4&gt;

&lt;p&gt;Kleine Maßnahme, große Wirkung. 
  &lt;br /&gt;Traurig nur, dass man überhaupt erst zu solchen Maßnahmen greifen muss. Die Entwickler von BlogEngine.NET scheinen noch immer nicht verstehen, dass zu einem Blog-System mehr gehört als nur Artikel und Kommentare zu verarbeiten. &lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ac88db4a-bae0-40e4-b88f-ad16f577536d" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" title="blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/double+content" title="double content" rel="tag"&gt;double content&lt;/a&gt; | &lt;a href="http://technorati.com/tags/SEO" title="SEO" rel="tag"&gt;SEO&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xGFoASJ7vSI:pVLT_T3zlTM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xGFoASJ7vSI:pVLT_T3zlTM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=xGFoASJ7vSI:pVLT_T3zlTM:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/xGFoASJ7vSI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/xGFoASJ7vSI/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/12/Double-Content-durch-Posts-mit-und-ohne-Datum.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=6032f5df-60fa-49f3-823f-5c4592989777</guid>
      <pubDate>Sun, 12 Jun 2011 18:05:38 +0200</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=6032f5df-60fa-49f3-823f-5c4592989777</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=6032f5df-60fa-49f3-823f-5c4592989777</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/12/Double-Content-durch-Posts-mit-und-ohne-Datum.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=6032f5df-60fa-49f3-823f-5c4592989777</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=6032f5df-60fa-49f3-823f-5c4592989777</feedburner:origLink></item>
    <item>
      <title>BlogEngine.NET Update auf Version 2.0.0.66</title>
      <description>&lt;p&gt;&lt;img  class="leftImg" title="Logo" alt="Logo" src="http://blog.klaus-b.net/image.axd?picture=logo.png" /&gt;&lt;/p&gt;  &lt;p&gt;Mit &lt;a title="Blogengine.NET. An innovative open source blogging platform developed with ASP.NET 2.0" href="http://www.dotnetblogengine.net/" rel="nofollow"&gt;BlogEngine.NET&lt;/a&gt; ab Version 2.0.0.62 ist die volle Unterstützung für Themes enthalten, die den &lt;a title="Razor-Syntax" href="http://msdn.microsoft.com/de-de/library/gg606533.aspx" rel="msdn nofollow"&gt;Razor&lt;/a&gt;-Syntax verwenden wollen. Das bedeutet spätestens ab jetzt ist &lt;a title="ASP.NET" href="http://msdn.microsoft.com/bb400852.aspx" rel="msdn nofollow"&gt;ASP.NET&lt;/a&gt; in der Version 4 angesagt, wie auch die Änderungen an den unterschiedlichen &lt;em&gt;web.config&lt;/em&gt; Dateien unschwer erraten lassen. Neu ist auch die Unterstützung für das IIS Rewrite Modul. Die verwendete &lt;a title="jQuery. write less, do more." href="http://jquery.com/" rel="nofollow"&gt;jQuery&lt;/a&gt;-Version wurde auf Version 1.5.2 aktualisiert. Neu hinzugekommen ist die Unterstützung mehrere Blogs unter einer Installation. Ebenfalls neu ist die Möglichkeit, die Angabe von Webseiten in den Kommentaren zu verbieten.&lt;/p&gt;  &lt;p&gt;Bevor man aber die vielen neuen Feature nutzen kann, ist erst einmal ein Datenbankupdate fällig. Das &lt;a title="SQL (Structured Query Language)" href="http://de.wikipedia.org/wiki/SQL" rel="wiki nofollow"&gt;SQL&lt;/a&gt;-Script für dieses Datenbankupdate trägt bereits die Bezeichnung &lt;strong&gt;From2.0To2.5&lt;/strong&gt;. Mit diesem Update werden folgende Änderungen vorgenommen:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Diverse Fremdschlüssel entfernt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_Users&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_UserRoles&lt;/em&gt; eine neue Spalte &lt;em&gt;Role&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_StopWords&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_Settings&lt;/em&gt; die neuen Spalten &lt;em&gt;SettingRowId&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_Roles&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_Rights&lt;/em&gt; die neuen Spalten &lt;em&gt;RightRowId&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In die Tabelle &lt;em&gt;be_RightRoles&lt;/em&gt; die neuen Spalten &lt;em&gt;RightRoleRowId&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_Referrers&lt;/em&gt; die neuen Spalten &lt;em&gt;ReferrerRowId&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_Profiles&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_Posts&lt;/em&gt; die neuen Spalten &lt;em&gt;PostRowID&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_PostTag&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_PostNotify&lt;/em&gt; eine neue Spalte&lt;em&gt; BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_PostComment&lt;/em&gt; die neuen Spalten&lt;em&gt; PostCommentRowID&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_PingService&lt;/em&gt; eine neue Spalte &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_Pages&lt;/em&gt; die neuen Spalten &lt;em&gt;PageRowID&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_DataStoreSettings&lt;/em&gt; die neuen Spalten &lt;em&gt;DataStoreSettingRowId&lt;/em&gt; und &lt;em&gt;BlogId&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;In der Tabelle &lt;em&gt;be_Categories&lt;/em&gt; die neuen Spalten &lt;em&gt;CategoryRowID&lt;/em&gt; und &lt;em&gt;BlogID&lt;/em&gt; eingefügt. &lt;/li&gt;    &lt;li&gt;Eine neue Tabelle &lt;em&gt;be_Blogs&lt;/em&gt; erstellt. &lt;/li&gt;    &lt;li&gt;Diverse neue Indizes erstellt. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Wer sich unter BlogEngine.NET mit einem eigenem Razor-Theme versuchen möchte, findet im Ordner &lt;em&gt;themes&lt;/em&gt; mit &lt;em&gt;Garland-Revisited&lt;/em&gt; bereits eine nette Vorlage. Wer bereits mit einem eigenem Theme arbeitet, kann davon einen Screenshot anfertigen und diesen im PNG-Format in das Verzeichnis des jeweiligen Themas unter dem Namen &lt;em&gt;theme.png&lt;/em&gt; mit einer Breite von 480 Pixel ablegen. In der Blogverwaltung wird dieser Screenshot als Vorschau in der Themenauswahl angezeigt, Das ist kein Muss, aber ein nettes Gimmick.&lt;/p&gt;  &lt;p&gt;&lt;img class="centerImg"  title="Themes Einstellungen" alt="Themes Einstellungen" src="http://blog.klaus-b.net/image.axd?picture=themesSettings.png" width="520" height="313" /&gt;&lt;/p&gt;  &lt;p&gt;Die Suche nach verfügbaren Themen für BlogEngine.NET wurde durch eine eigene Gallery stark vereinfacht. In den Einstellungen zu den Themen einfach auf den Link &lt;em&gt;Gallery&lt;/em&gt; klicken und eine Auswahl an verfügbaren Themen wird direkt in der Einstellungsseite angezeigt. Sollte ein Thema gefallen, einfach auf &lt;em&gt;Install&lt;/em&gt; klicken und Dank der Verwendung von &lt;a title="NuGet Package Management" href="http://nuget.codeplex.com/" rel="nofollow"&gt;NuGet&lt;/a&gt; wird das gewählte Thema auf dem Server installiert.&lt;/p&gt;  &lt;p&gt;Ähnlich einfach wurde die Installation verfügbarer Erweiterungen und Widgets.    &lt;br /&gt;Im Dashboard prangt einem jetzt sofort eine Auswahl verfügbarer Erweiterungen und Widgets entgegen.&lt;/p&gt;  &lt;p&gt;&lt;img class="centerImg"  title="Widgets und Erweiterungen" alt="Widgets und Erweiterungen" src="http://blog.klaus-b.net/image.axd?picture=widgetGalery.png" width="346" height="374" /&gt;&lt;/p&gt;  &lt;p&gt;Hinter dem Dienst, sowohl für die Themen als auch für die Widgets und Erweiterungen, steht die &lt;a title="BlogEgnine.NET Gallery" href="http://dnbegallery.org/cms" rel="BlogEgnine.NET Gallery"&gt;blogenginge.net gallery&lt;/a&gt;. Wer seine Erweiterungen, Widgets oder Themen zur Verfügung stellen will, kann sie in der Gallery veröffentlichen.&lt;/p&gt;  &lt;p&gt;Wer seinen Besuchern wie bisher erlauben will, ihre Webseiten in den Kommentaren anzugeben, sollte nicht vergessen unter &lt;em&gt;Einstellungen/Kommentare&lt;/em&gt; den Hacken bei     &lt;br /&gt;&lt;em&gt;Enable Website in Comments&lt;/em&gt;     &lt;br /&gt;zu setzen.&lt;/p&gt;  &lt;p&gt;&lt;img class="centerImg"  title="Erlaube Webseiten in Kommentaren" border="0" alt="Erlaube Webseiten in Kommentaren" src="http://blog.klaus-b.net/image.axd?picture=allowWebsites.png" width="524" height="256" /&gt;&lt;/p&gt;  &lt;p&gt;Diese Einstellung ist standardmäßig deaktiviert. Die bisher eingetragenen Verknüpfungen zu Webseiten bleiben von dieser Einstellung unberührt, aber bei allen neuen Kommentaren wird die Verknüpfung zur Webseite nicht gespeichert, wenn diese Option nicht gesetzt wird.&lt;/p&gt;  &lt;p&gt;Trotz der vielen Neuerungen sind viele, schon ältere, Fehler nicht gefixt. So funktioniert z.B.: die Übersichtsliste im Archiv noch immer nicht. Hier müsste nur der Anker korrekt gesetzt werden.&lt;/p&gt;  &lt;p&gt;Auch neue Fehler sind hinzugekommen.    &lt;br /&gt;Wer ein Fehler-Logging aktiv hat, dem wird folgende Fehlermeldung auffallen:&lt;/p&gt;  &lt;blockquote&gt;Error loading compiled extensions from assembly BlogEngine.Core, Version=2.0.0.66, Culture=neutral, PublicKeyToken=fed3cbd6fd4e62d0: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.&lt;/blockquote&gt;  &lt;p&gt;Diese Fehlermeldung ist etwas irreführen, denn sie bezieht sich nur im weiteren Sinn auf einen Fehler beim Laden der Erweiterungen. Vielmehr wird hier ein Problem mit der Zugriffssicherheit abgeleiteter Typen bemängelt, welches erst bei Verwendung der Assembly &lt;em&gt;Blogengine.Core&lt;/em&gt; unter der .NET Version 4 auftritt. Im einzelnen sind alle Klassen im Namensraum &lt;em&gt;BlogEngine.Core.Compilation.Design&lt;/em&gt; betroffen. Hier schafft das setzten des Attribut &lt;a title="SecurityRulesAttribute Klasse" href="http://msdn.microsoft.com/dd269630.aspx" rel="msdn nofollow"&gt;SecurityRules&lt;/a&gt; mit dem Wert &lt;em&gt;Level1&lt;/em&gt; der &lt;a title="SecurityRuleSet Enumeration" href="http://msdn.microsoft.com/dd288473.aspx" rel="msdn nofollow"&gt;SecurityRuleSet&lt;/a&gt;-Enumeration auf die Assembly Abhilfe. Dazu einfach in der &lt;em&gt;AssemblyInfo.cs&lt;/em&gt; folgende Zeile einfügen:&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fad2a5d3-0743-42bf-8e49-99cae377a719" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#:nogutter"&gt;[assembly: SecurityRules(SecurityRuleSet.Level1)]&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Von da an, werden die Sicherheitsregeln wieder wie unter .NET Version 2 auf die Assembly angewendet.&lt;/p&gt;

&lt;p&gt;Ein weiterer, aus meiner Sicht, Fehler ist der etwas gedankenlose Umgang mit einem ungeprüften Ergebnis einer &lt;a title="String.IndexOf Methode" href="http://msdn.microsoft.com/719kb161.aspx" rel="msdn nofollow"&gt;String.IndexOf&lt;/a&gt; Abfrage in der Methode &lt;em&gt;RewriteDefault&lt;/em&gt; der Klasse &lt;em&gt;UrlRewrite&lt;/em&gt;. Da wird im &lt;em&gt;else&lt;/em&gt;-Block ungeprüft das Ergebnis an eine &lt;a title="String.Substring Methode" href="http://msdn.microsoft.com/swz0961t.aspx" rel="msdn nofollow"&gt;String.SubString&lt;/a&gt; Methode übergeben. Wenn hier die überprüfte Zeichenfolge &lt;em&gt;default.aspx&lt;/em&gt; nicht gefunden wird, wird der Wert –1 an die String.SubString Methode übergeben, was in einer &lt;a title="IndexOutOfRangeException Klasse" href="http://msdn.microsoft.com/77c5xay2.aspx" rel="msdn nofollow"&gt;IndexOutOfRangeException&lt;/a&gt; endet. Hier hilft als Hack, bis zum Fix, ein &lt;a title="Ternär-Operator" href="http://msdn.microsoft.com/ty67wk28.aspx" rel="msdn nofollow"&gt;Ternär-Operator&lt;/a&gt;:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:19681c9c-d4f1-4fb5-aac3-5895318dffa8" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;else
{
    string newUrl = url.Replace("Default.aspx", "default.aspx");  // fixes a casing oddity on Mono
    // HACK: ternary operator um eine IndexOutOfRangeExcption zu vermeiden
    int defaultStart = url.IndexOf("default.aspx") == -1 ? 0 : url.IndexOf("default.aspx");
    newUrl = Utils.ApplicationRelativeWebRoot + url.Substring(defaultStart);
    context.RewritePath(newUrl);
}&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;FAZIT:&lt;/h4&gt;

&lt;p&gt;Die BlogEngine mausert sich immer mehr zu einer richtigen Blog-Anwendung. 
  &lt;br /&gt;Vielen Anwenderwünschen wird langsam Rechnung getragen, wie etwa die einfachere Installation von Themen, Widgets oder Erweiterung. Ich will hoffen, dass sich durch Eröffnung der blogengine.net gallery auch die Anzahl ansprechender Themen langsam erhöht. Dies war bisher immer einer der Hauptargumente um die BlogEngine.NET nicht zu verwenden.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2a3c3115-2f0a-4d12-81c9-9fbc7170a4e0" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/blogengine.net" title="blogengine.net" rel="tag"&gt;blogengine.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/asp.net" title="asp.net" rel="tag"&gt;asp.net&lt;/a&gt; | &lt;a href="http://technorati.com/tags/c%23" title="c#" rel="tag"&gt;c#&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=9LpDuAlreIY:dxm0j4yPY2s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=9LpDuAlreIY:dxm0j4yPY2s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=9LpDuAlreIY:dxm0j4yPY2s:1DmhQM8_AdY"&gt;&lt;img src="http://feeds.feedburner.com/~ff/klaus_b?d=1DmhQM8_AdY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/klaus_b/~4/9LpDuAlreIY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/9LpDuAlreIY/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/09/BlogEngineNET-Update-auf-Version-20066.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=b47dd2b2-c0e6-48eb-946d-a2e4b3dcdf42</guid>
      <pubDate>Thu, 09 Jun 2011 13:10:17 +0200</pubDate>
      <category>Blogengine.NET</category>
      <dc:publisher>klaus_b</dc:publisher>
      <pingback:server>http://blog.klaus-b.net/pingback.axd</pingback:server>
      <pingback:target>http://blog.klaus-b.net/post.aspx?id=b47dd2b2-c0e6-48eb-946d-a2e4b3dcdf42</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=b47dd2b2-c0e6-48eb-946d-a2e4b3dcdf42</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/09/BlogEngineNET-Update-auf-Version-20066.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=b47dd2b2-c0e6-48eb-946d-a2e4b3dcdf42</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=b47dd2b2-c0e6-48eb-946d-a2e4b3dcdf42</feedburner:origLink></item>
  </channel>
</rss>
