<?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.0.26</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,195.000000</geo:lat>
    <geo:long>12,389.000000</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>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" img="img" /&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:nHLH-fGdRxU: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:nHLH-fGdRxU: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:nHLH-fGdRxU: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 +0100</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>2</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:ErwDZhz2Ego: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:ErwDZhz2Ego: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:ErwDZhz2Ego: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 +0100</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:r1oK-hvVzEE: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:r1oK-hvVzEE: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:r1oK-hvVzEE: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 +0100</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:e-qksr0noRA: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:e-qksr0noRA: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:e-qksr0noRA: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 +0100</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:HrDLKn1nw7A: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:HrDLKn1nw7A: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:HrDLKn1nw7A: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 +0100</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:TJTfatCUO5o: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:TJTfatCUO5o: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:TJTfatCUO5o: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 +0100</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:vT6JRUZUX9k: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:vT6JRUZUX9k: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:vT6JRUZUX9k: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 +0100</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:w-iEbjwBy0o: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:w-iEbjwBy0o: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:w-iEbjwBy0o: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 +0100</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>
    <item>
      <title>Ist Boxing und Unboxing böse?</title>
      <description>&lt;p&gt;&lt;img class="leftImg" title="Evil jack in a box drawing - ©2007-2011 ~mr-biggs (deviantArt)" alt="Evil jack in a box drawing - ©2007-2011 ~mr-biggs (deviantArt)" src="http://blog.klaus-b.net/image.axd?picture=evil_jack_in_a_box.png" width="160" height="207" /&gt;&lt;/p&gt;  &lt;p&gt;In einem aktuellen Projekt machte mich &lt;a title="NDepend -  Analysiere deine .NET Code" href="http://ndepend.com/" rel="nofollow"&gt;NDepend&lt;/a&gt; auf einen übermäßigen Gebrauch von &lt;a title="Boxing und Unboxing (C#-Programmierhandbuch)" href="http://msdn.microsoft.com/de-de/library/yz2be5wk.aspx" rel="msdn nofollow"&gt;Boxing und Unboxing&lt;/a&gt; aufmerksam. Hauptsächlich wurde dabei eine Klasse angemeckert, welche die Einstellungen aus der &lt;em&gt;web.config&lt;/em&gt; für eine Anwendung verfügbar macht, die keinen Zugriff auf die hostende Webanwendung hat. In besagter Klasse wurden diverse Einstellungswerte verschiedenen Typs in einer &lt;a title="Object Klasse" href="http://msdn.microsoft.com/e5kfa45b.aspx" rel="msdn"&gt;Object&lt;/a&gt; Collection gehalten und beim Abruf aus dieser in den entsprechenden Wertetyp gecastet. Also jede Menge Boxing- und Unboxing-Vorgänge. Bei der Recherche zu dem Thema, warum man Boxing und Unboxing denn vermeiden solle, stieß ich immer wieder auf die Aussage: Boxing/Unboxing ist sehr rechenintensiv und kann sich daher negativ auf die Gesamtleistung einer Anwendung auswirken.     &lt;br /&gt;In der &lt;a title="Microsoft Developer Network" href="http://msdn.microsoft.com/" rel="msdn nofollow"&gt;MSDN&lt;/a&gt; heißt es unter anderem im Artikel &lt;a title="Leistung in C# und Visual Basic" href="http://msdn.microsoft.com/de-de/library/ms173196.aspx" rel="msdn nofollow"&gt;Leistung (C# und Visual Basic)&lt;/a&gt; im Absatz über Boxing und Unboxing:&lt;/p&gt;  &lt;blockquote&gt;Wenn ein Wertetyp mittels Boxing konvertiert wird, muss ein völlig neues Objekt erstellt werden.Dies kann bis zu 20-mal länger dauern als eine einfache Zuweisung eines Verweises.&lt;/blockquote&gt;  &lt;p&gt;Das war es Wert näher untersucht zu werden.    &lt;br /&gt;Für den Anfang beschränkte ich meinen Versuch auf die Primitiven. Der Einfachheit halber verwende ich hier &lt;a title="Int32 Struktur" href="http://msdn.microsoft.com/td2s409d.aspx" rel="msdn nofollow"&gt;Int32&lt;/a&gt;-Werte, welche in ein &lt;a title="Array Klasse" href="http://msdn.microsoft.com/czz5hkty.aspx" rel="msdn nofollow"&gt;Array&lt;/a&gt; vom Typ Object geschrieben werden. Anschließend werden die Werte aus diesem Object-Array mit verschiedenen Methoden in ein Array vom Typ Int32 geschrieben und die Ergebnisse verglichen. Das Object-Array wird immer mit 1 Millionen Werten von 0 aufsteigend gefüllt.&lt;/p&gt;  &lt;p&gt;Als erstes habe ich ein einfaches Boxing verwendet um das Object-Array mit Int32-Werten zu füllen. Anschließend werden via Unboxing die Werte aus dem Object-Array in das Int32-Array übertragen.&lt;/p&gt;  &lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6bfc09ac-30f7-4440-ac2f-706a469084a7" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;namespace BoxingUnboxingTest
{
    using System;
    using System.Diagnostics;
    using System.Globalization;

    class Program
    {
        private static object[] container;
        private static int[] result;
        private const int MaxItems = 1000000;

        static void Main(string[] args)
        {
            container = new object[MaxItems];
            result = new int[MaxItems];
            var sw = new Stopwatch();
            sw.Start();

            FillArrayWithInt();
            sw.Stop();
            var timeToFill = sw.ElapsedMilliseconds;
            sw.Start();
            FillResult(false, false);
            sw.Stop();
            var timeToTransfer = sw.ElapsedMilliseconds - timeToFill;
            var totalTime = sw.ElapsedMilliseconds;
        }

        private static void FillArrayWithInt()
        {
            for (int i = 0; i &amp;lt; MaxItems; i++)
            {
                container[i] = i;
            }
        }

        private static void FillResult(bool useParse, bool useConvert)
        {
            if (useParse)
            {
                for (int i = 0; i &amp;lt; MaxItems; i++)
                {
                    result[i] = int.Parse(container[i].ToString(), CultureInfo.InvariantCulture);
                }

                return;
            }

            if (useConvert)
            {
                for (int i = 0; i &amp;lt; MaxItems; i++)
                {
                    result[i] = Convert.ToInt32(container[i], CultureInfo.InvariantCulture);
                }

                return;
            }

            for (int i = 0; i &amp;lt; MaxItems; i++)
            {
                result[i] = (int)container[i];
            }
        }
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Das Ergebnis war erst einmal verblüffend. Ich erwartete, auf Grund der vielen boxing/unboxing Operationen ein katastrophales Ergebnis. Statt dessen wurde mir ein sehr flottes Resultat angezeigt: Für das Füllen des Object-Array, das Boxing, wurden im Schnitt 50 Millisekunden benötigt. Für das Umkopieren der Werte in das Int32-Array mittels Unboxing lediglich 15 Millisekunden im Mittel.&lt;/p&gt;

&lt;p&gt;Da ich ja vom Boxing/Unboxing weg sollte, probierte ich als nächstes eine Version mit der &lt;a title="Convert Klasse" href="http://msdn.microsoft.com/dsfy6sz9.aspx" rel="msdn nofollow"&gt;Convert&lt;/a&gt;-Klasse in der ich das boxing in das Object-Array beibehielt, das unboxing mit einer Überladung der ToInt32-Methode ersetzte. Das Ergebnis war ernüchternd. Anstatt schneller zu werden, ich hatte ja auf das böse unboxing verzichtet, benötigte diese Variante satte 1250 Millisekunden im Mittel.&lt;/p&gt;

&lt;p&gt;Die Verwendung der Methode &lt;a title="Int32.Parse Methode" href="http://msdn.microsoft.com/tz4z025a.aspx" rel="msdn nofollow"&gt;int.Parse&lt;/a&gt; war, mit 1850 Millisekunden im Mittel, die langsamste Variante.&lt;/p&gt;

&lt;p&gt;Als nächstes startete ich den gleichen Versuch mit Werten des Typs &lt;a title="DateTime Struktur" href="http://msdn.microsoft.com/03ybds8y.aspx" rel="msdn nofollow"&gt;DateTime&lt;/a&gt;. Auch hier begann ich mit dem Boxing/Unboxing und füllte das Object-Array wieder mit 1 Millionen Werten. Das Füllen des Array dauerte diesmal rund 1500 Millisekunden im Mittel. Das Umkopieren via Unboxing benötigte etwa 15 Millisekunden. Das Unboxing von DateTime-Werten geht also genauso schnell wie das Unboxing von einfachen Int32-Werten.&lt;/p&gt;

&lt;p&gt;Als nächstes testete ich das Verhalten mit der Convert-Klasse in dem ich die ToDateTime Methode verwendete und dieser die Werte als Typ Object übergab. Auch hier wieder das gleiche Ergebnis wie bei den Int32-Werten: etwa 1250 Millisekunden im Mittel.&lt;/p&gt;

&lt;p&gt;Auch bei DateTime-Objekten benötigte die Parse-Methode &lt;a title="DateTime.Parse Methode" href="http://msdn.microsoft.com/6fw7727c.aspx" rel="msdn nofollow"&gt;DateTime.Parse&lt;/a&gt; mit rund 4000 Millisekunden am längsten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Erstes Zwischenfazit&lt;/strong&gt;: 

  &lt;br /&gt;Für den reinen Transport von öfter wechselnden Werten verschiedenen Typs in einem Container mit einer Auflistung vom Typ Object, ist die Verwendung von Boxing/Unboxing die erste Wahl. 

  &lt;br /&gt;Ich konnte keine Methode finden, welche die Aufgabe schneller und einfacher erledigt.&lt;/p&gt;

&lt;p&gt;Aber damit ist das Thema noch nicht ausgereizt. Boxing/Unboxing wird auch innerhalb des Framework in den verschiedensten Methoden, für den Benutzer oft vollkommen transparent, verwendet. Ein typischer Vertreter dieser Art ist die oft verwendete Methode &lt;a title="String.Format Methode" href="http://msdn.microsoft.com/xh1dzhdx.aspx" rel="msdn nofollow"&gt;String.Format&lt;/a&gt; mit ihren diversen Überladungen. 

  &lt;br /&gt;In folgendem Beispiel werden die beiden Integer Werte in ein Object geboxt und anschließend die Methode &lt;a title="Object.ToString Methode" href="http://msdn.microsoft.com/7bxwbwt2.aspx" rel="msdn nofollow"&gt;Object.ToString&lt;/a&gt; aufgerufen.&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:627bbd68-0928-469c-92cb-91d19e1af591" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;var output = string.Format(
    CultureInfo.InvariantCulture,
    "Dies ist Wert Nr.{0} von {1} Werten insgesamt.",
    5,
    100);&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Um hier das Boxing zu vermeiden könnte anstatt der Integer Werte, die jeweilige Darstellung als Zeichenfolge an die Methode übergeben werden:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6c04b3c2-12d9-4612-a10b-4a57cca7d314" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;var output = string.Format(
    CultureInfo.InvariantCulture,
    "Dies ist Wert Nr.{0} von {1} Werten insgesamt.",
    5.ToString(CultureInfo.InvariantCulture),
    100.ToString(CultureInfo.InvariantCulture));&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Da die Methode int.ToString ein Member der &lt;a title="Int32 Struktur" href="http://msdn.microsoft.com/td2s409d.aspx" rel="msdn nofollow"&gt;int&lt;/a&gt; Struktur ist, wird hier kein Boxing benötigt. Ob dieses Vorgehen einen Vorteil gegenüber der direkten Angabe der Integer Werte darstellt, gilt es zu ermitteln.&lt;/p&gt;

&lt;p&gt;Als erstes habe ich ein Array vom Typ &lt;a title="String Klasse" href="http://msdn.microsoft.com/s1wwdcbf.aspx" rel="msdn nofollow"&gt;string&lt;/a&gt; mit 1 Millionen Werten mit der Methode string.Format gefüllt, in dem ich den jeweiligen Wert zwischen 0 und 999999 als Integer Wert an die Methode übergeben habe. Dieses Verfahren benötigte im Schnitt 3700 Millisekunden.&lt;/p&gt;

&lt;p&gt;Die Angabe der Zeichenfolge mit Hilfe der int.ToString Methode gegenüber der direkten Angabe der Integer Werte brachte auch dieses mal keine Verbesserung der Leistung. Diese Variante benötigte zur Erstellung der 1 Millionen Werte etwa 5000 Millisekunden im Mittel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zweites Zwischenfazit&lt;/strong&gt;: 

  &lt;br /&gt;Für Zahlenwerte jeglicher Art scheint die Verwendung von Boxing/Unboxing die schnellste und effizienteste Art zu sein, die jeweiligen Werte zwischen verschiedenen Objekten zu übertragen oder als formatierte Zeichenfolge darzustellen.&lt;/p&gt;

&lt;p&gt;Als letzten Versuch möchte ich mich einer anderen Art der &lt;a title="Werttypen (C#-Referenz)" href="http://msdn.microsoft.com/de-de/library/s1ax56ch.aspx" rel="msdn nofollow"&gt;Wertetypen&lt;/a&gt; zuwenden, dem &lt;a title="enum (C#-Referenz)" href="http://msdn.microsoft.com/de-de/library/sbbt4032.aspx" rel="msdn nofollow"&gt;enum&lt;/a&gt;. Enumerationen sind oft ein heißes Diskussionsthema: Die einen lieben und die anderen hassen sie. Manche bezeichnen sie gar als böse. Diese Diskussion soll hier außen vor bleiben. Ich betrachte sie für diesen Versuch als das was sie sind: Ein weiterer Wertetyp.&lt;/p&gt;

&lt;p&gt;Für diesen Versuch verwende ich wieder die Methode string.Format um eine formatierte Zeichenfolge darzustellen, in der der Wert einer Enumeration verwendet wird. 
  &lt;br /&gt;Bei der Zeichenfolgendarstellung einer Enumeration mit den Mitteln des Framework, wird immer ein Boxing durchgeführt. Egal ob in der Methode string.Format oder mit der ToString Methode einer Enumeration. Ein Blick in den IL-Code des folgenden Beispiel zeigt dieses Verhalten sehr schön. Zuerst der Code in C#:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:602cd787-8261-40c2-89e4-54a76920e5ef" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;static void Main(string[] args)
{
    var output = TestEnum.Entry8.ToString();
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Und anschließend der erzeugte IL-Code:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:e6621605-6216-4ea0-8647-8c5e8339fb4d" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Code size 14 (0xe)
	.maxstack 1
	.entrypoint
	.locals init (
		[0] string output
	)
	IL_0000: nop
	IL_0001: ldc.i4.8
	IL_0002: box BoxingUnboxingTest.TestEnum
	IL_0007: callvirt instance string [mscorlib]System.Object::ToString()
	IL_000c: stloc.0
	IL_000d: ret
} // end of method Program::Main&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Zeile 15 und 16 ist gut zu sehen, wie zuerst der Wert der Enumeration in ein Object geboxt und anschließend die Methode Object.ToString aufgerufen wird. 
  &lt;br /&gt;Zum füllen eine Array vom Typ String mit 1 Millionen Werte benötigte die Methode string.Format mit dem Boxing im Schnitt etwa 13800 Millisekunden.&lt;/p&gt;

&lt;p&gt;Im das Boxing zu vermeiden, habe ich mich für eine Erweiterungsmethode entschieden, welche in einem switch/case-Block die Zeichenfolgendarstellung des angegebenen Wertes der Enumeration zurückgibt:&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:2b5bb6c0-d5f9-4fc3-8970-df57a8e2a062" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;internal static string GetName(this TestEnum value)
{
    switch (value)
    {
        case TestEnum.Entry1:
            return "Entry1";
        case TestEnum.Entry2:
            return "Entry2";
        case TestEnum.Entry3:
            return "Entry3";
        case TestEnum.Entry4:
            return "Entry4";
        case TestEnum.Entry5:
            return "Entry5";
        case TestEnum.Entry6:
            return "Entry6";
        case TestEnum.Entry7:
            return "Entry7";
        case TestEnum.Entry8:
            return "Entry8";
        case TestEnum.Entry9:
            return "Entry9";
        default:
            return "None";
    }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wenn nun das vorangegangene Beispiel mit dieser Erweiterungsmethode wiederholt wird, sollte das Boxing aus dem IL-Code verschwunden sein.&lt;/p&gt;

&lt;div id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:03e381f3-a95b-4736-bb25-110c5e4e6466" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Code size 9 (0x9)
	.maxstack 1
	.entrypoint
	.locals init (
		[0] string output
	)
	IL_0000: nop
	IL_0001: ldc.i4.8
	IL_0002: call string BoxingUnboxingTest.Extensions::GetName(valuetype BoxingUnboxingTest.TestEnum)
	IL_0007: stloc.0
	IL_0008: ret
} // end of method Program::Main&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Im Gegensatz zum vorherigen IL-Code Beispiel wird in Zeile 15 kein Boxing mehr durchgeführt, sondern statt dessen die Erweiterungsmethode aufgerufen die ja den erwarteten String zurückgibt.&lt;/p&gt;

&lt;p&gt;Ist die Vermeidung des Boxings dieses mal messbar? 
  &lt;br /&gt;Ja, ist es. Die Variante unter Verwendung der Erweiterungsmethode benötigte rund 9270 Millisekunden. Sie ist rund ein Drittel schneller als die Vorherige Variante in der Boxing verwendet wird.&lt;/p&gt;

&lt;h3&gt;Fazit:&lt;/h3&gt;

&lt;p&gt;In den meisten Fällen, zumindest wenn Primitiven oder Zahlenwerte verwendet werden, braucht auf das Boxing und Unboxing keine besondere Rücksicht genommen werden. 
  &lt;br /&gt;Doch bereits bei der Verwendung von Werten aus Enumerationen ändert sich das Bild. Hier sollte im Einzelfall geprüft werden, wie sich der erzielte Nutzen im Verhältnis zum Aufwand verhält. Bei deutlich komplexeren Strukturen sind Tools wie etwa NDepend sehr hilfreich um festzustellen, ob und wo eventuell Boxing oder Unboxing verwendet wird,&lt;/p&gt;

&lt;p&gt;Für mich ist das Boxing und Unboxing nun nicht mehr so böse, wie es oft dargestellt wird. 
  &lt;br /&gt;Natürlich können in verschiedenen Situationen Leitungseinbußen durch das Boxing oder Unboxing entstehen. Aber deshalb dieses überaus hilfreiche Compiler Feature per se als böse zu bezeichnen, schießt doch etwas über das Ziel hinaus.&lt;/p&gt;

&lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e3780792-0eb2-4469-8b13-7f83e309c9fc" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/CLR" title="CLR" rel="tag"&gt;CLR&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/Analysis" title="Analysis" rel="tag"&gt;Analysis&lt;/a&gt; | &lt;a href="http://technorati.com/tags/Sourcecode" title="Sourcecode" rel="tag"&gt;Sourcecode&lt;/a&gt; | &lt;a href="http://technorati.com/tags/boxing" title="boxing" rel="tag"&gt;boxing&lt;/a&gt; | &lt;a href="http://technorati.com/tags/unboxing" title="unboxing" rel="tag"&gt;unboxing&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=HlENwAZql74:z_45jK9YbgM: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=HlENwAZql74:z_45jK9YbgM: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=HlENwAZql74:z_45jK9YbgM: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/HlENwAZql74" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/HlENwAZql74/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/06/04/Ist-Boxing-und-Unboxing-bose.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=bf818318-af56-494d-b16f-ac6f80f5cc2f</guid>
      <pubDate>Sat, 04 Jun 2011 14:38:25 +0100</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=bf818318-af56-494d-b16f-ac6f80f5cc2f</pingback:target>
      <slash:comments>5</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=bf818318-af56-494d-b16f-ac6f80f5cc2f</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/06/04/Ist-Boxing-und-Unboxing-bose.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=bf818318-af56-494d-b16f-ac6f80f5cc2f</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=bf818318-af56-494d-b16f-ac6f80f5cc2f</feedburner:origLink></item>
    <item>
      <title>Mein erster Kontakt mit NDepend</title>
      <description>&lt;p&gt;&lt;img class="leftImg"  title="NDepend" alt="NDepend"  src="http://blog.klaus-b.net/image.axd?picture=ndependLogo.png" width="116" height="35" /&gt;&lt;/p&gt;  &lt;p&gt;Kurz vor Ostern erhielt ich von &lt;a title="http://smacchia.chez-alice.fr/en/Home.html" href="http://smacchia.chez-alice.fr/en/Home.html" rel="colleague"&gt;Patrick Smacchia&lt;/a&gt;, dem verantwortlichen Entwickler hinter &lt;a title=".NET Code Analyse" href="http://ndepend.com/" rel="nofollow"&gt;NDepend&lt;/a&gt;, eine Anfrage, ob ich Interesse hätte mir NDepend einmal anzusehen. Die eingeholten Vorabinformationen aus der deutschen .NET-Gemeinde waren durchweg positiv und erzeugten eine gewisse Neugier. Warum also nicht eine eigene Meinung bilden?&lt;/p&gt;  &lt;p&gt;Ich bekundete mein Interesse beim NDepend-Team und erhielt kurz darauf eine Lizenz. Der Download fällt mit 9,4 MB eher klein aus. Eine echte Installation wird nicht benötigt. Es müssen lediglich die Daten aus dem ZIP-Archiv in ein privates Verzeichnis entpackt werden. Das entpacken der Daten in den Programmeordner sollte wegen möglicher Probleme mit der &lt;a title="Benutzerkontensetuerung unter Windows Vista und Windows 7" href="http://msdn.microsoft.com/de-de/library/bb384608.aspx" rel="msdn nofollow"&gt;Benutzerkontensteuerung&lt;/a&gt; (&lt;a title="User Account Control" href="http://de.wikipedia.org/wiki/User_Account_Control" rel="wiki nofollow"&gt;UAC&lt;/a&gt;) unterbleiben. Nach dem Entpacken muss, für die Integration von NDepend in &lt;a title="Visual Studio" href="http://msdn.microsoft.com/vstudio/" rel="msdn nofollow"&gt;Visual Studio&lt;/a&gt;, einmal die Anwendung &lt;em&gt;NDepend.Install.VisualStudioAddin.exe&lt;/em&gt; ausgeführt werden. In einem Auswahldialog wird nach der verwendeten Visual Studio Version gefragt. Es kann zwischen voller Integration und einer, &lt;em&gt;Light Integration&lt;/em&gt; genannten, teilweisen Integration gewählt werden. Die von NDepend verwendeten Shortcuts können auf Wunsch deaktiviert werden, falls Kollisionen mit bereits verwendeten Tastenkürzeln zu befürchten sind. Ab jetzt steht NDepend zur Codeanalyse in Visual Studio zur Verfügung.&lt;/p&gt;  &lt;p&gt;Um NDepend mit einem Visual Studio Projekt zu verwenden, kann entweder eine neues NDepend-Projekt erzeugt und mit dem aktuellen Visual Studio-Projekt verknüpft, oder das aktuelle Visual Studio-Projekt mit einem bestehenden NDepend-Projekt verknüpft werden.    &lt;br /&gt;Auf der Seite der Einstellungen des NDepend-Projekts, ist der wichtigste Punkt die richtige Auswahl der zu verwendenden Framework-Version.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.klaus-b.net/image.axd?picture=ndependProperties.png"&gt;&lt;img class="centerImg"  title="NDepend Einstellungen" alt="NDepend Einstellungen" src="http://blog.klaus-b.net/image.axd?picture=ndependProperties_thumb.png" width="520" height="375" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Mit dieser Einstellung wir festgelegt, aus welchen Ordnern NDepend die referenzierten Assemblies des Framework lädt. Die weiteren Einstellungen, etwa zur Analyse und zum Aussehen des erzeugten Reports, sind selbsterklärend.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.klaus-b.net/image.axd?picture=ndependContextMenu.png"&gt;&lt;img class="leftImg"  title="NDepend Kontextmenü" alt="NDepend Kontextmenü"  src="http://blog.klaus-b.net/image.axd?picture=ndependContextMenu_thumb.png" width="234" height="480" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Nach der ersten Analyse des aktuellen Projekts, steht in der linken unteren Ecke in Visual Studio ein kleiner farbiger Kreis zur Verfügung, der den aktuellen Status der Analyse des Projekts anzeigt. Es werden die Ampelfarben Rot, Gelb und Grün, sowie Grau und Blau mit folgender Bedeutung verwendet:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rot&lt;/strong&gt;     &lt;br /&gt;- Eine oder mehrere der als kritisch eingestuften Regeln wurde verletzt     &lt;br /&gt;- Eine oder mehrere der aktivierten Regeln kompiliert nicht     &lt;br /&gt;- Eine oder mehrere der aktuellen Abfragen ist fehlerhaft.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Gelb&lt;/strong&gt;     &lt;br /&gt;Eine oder mehrere der aktivierten Regeln wurde verletzt.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Grün&lt;/strong&gt;     &lt;br /&gt;Es wurde keine der aktivierten Regeln verletzt.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Grau&lt;/strong&gt; besagt, dass kein NDepend-Projekt zur Verfügung steht.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Blau&lt;/strong&gt; wird angezeigt, während eine Analyse ausgeführt wird.&lt;/p&gt;  &lt;p&gt;Beim Überfahren des Symbols mit der Maus wird ein Menü sichtbar. In diesem Menü können, unter anderem, die Einstellungen zur Ausführung der Analyse sowie zur Aktualisierung der Analyse in Visual Studio fein eingestellt werden.    &lt;br /&gt;Es kann auch eine Analyse des aktuellen Projekts direkt angestoßen werden.     &lt;br /&gt;Im oberen Bereich wird der aktuelle Status des Projekts in einer Zusammenfassung gezeigt.&lt;/p&gt;  &lt;p&gt;Den Kern der Analyse bildet die in NDepend integrierte &lt;a title="NDepend&amp;#39;s Code-Abfrage-Sprache (CQL)" href="http://ndepend.com/Features.aspx#CQL" rel="nofollow"&gt;Code Query Language&lt;/a&gt; (CQL). Dies Abfragesprache erinnert stark an &lt;a title="SQL (Structured Query Language)" href="http://de.wikipedia.org/wiki/SQL" rel="wiki nofollow"&gt;SQL&lt;/a&gt; und ist auch sehr ähnlich zu verwenden. Zum Bearbeiten bestehender Abfragen oder um neue Regeln zum aktuellen Projekt hinzuzufügen, steht ein integrierter Editor zur Verfügung. Mit diesem Konzept und dem integrierten Editor ist es sehr einfach, bestehende Regeln den aktuellen Anforderungen anzupassen oder neue Regeln zu erstellen.&lt;/p&gt;  &lt;p&gt;Eine der Regeln besagt:    &lt;br /&gt;&lt;em&gt;Felder welche auf die Bezeichnung Uri enden, sollten vom Typ System.&lt;/em&gt;&lt;a title="Uri Klasse" href="http://msdn.microsoft.com/txt7706a.aspx" rel="msdn nofollow"&gt;&lt;em&gt;Uri&lt;/em&gt;&lt;/a&gt;&lt;em&gt; sein.&lt;/em&gt;     &lt;br /&gt;Es kann aber wie in folgendem Beispiel vorkommen, dass der Namensteil Uri verwendet wird aber dennoch der Typ Uri nicht verwendet werden kann. Zum Beispiel ein Feld vom Typ &lt;a title="ConfigurationProperty Klasse" href="http://msdn.microsoft.com/s8ww86kz.aspx" rel="msdn nofollow"&gt;ConfigurationProperty&lt;/a&gt; mit dem Namen &lt;em&gt;serviceUri&lt;/em&gt; würde diese Regel verletzen. Mit dem integrierten CQL-Editor wird einfach als optionales Kriterium     &lt;br /&gt;&lt;em&gt;nicht vom Typ ConfigurationProperty&lt;/em&gt;     &lt;br /&gt;zur Abfrage hinzugefügt.&lt;/p&gt;  &lt;p&gt;&lt;img class="centerImg"  title="System.Uri-Regel" alt="System.Uri-Regel" src="http://blog.klaus-b.net/image.axd?picture=uriRule.png" width="521" height="490" /&gt;&lt;/p&gt;  &lt;p&gt;Die jeweiligen Änderungen oder Anpassungen des Regelwerks sind allerdings nur für das aktuelle Projekt gültig. Ich habe noch keinen Weg gefunden, um allgemeingültige Änderungen des Regelwerks vorzunehmen.&lt;/p&gt;  &lt;p&gt;NDepend analysiert nicht den &lt;a title="Quelltext" href="http://de.wikipedia.org/wiki/Quellcode" rel="wiki nofollow"&gt;Quellcode&lt;/a&gt;, sondern den erzeugten IL-Code in den kompilierten Assemblies. Um die jeweiligen Stellen im Quellcode zeigen zu können, werden Debug-Assemblies mit der zugehörigen &lt;a title="Programmdatenbankdateien" href="http://msdn.microsoft.com/de-de/library/ms241903.aspx" rel="msdn nofollow"&gt;PDB-Datei&lt;/a&gt; benötigt. Eine Analyse von Assemblies mit Release-Status ist nicht vorgesehen.&lt;/p&gt;  &lt;p&gt;Soweit zur Arbeits- und Funktionsweiße.    &lt;br /&gt;Als erstes Projekt zur Analyse mit NDepend habe ich mir eine kleine Anwendung ausgesucht, die als Modul in &lt;a title="ASP.NET" href="http://msdn.microsoft.com/bb400852.aspx" rel="msdn nofollow"&gt;ASP.NET&lt;/a&gt; Anwendungen zum Einsatz kommt. Die Anwendung hat kein UI, wird ausschließlich über die web.config konfiguriert und von einem &lt;a title="Erstellen und Registrieren eines benutzerdefinierten HTTP-Moduls" href="http://msdn.microsoft.com/ms227673.aspx" rel="msdn nofollow"&gt;Http-Modul&lt;/a&gt; gestartet.     &lt;br /&gt;Der erste Report brachte eine Fülle von Informationen und jede Menge Warnungen zu Tage. Die für mich interessanteste Warnung betraf die Sichtbarkeit des verwendeten Http-Moduls, der enthaltenen &lt;a title="Einführung in HTTP-Handler" href="http://msdn.microsoft.com/de-de/library/ms227675.aspx" rel="msdn nofollow"&gt;Http-Handler&lt;/a&gt; und der Klasse der Einstellungen die von &lt;a title="ConfigurationSection Klasse" href="http://msdn.microsoft.com/x0kca287.aspx" rel="msdn nofollow"&gt;ConfigurationSection&lt;/a&gt;&amp;#160; abgeleitet ist. NDepend empfahl diese Klassen als &lt;a title="internal (C#-Referenz)" href="http://msdn.microsoft.com/7c5ka91b.aspx" rel="msdn nofollow"&gt;internal&lt;/a&gt; zu deklarieren.     &lt;br /&gt;Und wie soll dann bitte die Webanwendung auf diese Typen zugreifen? Egal; das wollte ich wissen. Ich deklarierte also die betreffenden Klassen als internal, kompilierte das Projekt im Release-Status neu und startete eine Webanwendung in der ich das Modul verwendete. Zu meiner großen Überraschung funktionierte alles wie gewohnt. Mit dem positiven Nebeneffekt, dass ich keine öffentliche &lt;a title="Programmierschnittstelle" href="http://de.wikipedia.org/wiki/Programmierschnittstelle" rel="wiki nofollow"&gt;API&lt;/a&gt; mehr zur Verfügung stellte die auch so nie vorgesehen war. OK. Wieder etwas dazugelernt.&lt;/p&gt;  &lt;p&gt;NDepend ist auch das erste, mir bekannte, Analyse-Tool welches auf die Unveränderbarkeit von Strukturen (immutable struct) achtet. Hier wird geprüft, ob auch wirklich alle Felder der Struktur als &lt;a title="readonly-Schlüsselwort (C#-Referenz)" href="http://msdn.microsoft.com/de-de/library/acdd6hb7.aspx" rel="msdn nofollow"&gt;readonly&lt;/a&gt; deklariert sind. Dadurch wurde ich angehalten, mich mit der Implementierung von entsprechenden Replace-Methoden in solche unveränderliche Strukturen zu befassen.     &lt;br /&gt;Aber das ist ein anderes Thema.&lt;/p&gt;  &lt;p&gt;Im Allgemeinen sind die Standard-Regeln bereits sehr restriktiv ausgelegt. Wenn sie befolgt und nicht umgangen werden, resultiert aus der konsequenten Anwendung ein deutlich wartbarerer Code.&lt;/p&gt;  &lt;p&gt;NDepend kann natürlich noch deutlich mehr als ich hier in ein paar wenigen Zeilen schreiben kann. Ich werde nach und nach, wenn ich NDepend etwas besser kenne, auf die einzelnen Feature eingehen.&lt;/p&gt;  &lt;h4&gt;Fazit:&lt;/h4&gt;  &lt;p&gt;NDepend erscheint mir als ein hilfreiches Werkzeug, sehr gut geeignet zur täglichen Verwendung. Die Entwickler hinter NDepend leisten sehr gute Unterstützung bei eventuellen Problemen und helfen schnell und unkompliziert.    &lt;br /&gt;Bei meinen Recherchen vor der Verwendung von NDepend, sagte mit einer der Gefragten eine steile Lernkurve mit NDepend voraus. Dem kann ich mich nur anschließen.&lt;/p&gt;  &lt;div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e557db43-a739-4784-98f1-2735fd095e79" class="wlWriterEditableSmartContent"&gt;Technorati-Tags: &lt;a href="http://technorati.com/tags/Review" title="Review" rel="tag"&gt;Review&lt;/a&gt; | &lt;a href="http://technorati.com/tags/NDepend" title="NDepend" rel="tag"&gt;NDepend&lt;/a&gt; | &lt;a href="http://technorati.com/tags/Visual+Studio" title="Visual Studio" rel="tag"&gt;Visual Studio&lt;/a&gt; | &lt;a href="http://technorati.com/tags/Codeanalyse" title="Codeanalyse" rel="tag"&gt;Codeanalyse&lt;/a&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/klaus_b?a=sVICZKZ0yNo:ieoGT_iCdaw: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=sVICZKZ0yNo:ieoGT_iCdaw: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=sVICZKZ0yNo:ieoGT_iCdaw: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/sVICZKZ0yNo" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/klaus_b/~3/sVICZKZ0yNo/post.aspx</link>
      <comments>http://blog.klaus-b.net/post/2011/05/01/Mein-erster-Kontakt-mit-NDepend.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.klaus-b.net/post.aspx?id=3466b477-4328-42a5-a152-8802a8b8b3db</guid>
      <pubDate>Sun, 01 May 2011 18:03:57 +0100</pubDate>
      <category>Visual Studio</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=3466b477-4328-42a5-a152-8802a8b8b3db</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.klaus-b.net/trackback.axd?id=3466b477-4328-42a5-a152-8802a8b8b3db</trackback:ping>
      <wfw:comment>http://blog.klaus-b.net/post/2011/05/01/Mein-erster-Kontakt-mit-NDepend.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.klaus-b.net/syndication.axd?post=3466b477-4328-42a5-a152-8802a8b8b3db</wfw:commentRss>
    <feedburner:origLink>http://blog.klaus-b.net/post.aspx?id=3466b477-4328-42a5-a152-8802a8b8b3db</feedburner:origLink></item>
  </channel>
</rss>

