<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.aspnetzone.de/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Roberto's Blog : Asp.Net</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx</link><description>Ordnungsbegriffe: Asp.Net</description><dc:language /><generator>CommunityServer 2.1 SP2 (Build: 61120.2)</generator><item><title>ASP.NET Mvc multi Upload - Uploadify</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/18/asp-net-mvc-multi-upload-jquery-multiupload-plugin.aspx</link><pubDate>Tue, 18 Jan 2011 07:01:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:220582</guid><dc:creator>Roberto</dc:creator><slash:comments>1</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/220582.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=220582</wfw:commentRss><description>&lt;img src="http://11249.2.sihosting.net/Blog/Images/Multiupload.png" style="float:left;margin-right:10px;" alt="ASP.NET MVC multiupload"&gt;Als ich letzthin die Anforderung hatte, einen file upload in mvc zu machen, habe ich vergebens nach ein &lt;i&gt;@Html.FileUpload&lt;/i&gt; oder Ähnliches gesucht.&lt;br&gt;&lt;br&gt;&lt;b&gt;Die Erkenntnis&lt;/b&gt;: So etwas gibt es in MVC nicht, da man es auch nicht braucht.&lt;br&gt;&lt;br style="clear:left;"&gt;Im Prinzip geht ein FileUpload sehr einfach und zwar so:
&lt;pre class="brush: html"&gt;&amp;lt;form id="myForm" method="post" enctype="multipart/form-data"&amp;gt;
    &amp;lt;input type="file" id="FileInput" name="FileInput" /&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
Serverseitig kann man im Controller über &lt;u&gt;Request.Files["FileInput"]&lt;/u&gt; auf die Datei zugreifen.&lt;br&gt;&lt;br&gt;Wichtig hierbei ist der enctype des form elements. Mit Angabe des Wertes &lt;u&gt;"multipart/form-data"&lt;/u&gt; wird der Inhalt einer jeden Datei in eine getrennte Sektion des multiparts Dokumentes gepackt. Mehr dazu gibt es in einem &lt;a target="_blank" title="Scott Hanselman" href="http://www.hanselman.com/blog/ABackToBasicsCaseStudyImplementingHTTPFileUploadWithASPNETMVCIncludingTestsAndMocks.aspx"&gt;Post&lt;/a&gt; von Scott Hanselman&lt;br&gt;&lt;br&gt;Auf modernen Webseiten ist ein Upload mit ggf. mehreren Dateien und Fortschrittsbalken keine Seltenheit mehr. &lt;br&gt;Eigentlich gibt es viele Plugins, die etwas in der Art machen. Die meisten basieren im Hintergrund auf&amp;nbsp; die Flash Komponente &lt;a target="_blank" title="sfwupload object" href="http://www.swfupload.org/"&gt;swfupload&lt;/a&gt;, die es ermöglicht, mehrere Dateien in einem Schritt auszuwählen und hochzuladen.&lt;br&gt;&lt;br&gt;Mit Hilfe eines einfachen (jQuery) Plugins - &lt;a target="_blank" title="uploadify - jQuery Plugin" href="http://www.uploadify.com"&gt;uploadify&lt;/a&gt;, das mehr oder weniger alles abdeckt, was so verwendet wird, ist dies keine große Sache mehr.&lt;br&gt;&lt;br&gt;Dafür einfach die &lt;a target="_blank" title="uploadify - jQuery plugin download" href="http://www.uploadify.com/download/"&gt;letzte Version herunterladen&lt;/a&gt;, die .js und .css Dateien einbinden&lt;br&gt;

&lt;pre class="brush: html"&gt;&amp;lt;link href="@Url.Content("~/Content/uploadify.css")" rel="stylesheet" type="text/css" /&amp;gt;
&amp;lt;script src="@Url.Content("~/Scripts/jquery.uploadify.v2.1.4.min.js")" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src="@Url.Content("~/Scripts/swfobject.js")" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;

und folgendes an der gewünschten Stelle in den HTML Markup schreiben:

&lt;pre class="brush: html"&gt;&amp;lt;input type="file" id="FileInput" name="FileInput" /&amp;gt;
&lt;/pre&gt;

Ein einfacher Aufruf des Plugins sieht in etwa so aus:

&lt;pre class="brush: js"&gt;$('#FileInput').uploadify({
    'uploader'  : '/Content/swf/uploadify.swf',
    'script'    : '/Home/Upload',
    'cancelImg' : '/Content/Images/cancel.png',
    'folder'    : '/Uploads',
    'auto'      : true
});
&lt;/pre&gt;

&lt;i&gt;Hinweis zu den Paramtern:&lt;/i&gt;&lt;br&gt;uploader: Das swf objekt.&lt;br&gt;script: Die MVC Controller Action.&lt;br&gt;folder: Der Pfad, in dem die Dateien gespeichert werden sollen.&lt;br&gt;&lt;br&gt;Mehr dazu in der &lt;a target="_blank" title="uploadify - jQuery plugin download" href="http://www.uploadify.com/documentation/"&gt;uploadify Dokumentation&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Im Controller reicht folgende Methode aus:

&lt;pre class="brush: c#"&gt;public string Upload(HttpPostedFileBase fileData)
{
    var fileName = Server.MapPath("~/uploads/" + System.IO.Path.GetFileName(FileData.FileName));
    FileData.SaveAs(fileName);

    return "ok";
}
&lt;/pre&gt;

&lt;i&gt;Natürlich kann man als Rückgabe etwas schöneres mit Logik einbauen.&lt;br&gt;&lt;/i&gt;&lt;br&gt;Der Übergabe Parameter muss als "fileData" benannt werden. &lt;br&gt;Ein weiterer Unterschied zu einem normalen Upload ist jener, dass mit &lt;a target="_blank" title="HttpPostedFileBase" href="http://msdn.microsoft.com/de-de/library/system.web.httppostedfilebase.aspx"&gt;HttpPostedFileBase &lt;/a&gt;und nicht &lt;a target="_blank" title="HttpPostedFile" href="http://msdn.microsoft.com/de-de/library/system.web.httppostedfile%28VS.80%29.aspx"&gt;HttpPostedFile &lt;/a&gt;gearbeitet wird.&lt;br&gt;&lt;br&gt;Um ein wenig Sicherheit hinzuzufügen, wird die upload- Methode mit dem &lt;a target="_blank" title="Authorize Attribute" href="http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx"&gt;[Authorize] Attribut&lt;/a&gt; dekoriert.

&lt;pre class="brush: c#"&gt;[Authorize]
public string Upload(...)
&lt;/pre&gt;

Das Plugin meldet nun einen Fehler. &lt;br&gt;Da es aber ohne dem Authorize Attribute im Prinzip funktioniert hat, wurde durch eine Suche im Internet schnell klar, dass es sich eigentlich um einen &lt;a target="_blank" title="Flash bug" href="https://bugs.adobe.com/jira/browse/FP-1044"&gt;Bug in Flash&lt;/a&gt; handelt der in dem Fall zur Folge führt, dass die ASP.NET Session und Autentifizierungs- Cookies nicht mitsendet werden.&lt;br&gt;&lt;br&gt;Ein Workaround für dieses Problem bietet uploadify zum Glück mit dem "scriptData" Parameter, dem manuell das Authentifizierungstoken und die ASP.NET SessionId mitgegeben werden könen.&lt;br&gt;&lt;br&gt;Folgendes wird im Aufruf des Plugins hinzugefügt/geändert:

&lt;pre class="brush: c#"&gt;var token = "@(Request.Cookies[FormsAuthentication.FormsCookieName]==null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value)";
var sessionId = "@Session.SessionID";

$('#FileInputWithAuth').uploadify({
    ...
    'scriptData': { SessionId: sessionId, Token: token }
});
&lt;/pre&gt;

Durch die &lt;a target="_blank" title="Stackoverflow" href="http://stackoverflow.com/questions/1729179/uploadify-session-and-authentication-with-asp-net-mvc"&gt;Diskussion auf StackOverFlow&lt;/a&gt; und dem &lt;a target="_blank" title="Workaround for flash cookies bug in asp.net mvc" href="http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx"&gt;folgenden Blog Post &lt;/a&gt;bin ich auf &lt;b&gt;zwei Möglichkeiten&lt;/b&gt; gestoßen, um serverseitig die mitgegeben Parametern zu verarbeiten und in die Authentifizierungs- Logik einzubringen.&lt;br&gt;&lt;ul&gt;&lt;li&gt;Die SessionId und das Authentifizierungscookie in der &lt;b&gt;Global.asax&lt;/b&gt; wiedererstellen&lt;/li&gt;&lt;li&gt;Ein eigenes &lt;b&gt;Authorize Attribut&lt;/b&gt;, das ebenfalls das Cookie ausliest und validiert.&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br&gt;Möglichkeit 1) Global.asax&lt;/b&gt;&lt;br&gt;&lt;br&gt;In der Begin Request methode folgenden code unterbringen:

&lt;pre class="brush: c#"&gt;protected void Application_BeginRequest(object sender, EventArgs e)
{
    try
    {
        const string sessionParamName = "SessionId";
        const string sessionCookieName = "ASP.NET_SessionId";

        if (HttpContext.Current.Request.Form[sessionParamName] != null)
        {
            UpdateCookie(sessionCookieName, HttpContext.Current.Request.Form[sessionParamName]);
        }
        else if (HttpContext.Current.Request.QueryString[sessionParamName] != null)
        {
            UpdateCookie(sessionCookieName, HttpContext.Current.Request.QueryString[sessionParamName]);
        }
    }
    catch
    {
    }

    try
    {
        const string authParamName = "Token";
        string authCookieName = FormsAuthentication.FormsCookieName;

        if (HttpContext.Current.Request.Form[authParamName] != null)
        {
            UpdateCookie(authCookieName, HttpContext.Current.Request.Form[authParamName]);
        }
        else if (HttpContext.Current.Request.QueryString[authParamName] != null)
        {
            UpdateCookie(authCookieName, HttpContext.Current.Request.QueryString[authParamName]);
        }
    }
    catch
    {
    }
}

private static void UpdateCookie(string cookieName, string cookieValue)
{
    var cookie = HttpContext.Current.Request.Cookies.Get(cookieName) ?? new HttpCookie(cookieName);
    cookie.Value = cookieValue;
    HttpContext.Current.Request.Cookies.Set(cookie);
}
&lt;/pre&gt;

&lt;b&gt;Möglichkeit B) Das eigene Attribut:&lt;/b&gt;

&lt;pre class="brush: c#"&gt;public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    private const string TokenKey = "token";

    protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
    {
        var token = httpContext.Request.Params[TokenKey];

        if (token != null)
        {
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);

            if (ticket != null)
            {
                var identity = new FormsIdentity(ticket);
                var principal = ...
            }
        }

        return base.AuthorizeCore(httpContext);
    }
}
&lt;/pre&gt;

Im Prinzip funktionieren beide Möglichkeiten einwandfrei, wobei mir persönlich das Attribut besser gefällt. Zum einen, da der code in der Global.asax jedesmal ausgeführt wird und er eigentlich nur für die speziellen asynchronen upload requests benötigt wird, zum anderen kann man die Logik im Attribut besser auslagern.&lt;br&gt;&lt;br&gt;Anbei gibt’s das Beispiel mit beiden Varianten.&lt;br&gt;&lt;br&gt;
&lt;div class="DownloadBox"&gt;
&lt;a title="ASP.NET MVC 3 multiupload mit jQuery uploadify plugin sample download" href="http://www.aspnetzone.de/files/folders/220583/download.aspx"&gt;ASP.NET MVC multiupload mit jQuery uploadify.&lt;/a&gt;&lt;br&gt;
&lt;/div&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/18/asp-net-mvc-multi-upload-jquery-multiupload-plugin.aspx"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/18/asp-net-mvc-multi-upload-jquery-multiupload-plugin.aspx&amp;amp;bgcolor=3169AD&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000" alt="DotNetKicks-DE Image" border="0"&gt;&lt;/a&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=220582" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Plugin/default.aspx">Plugin</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Mvc/default.aspx">Mvc</category></item><item><title>ASP.NET Mvc 3 unobtrusive validation - erweitern mit eigenen jQuery Adaptern und Validatoren</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx</link><pubDate>Thu, 13 Jan 2011 07:30:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:220524</guid><dc:creator>Roberto</dc:creator><slash:comments>1</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/220524.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=220524</wfw:commentRss><description>&lt;ol style="list-style:none outside none;"&gt;&lt;li&gt;&lt;a title="Teil 1: ASP.NET Mvc3 unobtrusive Validierung" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx"&gt;Teil 1: ASP.NET Mvc 3 unobtrusive validation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="Teil 2: ASP.NET Mvc3 unobtrusive validation - clientseitige Adapter" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;Teil 2: Unobtrusive validation - Clientseitige Adapter&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="mvc3 unobtrusive validation - erweitern mit eigenen Adaptern, Attributen und Validatoren" href="http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx"&gt;Teil 3: Unobtrusive validation - Eigene Adapter erstellen&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;Grundsätzlich gibt es serverseitig zwei Möglichkeiten die eigenen Attribute für die Validierung zu Gestalten:&lt;br&gt;&lt;br&gt;Implementierung einer Basisklasse wie &lt;a title="RegularExpressionAttribute" target="_blank" href="http://msdn.microsoft.com/de-de/library/system.componentmodel.dataannotations.regularexpressionattribute.aspx"&gt;RegularExpressionAttribute &lt;/a&gt;sowie des Interfaces &lt;a target="_blank" title="IClientValidatable" href="http://msdn.microsoft.com/en-us/library/system.web.mvc.iclientvalidatable%28v=vs.98%29.aspx"&gt;IClientValidatable&lt;/a&gt;&lt;br&gt;Implementierung einer Basisklasse wie &lt;a title="RegularExpressionAttribute" target="_blank" href="http://msdn.microsoft.com/de-de/library/system.componentmodel.dataannotations.regularexpressionattribute.aspx"&gt;RegularExpressionAttribute &lt;/a&gt;und den Einbau eines &lt;a target="_blank" title="DataAnnotaionsModelValidator" href="http://msdn.microsoft.com/de-de/library/system.web.mvc.dataannotationsmodelvalidator.aspx"&gt;DataAnnotationsModelValidator&lt;/a&gt;&lt;br&gt;&lt;br&gt;Im Prinzip hat &lt;a title="jQuery Adapter zur Konvertierung von HTML5 Attributen" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;der letzte Post&lt;/a&gt; gezeigt, dass ein jQuery Adapter die Konvertierung von HTML5 Attributen in die für jQuery kompatiblen Metadaten vornimmt.&lt;br&gt;&lt;br&gt;Diese HTML5 Attribute haben alle die selbe Form: data-val-&amp;lt;xxx&amp;gt;&lt;br&gt;&lt;br&gt;Als Beispiel gibt es bereits vordefinierte Konstellationen wie &lt;u&gt;data-val-regex&lt;/u&gt; und data-&lt;u&gt;val-regex-pattern&lt;/u&gt;.&lt;br&gt;&lt;br&gt;Somit würde der im Hintergrund stehende Adapter nichts anderes machen, als zu überprüfen, ob ein Feld mit dem Attribut data-val-regex gesetzt ist und wenn ja, das dazugehörige pattern auslesen und validieren.&lt;br&gt;&lt;br&gt;Im nachstehenden Beispiel wird ein eigenes, triviales Email Attribut erstellt, um die Umsetzung etwas deutlicher zu erklären.&lt;br&gt;&lt;br&gt;&lt;b&gt;Möglichkeit 1) IClientValidatable&lt;/b&gt;&lt;br&gt;&lt;br&gt;Das Attribut

&lt;pre class="brush: c#;"&gt;public class EmailWithoutValidatorAttribute : RegularExpressionAttribute, IClientValidatable 
{ 
    public EmailWithoutValidatorAttribute() : base(@"&amp;lt;emailregex&amp;gt;")
    {

    }
 
    public IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules(ModelMetadata metadata, 
                                                                             ControllerContext context)
    {
        var rule = new ModelClientValidationRule(...);
        return new[] { rule };
    }
}
&lt;/pre&gt;

Eigentlich nur ein RegularExpressionAttrubite wie von früheren Zeiten gewohnt, sowie eine zusätzliche Methode GetClientValidationRules, die die Rückgabe einer Liste von Regeln erwartet. Ob eine oder mehrere Regeln zurückgegeben werden, ist irrelevant.&lt;br&gt;&lt;br&gt;Nun reicht eine normale &lt;a target="_blank" title="ModelClientValidationRule" href="http://msdn.microsoft.com/en-us/library/system.web.mvc.modelclientvalidationrule.aspx"&gt;ModelClientValidationRule &lt;/a&gt;für das Vorhaben nicht aus, somit wird eine eigene erstellt. Diese hat den Vorteil, dass ein eigener &lt;b&gt;validationType &lt;/b&gt;(Der eigentliche Name des Adapters, der später benötigt wird) angegeben werden kann.

&lt;pre class="brush: c#;"&gt;public class NamedRegexValidationRule : ModelClientValidationRule
{
    public NamedRegexValidationRule(string errorMessage,
                               string pattern, string validationType)
    {
        this.ErrorMessage = errorMessage;
        this.ValidationType = validationType;
        this.ValidationParameters.Add("pattern", pattern);
    }
}
&lt;/pre&gt;

Die im Code gezeigten ValidationParemeters können beliebig gefüllt werden, benötigt wird hier ausschließlich das Pattern.&lt;br&gt;&lt;br&gt;&lt;i&gt;Hinweis: Die &amp;lt;string, object&amp;gt; collection kann beliebig gefüllt werden. Letztendlich&amp;nbsp; wird jedes Element als ein html Attribut data-val-&amp;lt;string&amp;gt;="&amp;lt;value&amp;gt;" gerendert. Es ist somit egal, ob "pattern" oder "blubr" vorkommt.&lt;/i&gt;&lt;br&gt;&lt;br&gt;Die angepasste Methode im Attribut würde somit wie folgt aussehen (Wichtig ist der Name „customemail“, dieser wird als Adaptername verwendet und kann ausschließlich mit Kleinbuchstaben angegeben werden)

&lt;pre class="brush: c#;"&gt;public IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules(ModelMetadata metadata, 
                                                                         ControllerContext context)
{
    var rule = new NamedRegexValidationRule(this.ErrorMessage, this.Pattern, "customemail");
    return new[] { rule };
}
&lt;/pre&gt;

Angenommen es ist ein Model "Person" mit einer Eigenschaft "Email" vorhanden, die mit dem eben erstellen Attribut versehen ist:

&lt;pre class="brush: c#;"&gt;public class Person
{
    [EmailWithoutValidator(ErrorMessage = "Not a valid email.")]
    public string Email { get; set; }
}
&lt;/pre&gt;

Das dazugehörige Feld als gerenderter Version &lt;i&gt;@Html.TextBoxFor(p =&amp;gt; p.Email)&lt;/i&gt;

&lt;pre class="brush: html;"&gt;&amp;lt;input type="text" value="" name="Email" id="Email" class="input-validation-error"
    data-val-customemail-pattern="&amp;lt;EmailPattern&amp;gt;" 
    data-val-customemail="Not a valid email." 
    data-val="true"&amp;gt;
&lt;/pre&gt;

Zwei Sachen wurden damit erreicht:&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;u&gt;data-val-customemail&lt;/u&gt; steht für die angegebene Fehlermeldung.&lt;/li&gt;&lt;li&gt;&lt;u&gt;data-val-customemail-pattern&lt;/u&gt; steht für das angegebene Email Pattern.&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;b&gt;Möglichkeit 2)&lt;/b&gt; &lt;b&gt;DataAnnotationsModelValidator&lt;/b&gt;

&lt;pre class="brush: c#;"&gt;public class EmailWithValidatorAttribute : RegularExpressionAttribute
{
    public EmailWithValidatorAttribute() : base(@"&amp;lt;EmailRegex&amp;gt;")
    {
    }
}
&lt;/pre&gt;

Nichts anderes als bei Möglichkeit 1, ohne der Implementierung des IClientValidatable Interfaces und somit der Erstellung der Regeln.&lt;br&gt;&lt;br&gt;Diese werden bei dieser Variante &lt;b&gt;in den Validator&lt;/b&gt; ausgelagert:

&lt;pre class="brush: c#;"&gt;public class EmailValidator : DataAnnotationsModelValidator&amp;lt;EmailWithValidatorAttribute&amp;gt;
{
    private readonly string _errorMessage;
    private readonly string _pattern;

    public EmailValidator(ModelMetadata metadata, ControllerContext context, EmailWithValidatorAttribute attribute) 
                       : base(metadata, context, attribute)
    {
        this._errorMessage = attribute.ErrorMessage;
        this._pattern = attribute.Pattern;
    }

    public override IEnumerable&amp;lt;ModelClientValidationRule&amp;gt; GetClientValidationRules()
    {
        var rule = new NamedRegexValidationRule(this._errorMessage, this._pattern, "customemail");
        return new[] { rule };
    }
}
&lt;/pre&gt;

Auch hier gibt es eine Methode &lt;u&gt;GetClientValidationRules()&lt;/u&gt;, die eigentlich die selbe Logik beinhaltet, wie in Möglichkeit 1.&lt;br&gt;&lt;br&gt;Zusätzlich muss der Validator nun in der Global.asax (In der application start Methode) noch mit Angabe des Attributes registriert werden:

&lt;pre class="brush: c#;"&gt;DataAnnotationsModelValidatorProvider.RegisterAdapter(
                            typeof(EmailWithValidatorAttribute), 
                            typeof(EmailValidator));
&lt;/pre&gt;

Im Prinzip bringen beide Möglichkeiten das selbe Ergebnis, Möglichkeit 1 hat den Nachteil (zumindest für den ein oder anderen), dass die Logik direkt im Attribut steht und Möglichkeit 2 lagert dies in einen externen Validator aus. Somit ist das Attribut nicht MVC abhängig und könnte auch für andere Zwecke verwendet werden, bzw. bereits vorhandene Attribute könnten problemlos wiederverwendet werden.&lt;br&gt;&lt;br&gt;&lt;br&gt;Last but not least, &lt;b&gt;der clientseitige Aufbau des Adapters.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Die jQuery unobtrusive validation Bibliothek stellt eine Methode Add() zur Verfügung, über welche neue, eigene Adapter registiert werden können. Diese nimmt als Parameter einmal den Adapternamen, den/die Attributnamen die benötig werden, sowie eine Funktion, über die die eigene Logik implementiert werden kann.&lt;br&gt;

&lt;pre class="brush: js;"&gt;jQuery.validator.unobtrusive.adapters.add("customemail", ["pattern"], function (options) {

    if (options.element.tagName.toUpperCase() == "INPUT") {

        // Set the regex rule with the given pattern.
        options.rules["regex"] = options.params.pattern;

        if (options.message) {
            options.messages["regex"] = options.message;
        }
    }
});
&lt;/pre&gt;

Wie im &lt;a title="jQuery Validation Adapter object parameters" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;letzten Post gezeigt&lt;/a&gt;, beinhaltet das options Objekt Regeln, Parameter und Mitteilungen, über die die Validierung gesteuert wird.&lt;br&gt;&lt;br&gt;In Falle einer Email Validierung reicht eine regex Regel aus, es können aber beliebig viele hinzugefügt werden. Wichtig ist hierbei nur, dass diese als Paremter angegeben werden ["pattern", "&amp;lt;anderes Attribut"&amp;gt;, ...]&lt;br&gt;&lt;br&gt;Natürlich macht es nicht wirklich viel Sinn, ein Email Attribut so kompliziert zu gestalten, viel mehr geht es darum zu zeigen, wie es im Verhältnis doch einfach ist, eigene Adapter zu erstellen. Im Web 2.0 Zeitalter ist eine kombination aus client und server Validierung eher Standard als eine Ausnahme. Mit ein bisschen Mühe können tolle Sachen, wie bspw.&amp;nbsp; eine Überprüfung, ob ein Username einzigartig ist entwickelt werden. Der Große Vorteil liegt auch hier in der Entkoppelung der Validierungslogik vom restlichen Teil der Anwendung.&lt;br&gt;&lt;br&gt;Anbei gibt’s wie immer das Beispiel zum Post.&lt;br&gt;&lt;br&gt;&lt;div class="DownloadBox"&gt;
&lt;a title="ASP.NET MVC 3 custom unobstrusive validation sample with jQuery adapters, attributes and validators" href="http://www.aspnetzone.de/files/folders/220527/download.aspx"&gt;ASP.NET MVC 3 unobstrusive custom validation sample.&lt;/a&gt;&lt;br&gt;
&lt;/div&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx&amp;amp;bgcolor=3169AD&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000" alt="DotNetKicks-DE Image" border="0"&gt;&lt;/a&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=220524" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Mvc/default.aspx">Mvc</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Validation/default.aspx">Validation</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Html5/default.aspx">Html5</category></item><item><title>ASP.NET unobtrusive validation - Clientseitige Adapter</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx</link><pubDate>Mon, 27 Dec 2010 13:15:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:220384</guid><dc:creator>Roberto</dc:creator><slash:comments>2</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/220384.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=220384</wfw:commentRss><description>&lt;ol style="list-style:none outside none;"&gt;&lt;li&gt;&lt;a title="Teil 1: ASP.NET Mvc3 unobtrusive Validierung" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx"&gt;Teil 1: ASP.NET Mvc 3 unobtrusive validation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="Teil 2: ASP.NET Mvc3 unobtrusive validation - clientseitige Adapter" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;Teil 2: Unobtrusive validation - Clientseitige Adapter&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="mvc3 unobtrusive validation - erweitern mit eigenen Adaptern, Attributen und Validatoren" href="http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx"&gt;Teil 3: Unobtrusive validation - Eigene Adapter erstellen&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;Wie bereits &lt;a title="Teil 1: ASP.NET Mvc3 unobtrusive Validierung" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx"&gt;im letzten Post&lt;/a&gt; beschrieben, gibt es seit der dritten Version des MVC Frameworks die Möglichkeit, Formular Validierungen über HTML 5 kompatible Attribute zu machen.&lt;br&gt;&lt;br&gt;Diese werden clientseitig über &lt;a title="Adapter" target="_blank" href="http://de.wikipedia.org/wiki/Adapter_%28Entwurfsmuster%29"&gt;Adapter&lt;/a&gt; umgesetzt, die die entsprechenden Parameterwerte aus den HTML 5 Attributen in die für jQuery Validate vorgesehenen Metadaten konvertieren.&lt;br&gt;&lt;br&gt;In diesem Post wird nicht genauer auf das jQuery Validate Plugin eingegangen, sondern mehr über die Logik und Konvertierungsmechanismen der Adapter.&lt;br&gt;&lt;br&gt;Mehr Informationen zu jQuery Validate finden sich &lt;a title="jQuery Validate Plugin" target="_blank" href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/"&gt;hier&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Als weiteres, für den Post relevanteres Plugin findet sich das &lt;i&gt;jQuery.validator.unobtrusive.adapters.js&lt;/i&gt; im Ordner Scripts eines jeden MVC3 Projekttemplates.&lt;br&gt;&lt;br&gt;Im Script gibt es eine Registrierungsmethode "add", sowie einige allgemeine Methoden "addBool", "addSingleVal" und "addMinMax".&lt;br&gt;&lt;br&gt;Im Grunde sind die meisten Fälle damit abgedeckt, als Beispiel ein Auszug aus der eben genannten Datei:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;adapters.addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"creditcard"&lt;/span&gt;).addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"date"&lt;/span&gt;).addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"digits"&lt;/span&gt;).addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"email"&lt;/span&gt;).addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"number"&lt;/span&gt;).addBool(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"url"&lt;/span&gt;);&lt;br /&gt;adapters.addSingleVal(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"accept"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"exts"&lt;/span&gt;).addSingleVal(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"regex"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"pattern"&lt;/span&gt;);&lt;br /&gt;adapters.addMinMax(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"length"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"minlength"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"maxlength"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"rangelength"&lt;/span&gt;).addMinMax(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"range"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"min"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"max"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"range"&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Bevor genauer auf die einzelnen Methoden eingegangen wird, eine kurze Erklärung zur Methode "add", die intern von jeder aufgerufen wird:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;adapters.add &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;function&lt;/span&gt; (adapterName, params, fn)&lt;br /&gt;{&lt;br /&gt;....&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;adapterName&lt;/b&gt;: Ist der Name des zu hinzuzufügenden Adapters. Im Prinzip nichts anderes, als der im Attribut data-val-&amp;lt;Name&amp;gt; vorkommenden Platzhalter.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;params&lt;/b&gt;: Ist ein optionales Array aus Parametern, die aus den Attributen data-val-&amp;lt;Name&amp;gt;-&amp;lt;Paremter&amp;gt; extrahiert werden.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;fn&lt;/b&gt;: Ist die Funktion, welche die Werte der Html Attribute in die für "jQuery Validate" benötigten Regeln und/oder Mitteilungen konvertiert.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Die Methode &lt;b&gt;addBool&lt;/b&gt; macht somit einen in etwa ähnlichen Aufruf: &lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;add(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"email"&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;function&lt;/span&gt;(options) {&lt;br /&gt;    ...&lt;br /&gt;    options.rules[&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"required"&lt;/span&gt;] &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; true;&lt;br /&gt;    ...&lt;br /&gt;});&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;i&gt;Hinweis&lt;/i&gt;: Das &lt;b&gt;option Element&lt;/b&gt; beinhaltet &lt;b&gt;folgende Werte:&lt;/b&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;element&lt;/b&gt;: Das HTML Element dem der Validator zugeordnet ist.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;form&lt;/b&gt;: Das HTML Form Element.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;message&lt;/b&gt;: Die Ausgabe, die ebenfalls aus den HTML Attributen extrahiert wird.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;params&lt;/b&gt;: Ein Array Element mit Werten, die aus den HTML Attributen extrahiert werden. (Bspw. var min = options.params.min)&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;rules&lt;/b&gt;: Das Array Element, das die Namen und Werte beinhaltet, die wiederum für die jQuery Validate Regel benötigt werden. (Bspw. ["required"] = true)&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;messages&lt;/b&gt;: Ein Array Element, das die Namen und Werte beinhaltet, wobei der Name für die verletze Regel und der Wert für die dazugehörige Ausgabe stehen. (Bspw. ["required"] = "Das Feld darf nicht leer sein.")&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Nun sollte auch die &lt;b&gt;addSingleValue&lt;/b&gt; anhand eines Beispiels verständlich werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;adapters.addSingleVal(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"regex"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"pattern"&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Gegeben ist ein HTML Element, wobei die Eingabe nicht leer sein kann und es nur Großbuchstaben beinhalten darf. (= dem Regex [A-Z] enstprechen).&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;input ... &lt;br /&gt;data-val="true"&lt;br /&gt;data-val-required="Das Feld darf nicht leer sein."&lt;br /&gt;data-val-regex="Das Feld darf nur Großbuchstaben beinhalten."&lt;br /&gt;data-val-regex-pattern="[A-Z]" /&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Folgende Werte würden daraus entstehen:&lt;br&gt;&lt;br&gt;-&amp;gt; options.rules["required"] = true&lt;br&gt;-&amp;gt; options.rules["regex"] = "[A-Z]"&lt;br&gt;-&amp;gt; options.messages["required"] = "Das Feld darf nicht leer sein."&lt;br&gt;
-&amp;gt; options.messages["regex"] = "Das Feld darf nur Großbuchstaben beinhalten."&lt;br&gt;&lt;br&gt;Und natürlich würde auch addMinMax nichts anderes machen, als ein paar "rules" wie bspw. "min", "max" zu setzen.&lt;br&gt;&lt;br&gt;Am Besten einfach ein paar Testelemente machen und mit der &lt;a title="Firebug - Firefox Extensions" target="_blank" href="https://addons.mozilla.org/de/firefox/addon/1843/"&gt;Firefox Extension Firebug&lt;/a&gt; ansehen.&lt;br&gt;&lt;br&gt;Im nächsten Teil wird dann genauer auf die Erstellung eigener Adapters eingegangen!&lt;br&gt;&lt;br&gt;

&lt;a href="http://dotnet-kicks.de/kick/?url=http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx&amp;amp;bgcolor=3169AD&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000" alt="DotNetKicks-DE Image" border="0"&gt;&lt;/a&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=220384" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Mvc/default.aspx">Mvc</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Validation/default.aspx">Validation</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Html5/default.aspx">Html5</category></item><item><title>ASP.NET Mvc 3 unobtrusive validation</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx</link><pubDate>Sun, 26 Dec 2010 10:55:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:220382</guid><dc:creator>Roberto</dc:creator><slash:comments>1</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/220382.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=220382</wfw:commentRss><description>&lt;img src="http://11249.2.sihosting.net/Blog/Images/MvcValidation.png" style="float:left;margin-right:10px;" alt="ASP.NET MVC3 unobtrusive Validation"&gt;In dieser dreiteiligen Postreihe wird gezeigt, wie sich ab ASP.NET Mvc 3 die Validierung von Formularen geändert hat, welche Vorteile sie mit sich bringt und wie die Validierung mit eigenen Regeln erweitert wird.&lt;br&gt;&lt;div style="margin-left:10px;"&gt;&lt;ol style="list-style:none outside none;"&gt;&lt;li&gt;&lt;a title="Teil 1: ASP.NET Mvc3 unobtrusive Validierung" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx"&gt;Teil 1: ASP.NET Mvc 3 unobtrusive validation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="Teil 2: ASP.NET Mvc3 unobtrusive validation - clientseitige Adapter" href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/27/ASP-NET-mvc3-unobtrusive-validation-clientseitige-adapter.aspx"&gt;Teil 2: Unobtrusive validation - Clientseitige Adapter&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="mvc3 unobtrusive validation - erweitern mit eigenen Adaptern, Attributen und Validatoren" href="http://www.aspnetzone.de/blogs/robertobez/archive/2011/01/13/mvc3-unobtrusive-validation-eigene-jquery-adapter-validator-attributes.aspx"&gt;Teil 3: Unobtrusive validation - Eigene Adapter erstellen&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;br style="clear:left;"&gt;Bereits in &lt;a target="_blank" title="ASP.NET MVC2" href="http://www.asp.net/mvc"&gt;MVC2&lt;/a&gt; gab es eine client und serverseitige &lt;a target="_blank" title="MVC2 model validation" href="http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx"&gt;Validierung für Models&lt;/a&gt;.&lt;br&gt;Standartmäßig für den Client mit ASP.NET Ajax, aber auch mit einer kleinen &lt;a target="_blank" title="JQuery" href="http://www.jquery.com"&gt;jQuery &lt;/a&gt;Erweiterung machbar.&lt;br&gt;&lt;br&gt;Bereits durch dieses Verfahren wurde der &lt;b&gt;serverseitige Teil&lt;/b&gt; (Durch den Einsatz von DataAnnotations) vom &lt;b&gt;Clientseitigen &lt;/b&gt;entkoppelt.&lt;br&gt;&lt;br&gt;&lt;br style="clear:left;"&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; Mandant&lt;br /&gt;{&lt;br /&gt;    [Required(ErrorMessage &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Name is required."&lt;/span&gt;)]&lt;br /&gt;    [StringLength(50, ErrorMessage &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Must be under 50 characters."&lt;/span&gt;)]&lt;br /&gt;    [DisplayName(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Mandant Name"&lt;/span&gt;)]&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; Name { get; set; }&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Was im Html Code dabei gerendert wird, sieht in etwa so aus:&lt;span class="sourceRowText "&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;//&amp;lt;![CDATA[&lt;br /&gt;if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }&lt;br /&gt;window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"Mandant.Name","ReplaceValidationMessageContents":true,"ValidationMessageId":"Mandant_Name_validationMessage","ValidationRules":[{"ErrorMessage":"Name is required.","ValidationParameters":{},"ValidationType":"required"},{"ErrorMessage":"Must be under 50 characters.","ValidationParameters":{"minimumLength":0,"maximumLength":50},"ValidationType":"stringLength"}]}, ...&lt;br /&gt;//]]&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Ab der dritten Version des MVC Frameworks wird die Validierung hingegen etwas schicker gelöst.&lt;br&gt;&lt;br&gt;Im Prinzip bringt die Neuerung den Vorteil mit sich, dass auf einen langen JSON String im Html code &lt;b&gt;verzichtet wird&lt;/b&gt; und dafür auf &lt;b&gt;HTML5 kompatible Attribute&lt;/b&gt; gesetzt wird, die die Validierung der Input Felder beschreiben.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;input&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;type&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="text"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;value&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=""&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="Name"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;id&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="Name"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;data-val-required&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="The Name field is required."&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;data-val&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="true"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="input-validation-error"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;input&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;type&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="text"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;value&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=""&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="Age"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;id&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="Age"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;data-val-required&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="The Age field is required."&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;data-val-number&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="The field Age must be a number."&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;data-val&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="true"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="input-validation-error"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Ein weiterer Vorteil ist der Verzicht auf automatisch generierte IDs, da die Informationen nun direkt am Input Feld angefügt werden.&lt;br&gt;&lt;br&gt;Um diese "&lt;b&gt;unobtrusive&lt;/b&gt;" (Übersetzt: unauffällig, bescheiden) Validierung nutzen zu können, sind zwei einfache Schritte notwendig.&lt;br&gt;&lt;br&gt;Folgende Script Bilbiotheken einbinden:&lt;br&gt;&lt;br&gt;&lt;i&gt;(Beim erstellen eines neuen MVC3 Projekts werden diese standartmäßig eingebunden)&lt;/i&gt;&lt;br&gt;&lt;span style="color:blue;"&gt;&lt;br&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;src&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"&lt;/span&gt;&lt;span style="background:none repeat scroll 0% 0% yellow;"&gt;@&lt;/span&gt;&lt;span style="color:blue;"&gt;Url&lt;/span&gt;&lt;span style="color:blue;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Content&lt;/span&gt;&lt;span style="color:blue;"&gt;(&lt;/span&gt;&lt;span&gt;"~/Scripts/jquery-1.4.1.min.js"&lt;/span&gt;&lt;span style="color:blue;"&gt;)"&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"text/javascript"&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;src&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"&lt;/span&gt;&lt;span style="background:none repeat scroll 0% 0% yellow;"&gt;@&lt;/span&gt;&lt;span style="color:blue;"&gt;Url&lt;/span&gt;&lt;span style="color:blue;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Content&lt;/span&gt;&lt;span style="color:blue;"&gt;(&lt;/span&gt;&lt;span&gt;"~/Scripts/jquery.unobtrusive-ajax.min.js"&lt;/span&gt;&lt;span style="color:blue;"&gt;)"&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"text/javascript"&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;br&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;src&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"&lt;/span&gt;&lt;span style="background:none repeat scroll 0% 0% yellow;"&gt;@&lt;/span&gt;&lt;span style="color:blue;"&gt;Url&lt;/span&gt;&lt;span style="color:blue;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Content&lt;/span&gt;&lt;span style="color:blue;"&gt;(&lt;/span&gt;&lt;span&gt;"~/Scripts/jquery.validate.min.js"&lt;/span&gt;&lt;span style="color:blue;"&gt;)"&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"text/javascript"&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;src&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"&lt;/span&gt;&lt;span style="background:none repeat scroll 0% 0% yellow;"&gt;@&lt;/span&gt;&lt;span style="color:blue;"&gt;Url&lt;/span&gt;&lt;span style="color:blue;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Content&lt;/span&gt;&lt;span style="color:blue;"&gt;(&lt;/span&gt;&lt;span&gt;"~/Scripts/jquery.validate.unobtrusive.min.js"&lt;/span&gt;&lt;span style="color:blue;"&gt;)"&lt;/span&gt;&amp;nbsp;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:blue;"&gt;"text/javascript"&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:maroon;"&gt;script&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;br&gt;&lt;br&gt;&lt;/span&gt;Dazu noch sicherstellen, dass in der Web.Config folgende Einstellungen gesetzt sind:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;appSettings&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;add&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;key&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="ClientValidationEnabled"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;value&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="true"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt; &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;add&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;key&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="UnobtrusiveJavaScriptEnabled"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;value&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="true"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;appSettings&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;i&gt;&lt;br&gt;Diese sind ebenfalls ab einem MVC3 Projekt-Template standartmäßig dabei, bei einem Upgrade von einer älteren Version müssen sie manuell hinzugefügt werden.&lt;br&gt;&lt;/i&gt;&lt;br&gt;Die eben genannten Einstellungen sind Global für das ganze Projekt, natürlich gibts diese auch Kontext spezifisch:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;HtmlHelper.ClientValidationEnabled &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;;&lt;br /&gt;HtmlHelper.UnobtrusiveJavaScriptEnabled &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Dazu wie gewohnt das Model mit den DataAnnotations versehen (siehe weiter oben) und das Ganze sollte funktionieren.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Und wie das Ganze im Hintergrund funktioniert?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Grundsätzlich hängt alles davon ab, ob das &lt;b&gt;data-val="true"&lt;/b&gt; Attribut gesetzt ist.&lt;br&gt;Dieses wird dem Feld hinzugefügt, wenn mindestens eine Regel aktiv ist. &lt;br&gt;Die wohl am meisten verwendete Regel ist jene, die besagt, ob ein Feld ein Pflichtfeld ist. (Html Attribut dazu: data-val-required="true")&lt;br&gt;Natürlich gibt es zusätzlich verschiedene optionale &lt;a target="_blank" title="Data Annotations" href="http://msdn.microsoft.com/de-de/library/system.componentmodel.dataannotations.aspx"&gt;Attribute &lt;/a&gt;wie data-val-length, data-val-length-min (max), data-val-range-min (max), data-val-regex, data-val-regex-pattern, usw.&lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;br&gt;Fazit:&lt;/b&gt;&lt;br&gt;&lt;br&gt;Ich habe bereits ein Projekt umgestellt, es geht relativ fix und ist doch um einiges schöner - somit: man sollte sich die Arbeit antun.&lt;br&gt;&lt;br&gt;Im nächsten Post wird genauer auf eigene jQuery Validators eingegangen, schaut also vorbei :-)&lt;br&gt;&lt;br&gt;Anbei wie immer das Beispiel:&lt;br&gt;&lt;br&gt;

&lt;div class="DownloadBox"&gt;
&lt;a title="ASP.NET MVC 3 unobstrusive validation sample" href="http://www.aspnetzone.de/files/folders/220381/download.aspx"&gt;ASP.NET MVC 3 unobstrusive validation sample.&lt;/a&gt;
&lt;/div&gt;
&lt;a href="http://dotnet-kicks.de/kick/?url=http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx"&gt;&lt;img src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http://www.aspnetzone.de/blogs/robertobez/archive/2010/12/26/asp-net-mvc3-unobtrusive-validation.aspx&amp;amp;bgcolor=3169AD&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000" alt="DotNetKicks-DE Image" border="0"&gt;&lt;/a&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=220382" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Mvc/default.aspx">Mvc</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Validation/default.aspx">Validation</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Html5/default.aspx">Html5</category></item><item><title>MVC Html Helper á la Fluent Interface</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/06/08/mvc-html-helpers-fluent-interface.aspx</link><pubDate>Tue, 08 Jun 2010 21:45:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:217589</guid><dc:creator>Roberto</dc:creator><slash:comments>2</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/217589.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=217589</wfw:commentRss><description>&lt;img src="http://11249.2.sihosting.net/Blog/Images/MVCHtmlHelpers.jpg" alt="MVC Html Helpers" style="margin-bottom:5px;margin-top:5px;margin-right:10px;float:left;"&gt;Helferlein können das Leben ganz schön vereinfachen.&lt;br&gt;&lt;br&gt;Das zeigt sich an diversen Beispielen. Wer hat sich noch nicht eine LabeledTextbox oder ein Control in der Art in klassischen Webforms fabriziert, um sich damit eine Menge Tipparbeit zu sparen?&lt;br&gt;&lt;br&gt;Natürlich geht das auch mit &lt;a href="http://www.asp.net/mvc" target="_blank" title="ASP.NET MVC"&gt;MVC&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Ist es nicht cool, wie Telerik und Co. Das machen?&lt;br&gt;&lt;br&gt;&lt;b&gt;&amp;lt;%= Html.MeineSuperAnwendung().MeinMegaControl().DasAllesKann %&amp;gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;Korrekt! Die eierlegende Wollmilchsau unter den eigenen Controls kann das!&lt;br&gt;&lt;br&gt;&lt;b&gt;Wie das geht?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Ganz einfach: Man nehme eine statische Klasse, die das Control instanziert und zurückgibt.&lt;br&gt;&lt;br&gt;Die &lt;a href="http://en.wikipedia.org/wiki/Fluent_interface" target="_blank" title="Fluent interface"&gt;fluent Schreibweise&lt;/a&gt; ist nichts anderes als eine Methode, die das eigene Objekt zurückgibt.&lt;br&gt;&lt;br&gt;Gegeben eine Klasse Button mit folgender Methode:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; Button IchBinEinFluentDing()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;var button &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; Button().IchBinEinFluentDing().IchBinEinFluentDing()&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Klingt nicht nur simple, ist es auch. Gut, nicht ganz, ein Zwischenschritt wird noch benötigt.&lt;br&gt;&lt;br&gt;Die „Container“ Klasse, die die einzelnen Controls zurückgeben kann. Somit wird nicht auf ein Controltyp beschränkt.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; MyHtmlHelpers&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; HtmlHelper _helper;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; MyHtmlHelpers(HtmlHelper helper)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._helper &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; helper;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; CoolButton CoolButton(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; text)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; CoolButton(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._helper, text);&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Wie bereits verraten, die &lt;b&gt;statische Klasse&lt;/b&gt; (Extension), die die Helpers zurück gibt:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;static&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; MyProductExtension&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;static&lt;/span&gt; MyHtmlHelpers MyProduct(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt; HtmlHelper helper)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; MyHtmlHelpers (helper);&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Lange Rede – kurzer Sinn:&lt;br&gt;&lt;br&gt;&lt;b&gt;Html.MyProduct().CoolButton()&lt;/b&gt;&lt;br&gt;&lt;br&gt;Gut, die Schreibweise ist klar, aber das Ganze macht noch keinen Sinn. Der Button muss her!&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; CoolButton&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; IDictionary&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt; _attributes;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; _text;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; HtmlHelper _helper;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; CoolButton(HtmlHelper helper, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; text)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._text &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; text;&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._helper &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; helper;&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._attributes &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt;();&lt;br /&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Ein Text für den Button, das html helper objekt - das später benötigt wird und das Kernstück – die Attribute. Das ganze Ding soll ja letztendlich flexibel sein.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; CoolButton SetAttribute(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; key, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; value)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (!&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._attributes.ContainsKey(key))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._attributes.Add(key, value.ToString());&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Natürlich soll der Button auch navigieren können – Angaben á la MVC + Id:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; CoolButton RouteTo(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; controller, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; action, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; itemId)&lt;br /&gt;{&lt;br /&gt;    var urlHelper &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; UrlHelper(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._helper.ViewContext.RequestContext);&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; url;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (itemId == &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        url &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; urlHelper.Action(action, controller);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        url &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; urlHelper.Action(action, controller, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; { id &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; itemId });&lt;br /&gt;    }&lt;br /&gt;            &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._attributes.Add(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"onclick"&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"window.location='{0}';return false;"&lt;/span&gt;, url));&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Natürlich macht es nicht immer Sinn ein onclick event zu haben, aber es soll ja letztendlich der Sinn der Attribute erklärt werden.&lt;br&gt;&lt;br&gt;Es können weitere solcher Methoden folgen, bspw. Um die css Klasse oder ein client event zu setzen.&lt;br&gt;&lt;br&gt;Last but not least – &lt;b&gt;Rendern&lt;/b&gt;. &lt;br&gt;Aufgrund des Attribute Dictionarys recht einfach: Stück für Stück zusammensetzen.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; Render()&lt;br /&gt;{&lt;br /&gt;    var attributeBuilder &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;foreach&lt;/span&gt; (KeyValuePair&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt; attribute &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;in&lt;/span&gt; _attributes)&lt;br /&gt;    {&lt;br /&gt;        attributeBuilder.AppendFormat(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;" {0}=\"{1}\""&lt;/span&gt;, attribute.Key, attribute.Value);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"&amp;lt;button {0}&amp;gt;{1}&amp;lt;/button&amp;gt;"&lt;/span&gt;, attributeBuilder.ToString(), &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;._text);&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Für jedes KeyValuePair des Dictionarys wird folgendes Konstrukt erstellt: Key=“Value“, onclick=“TuWas();“&lt;br&gt;&lt;br&gt;Das Ganze sieht dann in etwa so aus:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;%= Html.MyProduct().CoolButton(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Edit"&lt;/span&gt;)&lt;br /&gt;                        .SetAttribute(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"class"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"editButton"&lt;/span&gt;)&lt;br /&gt;                        .RouteTo(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"User"&lt;/span&gt;, &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Edit"&lt;/span&gt;, Model.User.Id)&lt;br /&gt;                        .Render() %&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Man kann darüber streiten, ob eine Fluent Schreibweise wie eben beschrieben Sinn macht, ob sie sauber ist, oder ob sie nur ein Workaround ist, bis etwas Neues Erfunden wird?&lt;br&gt;&lt;br&gt;In ASP.NET Webforms Zeiten hab ich mir teilweise meine Controls per Render Überschreibung mit dem Writer selbst erzeugt (Fragt jetzt nicht warum – ich wollte einfach die Kontrolle über das Ding haben ;-) ). Das ist ja ebenfalls suboptimal und im Gegensatz dazu sind HTML Helpers ein Genuss :-)&lt;br&gt;&lt;br&gt;Anbei gibt’s wie immer ein etwas ausführlicheres Beispiel.&lt;br&gt;&lt;br&gt;
&lt;div class="DownloadBox"&gt;
&lt;a href="http://aspnetzone.de/files/folders/217590/download.aspx" title="ASP.NET MVC Html Helpers sample"&gt;ASP.NET MVC Html Helpers sample&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=217589" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Mvc/default.aspx">Mvc</category></item><item><title>Abstraktion</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/03/01/Software-Abstraktion.aspx</link><pubDate>Mon, 01 Mar 2010 08:37:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:216240</guid><dc:creator>Roberto</dc:creator><slash:comments>1</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/216240.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=216240</wfw:commentRss><description>&lt;img alt="Abstraktion" src="http://11249.2.sihosting.net/Blog/Images/Abstraktion.jpg" style="margin-right:5px;margin-bottom:5px;margin-top:5px;float:left;"&gt;Am 13. Oktober 2008 haben &lt;a href="http://www.peterbucher.ch/" target="_blank" title="Peter Bucher"&gt;Peter Bucher&lt;/a&gt; und &lt;a target="_blank" title="Golo Roden" href="http://www.goloroden.de/"&gt;Golo Roden&lt;/a&gt; unter dem Titel "Noch Fragen, Bucher? Ja, Roden!" angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen. Heute, am 1. März 2010, ist es nun wieder so weit, und das Thema für diesen Monat lautet:&lt;br&gt;&lt;br&gt;&lt;b&gt;Abstraktion&lt;/b&gt;&lt;br&gt;&lt;br&gt;Die beiden haben mich netterweise gefragt ob ich dieses Mal als "Gast-Mitstreiter" dabei bin, und so haben wir drei uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. &lt;a target="_blank" href="http://www.aspnetzone.de/blogs/peterbucher/" title="Peter Buchers Blog"&gt;Peters&lt;/a&gt; und &lt;a target="_blank" href="http://www.des-eisbaeren-blog.de/" title="Golo Roden Blog"&gt;Golos&lt;/a&gt; Kommentare finden sich zeitgleich in ihren Blogs, folgend nun meine Meinung zu diesem Thema:&lt;br&gt;&lt;br&gt;Das Prinzip der &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Abstraction_%28computer_science%29" title="Abstraktion"&gt;Abstraktion&lt;/a&gt; ist im Grunde nichts anderes als das Weglassen von Einzelheiten und das Überführen auf etwas Allgemeines oder Einfacheres (Generalisieren). So jedenfalls die Definition.&lt;br&gt;&lt;br&gt;Auch in der &lt;a target="_blank" href="http://de.wikipedia.org/wiki/Objektorientierte_Programmierung"&gt;Objektorientierten Programmierung&lt;/a&gt; findet dieses Prinzip Einsatz. Durch die Abstraktion von Aktionen oder Eigenschaften wird versucht, Redundanzen zu vermeiden.&lt;br&gt;&lt;br&gt;Außerdem vereinfacht uns Abstraktion das Leben durch Verringerung der Komplexität.&lt;br&gt;&lt;br&gt;Beispiele für Abstraktion&lt;br&gt;&lt;ul&gt;&lt;li&gt;Auslagerung von Codezeilen in eine benannte (zentralere) Funktion&lt;/li&gt;&lt;li&gt;Einführung von generischen Klassen&lt;/li&gt;&lt;li&gt;Unterklassen&lt;/li&gt;&lt;li&gt;Interfaces&lt;/li&gt;&lt;li&gt;Vererbung&lt;/li&gt;&lt;li&gt;Modularisierung der Anwendung&lt;/li&gt;&lt;li&gt;…&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;Grundsätzlich wird in der Software Programmierung zwischen zwei Arten der Abstraktion unterschieden:&lt;br&gt;&lt;br&gt;&lt;b&gt;Funktionale Abstraktion (Control abstraction)&lt;/b&gt;&lt;br&gt;&lt;br&gt;In der funktionalen Abstraktion wird eine Anwendung an Hand von funktionalen Merkmalen in individuelle Komponenten aufgebrochen, wobei die einzelnen Komponenten jeweils eine logisch-semantisch zusammengehörige Einheit bilden.&lt;br&gt;&lt;br&gt;Bspw. so eine drei Schichten Architektur&lt;br&gt;&lt;br&gt;&lt;img alt="Funktionale Abstraktion" src="http://11249.2.sihosting.net/Blog/Images/FunktionaleAbstraktion.jpg"&gt;&lt;br&gt;&lt;br&gt;Jede der einzelnen Schichten erfüllt eine bestimmte Funktion und auf diese sollte sie sich beschränken. Wie das intern abgehandelt wird, interessiert einzig und allein diese selbst.&lt;br&gt;&lt;br&gt;Die Grafik zeigt die Präsentationsschicht (bspw. Website), die auf die Business Logik zugreift um bspw. eine Auflistung aller Kunden zu bekommen. Wenn ein Entwickler das grafische UI programmiert, sollte er die Möglichkeiten der Business Schicht verstehen, aber nicht deren internen Aufbau.&lt;br&gt;&lt;br&gt;Die Business Schicht wiederum dient als Schnittstelle zur Datenschicht. Sie beinhaltet lediglich Services, die die gewünschten Daten aus der Datenschicht holen und zur Verfügung stellen. In welcher Art und Weiße die Daten geholt werden, ist, wie weiter oben bereits erwähnt, der Präsentation egal.&lt;br&gt;&lt;br&gt;Woher die Daten kommen, ob und welche Datenbank verwendet wird, welcher OR Mapper im Einsatz ist, … interessiert nur die Datenschicht.&lt;br&gt;Alle Schichten sind voneinander unabhängig. Dies senkt die Komplexität der Anwendung und vereinfacht das ändern zentraler Funktionalitäten.&lt;br&gt;&lt;br&gt;Wenn gesagt wird: Belästige mich nicht mit Details – wird versucht zu abstrahieren.&lt;br&gt;&lt;br&gt;&lt;b&gt;Datenabsraktion (Data abstraction)&lt;/b&gt;&lt;br&gt;&lt;br&gt;Das klassische Beispiel hierfür sind mehrere Entitäten&lt;br&gt;&lt;br&gt;&lt;img alt="Daten Abstraktion" src="http://11249.2.sihosting.net/Blog/Images/DataAbstraction.jpg"&gt;&lt;br&gt;&lt;br&gt;Jede dieser einzelnen Entitäten beinhaltet Standartfelder wie Id, Erstell- und Änderungsdatum.&lt;br&gt;&lt;br&gt;Es wäre suboptimal diese getrennt in den einzelnen Entitäten einzufügen. Viel besser ist eine etwas mehr zentralere Klasse (Entity), die bestimmte, für alle gemeinsame Eigenschaften beinhaltet um&amp;nbsp; somit ein wenig Redundanz zu vermeiden.&lt;br&gt;&lt;br&gt;&lt;i&gt;In C# werden mit dem „abstract“- Modifizier(in vb.Net MustInherit) zentrale Klassen erstellt, sprich sie dienen nur als Basisklassen und müssen implementiert werden.&lt;/i&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Wie viel Abstraktion ist zu viel Abstraktion?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Je detailreicher die Strukturen bzw. Modelle werden (je weniger Abstraktion sie verwenden), desto besser ist die Akzeptanz. Je weniger Details die einzelnen Modelle der Anwendung beinhalten (je mehr Abstraktion sie verwenden), desto größer ist die Flexibilität und Wiederverwendbarkeit.&lt;br&gt;&lt;br&gt;Das Abstraktionsprinzip besagt, Abstraktion sollte dann verwendet werden, wenn damit Redundanzen (üblich im Code) vermieden werden können.&lt;br&gt;Die Softwareentwicklung strebt ja bekanntlich nach immer höheren Stufen der Abstraktion. Aber mehr ist nicht immer besser. Wer ganze Stockwerke aus Abstraktionsebenen baut, vergisst, dass diese nicht nur von Maschinen betreten werden.&lt;br&gt;&lt;br&gt;Mehrere Abstraktionen bedeuten meist einen höheren Aufwand und sind außerdem schwieriger zu verstehen.&lt;br&gt;&lt;br&gt;Zu Beginn eines Projektes sind Abstraktionen teilweise schnell implementiert, allerdings müssen sich diese erst bewähren: &lt;br&gt;Wird in einem späteren Projektzyklus klar, dass eine Abstraktion nicht korrekt ist, können sehr hohe Änderungskosten anfallen – ein Alptraum für jeden Entwickler.&lt;br&gt;&lt;br&gt;Um ein neues Problem zu lösen gerät mancher Entwickler in die Versuchung eine zusätzliche Abstraktionsschicht einzubauen. Abstraktionen an sich sind nicht das Problem, sondern vielmehr die (zu komplexe oder falsche) Denkweise des Entwicklers, der sich damit zusätzliche Probleme einfängt.&lt;br&gt;&lt;br&gt;&lt;u&gt;Ein Beispiel dazu:&lt;/u&gt;&lt;br&gt;&lt;br&gt;Zwei Entitäten Kunden und Benutzer sind gegeben. Jetzt fällt einem Entwickler ein, dass beides Personen sind und beide das Feld Name haben. Es ist eine Basisklasse „Person“ gegeben und das „Name“ Feld wird dorthin verschoben.&lt;br&gt;Jetzt kommt ein weiterer Entwickler, der der Meinung ist, dass das Feld „Name“ bei bestimmten Kunden eigentlich die Kundennummer ist und abstrahiert das Feld zu „Kundennummer“.&lt;br&gt;Was zurück bleibt ist eine nicht mehr klare Bedeutung der einzelnen Felder.&lt;br&gt;&lt;br&gt;&lt;b&gt;Mein Fazit&lt;/b&gt;&lt;br&gt;&lt;br&gt;Wie bei so vielem im Leben ist auch hier eine gesunde Mischung gefragt.&lt;br&gt;Abstraktion gehört zu den Urbausteinen der Softwareprogrammierung. Heute wäre es nahezu undenkbar eine Anwendung ohne zu entwickeln.&lt;br&gt;&lt;br&gt;Wie viel Abstraktion verwendet wird, hängt von vielen Faktoren ab. Unter anderem den Anforderungen, der Erfahrung des Teams, Erweiterbarkeit, etc. &lt;br&gt;Wenn bspw. von Anfang an vorgesehen wird, dass ein Kunde ein Verkäufer werden kann, sollte vielleicht auch vorgesehen werden, dass dieser zu einem Mars Mensch mutieren kann.&lt;br&gt;Klar, diese „neverending abstraction“ ist immer eine Frage des Aufwands.&lt;br&gt;&lt;br&gt;Ich kenne die Frage sehr wohl, was man wie in Zukunft machen könnte oder vorsehen sollte. In den meisten Fällen hat sich herausgestellt – Eierlegende Wollmilchsäue sind nur selten die Beste Lösung. Abstraktion ist dafür gedacht, die Komplexität einer Anwendung zu verringern und nicht in den Sternen zu treiben.&lt;br&gt;&lt;br&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=216240" width="1" height="1"&gt;</description><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Abstraktion/default.aspx">Abstraktion</category></item><item><title>DI / IoC Container LightCore Teil 3: Registrierung von Generics</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-generics.aspx</link><pubDate>Sun, 21 Feb 2010 17:18:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:216097</guid><dc:creator>Roberto</dc:creator><slash:comments>2</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/216097.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=216097</wfw:commentRss><description>&lt;img alt="LightCore Generics Registration" src="http://11249.2.sihosting.net/Blog/Images/LightCoreGeneric.gif" style="margin-right:5px;margin-bottom:5px;margin-top:5px;float:left;"&gt;Im dritten Teil der Post Serie wird die bisher angewandte drei Schichten Struktur etwas erweitert, sodass diese durch das hinzufügen von generischen Klassen etwas mehr flexibel wird.&lt;br&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx" title="LightCore - Einführung"&gt;1. LightCore – Einführung&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-xml-module.aspx" title="LightCore - Registrierung über Xml Module"&gt;2. LightCore – Registrierung über Xml Module&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-generics.aspx" title="LightCore - Registrierung von Generics"&gt;3. LightCore – Registrierung von Generics&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;a href="http://msdn.microsoft.com/de-de/library/sz6zd40f.aspx"&gt;Generics&lt;/a&gt; sind nichts anderes als Klassen, bei denen der Nutzer die Datentypen, die der Typ verarbeiten soll, vorgeben kann.&lt;br&gt;&lt;br&gt;Es kann durchaus Sinn machen, bei Projekten die Repositories generisch zu halten, da sich diese immer auf dieselbe Datenquelle beziehen(bspw. bei Verwendung des NHibernate OR-Mappers) und sie sich lediglich von den angeforderten Typen unterscheiden.&lt;br&gt;&lt;br&gt;LightCore bietet &lt;u&gt;zwei Möglichkeiten&lt;/u&gt;, generische Typen zu registrieren.&lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;img src="http://11249.2.sihosting.net/Blog/Images/Lock.png" style="float:left;margin-top:-7px;"&gt;&amp;nbsp; Closed Types&lt;/b&gt;&lt;br&gt;&lt;br&gt;Eine generische Klasse, die schon einen Typparameter hat. &lt;br&gt;IRepository&amp;lt;User&amp;gt; zu Repository&amp;lt;User&amp;gt; registrieren.&lt;br&gt;&lt;br&gt;Die Registrierung und Auflösung sieht in dem Fall so aus:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;builder.Register&amp;lt;IRepository&amp;lt;User&amp;gt;, Repository&amp;lt;User&amp;gt;();&lt;br /&gt;container.Resolve&amp;lt;IRepository&amp;lt;User&amp;gt;&amp;gt;();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Der &lt;u&gt;Nachteil&lt;/u&gt; dieser Variante liegt darin, dass jedes Repository getrennt registriert werden muss (eines für den User, eines für die UserGroup…). Dies wär in dem Fall suboptimal, da sie von den Funktionen her identisch sind.&lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;img src="http://11249.2.sihosting.net/Blog/Images/Open.png" style="float:left;margin-top:-7px;"&gt;&amp;nbsp; Open Types&lt;/b&gt;&lt;br&gt;&lt;br&gt;Eine generische Klasse, die keinen bestimmten Parameter hat.&lt;br&gt;Der Kontrakt, in dem Fall IRepository&amp;lt;&amp;gt; hätte die Implementation Repository&amp;lt;&amp;gt;.&lt;br&gt;&lt;br&gt;Der Vorteil dabei ist die Auflösung (on-the-fly) auf einem beliebigen Typparameter.&lt;br&gt;So wäre IRepository&amp;lt;User&amp;gt; und IRepository&amp;lt;UserGroup&amp;gt;.&lt;br&gt;&lt;br&gt;In dem Fall muss das Repository nur &lt;u&gt;ein einziges Mal&lt;/u&gt; registrieren werden und kann mit beliebigem Typ auflöst werden.&lt;br&gt;&lt;br&gt;Wenn das Projekt ein generisches Repository mit viele verschiedene Typen dazu hat, ist der open type die erste Wahl.&lt;br&gt;&lt;br&gt;Als Beispiel wird wieder eine Solution mit einer klassischen drei Schichten Architektur verwendet.&lt;br&gt;&lt;br&gt;Um das Ganze noch etwas zu vertiefen wird eine vierte Schicht „Core“ hinzugefügt. Diese beinhaltet die zentralen Interfaces wie bspw. IRepository oder IService.&lt;br&gt;&lt;br&gt;&lt;img alt="LightCore Generics Registration Project Tree" src="http://11249.2.sihosting.net/Blog/Images/LightCoreDemoGenerics.jpg"&gt;&lt;br&gt;&lt;br&gt;Das Repository muss wie oben beschrieben nur einmal registriert werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;container.Register(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;typeof&lt;/span&gt;(IRepository&amp;lt;&amp;gt;), &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;typeof&lt;/span&gt;(Repository&amp;lt;&amp;gt;));&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Jetzt könnten alle gewünschten Typen (Im Beispiel user und usergroup) instanziiert werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;container.resolve&amp;lt;IRepository&amp;lt;User&amp;gt;&amp;gt;();&lt;br /&gt;container.resolve&amp;lt;IRepository&amp;lt;UserGroup&amp;gt;&amp;gt;();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Fazit:&lt;/b&gt;&lt;br&gt;&lt;br&gt;Durch die Unterstützung von generischen Klassen ist Lightcore für mich interessant gewordern und ist bereits in einer Anwendung im Einsatz. Es funktioniert bis dato Problemfrei und ohne merkbare Performance Verluste. Es bietet genau das, was ich zur Zeit benötige. Somit bin ich gespannt auf dessen zukünftige Erweiterungen.&lt;br&gt;&lt;br&gt;Anbei wie immer das Beispiel nicht vergessen! :-)&lt;br&gt;&lt;br&gt;
&lt;div class="DownloadBox"&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216101/download.aspx" title="Download LightCore Demo: Einführung"&gt;LightCore Demo: Einführung&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216102/download.aspx" title="Download LightCore Demo: Registrierung über Xml Modul"&gt;LightCore Demo: Registerirung über Xml Module&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216103/download.aspx" title="Download LightCore Demo: Registrierung von Generics"&gt;LightCore Demo: Registrierung von Generics&lt;/a&gt;&lt;br&gt;
&lt;/div&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=216097" width="1" height="1"&gt;</description><enclosure url="http://www.aspnetzone.de/blogs/robertobez/attachment/216097.ashx" length="63987" type="application/zip" /><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/LightCore/default.aspx">LightCore</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/IoC/default.aspx">IoC</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Generics/default.aspx">Generics</category></item><item><title>DI / IoC Container LightCore Teil 2: Registrierung über Xml Modul</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-xml-module.aspx</link><pubDate>Sun, 21 Feb 2010 16:02:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:216096</guid><dc:creator>Roberto</dc:creator><slash:comments>5</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/216096.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=216096</wfw:commentRss><description>&lt;img alt="LightCore Xml Registration module" src="http://11249.2.sihosting.net/Blog/Images/LightCoreXml.gif" style="margin-right:5px;margin-bottom:5px;margin-top:5px;float:left;"&gt;Wie bereits im &lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx"&gt;ersten Teil&lt;/a&gt; erwähnt, wird es einer mehr Schichten Architektur immer wichtiger, Abhängigkeiten zu minimieren. Dabei einen ersten Schritt zu setzen, ist die Implementierung eines IoC Containers. Dieser hilft dabei, den Code in den diversen Projekten unabhängiger zu halten.&lt;br&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx" title="LightCore - Einführung"&gt;1. LightCore – Einführung&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-xml-module.aspx" title="LightCore - Registrierung über Xml Module"&gt;2. LightCore – Registrierung über Xml Module&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-generics.aspx" title="LightCore - Registrierung von Generics"&gt;3. LightCore – Registrierung von Generics&lt;/a&gt;&lt;br&gt;&lt;br&gt;Mich persönlich hat &lt;a href="http://www.aspnetzone.de/blogs/peterbucher/" title="Peter Bucher" target="_blank"&gt;Peter Bucher&lt;/a&gt; mit seinem neusten Projekt &lt;a target="_blank" href="http://lightcore.peterbucher.ch/"&gt;LightCore&lt;/a&gt; darauf aufmerksam gemacht. Anfangs war dies nur als Unit Testing Spielwiese gedacht, hat sich aber zu einem konkurrenzfähigen Micro Kernel entwickelt. Dessen weitere Entwicklung wird in Zukunft per Community gesteuert. Der Source Code wurde veröffentlicht und ist auf jeden Fall einen Blick Wert! (Stichwort: Codequalität)&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;Zurück zum Thema. Viele werden sich denken, was bringt mir das Ganze eigentlich?&lt;br&gt;&lt;ul&gt;&lt;li&gt;Abhängigkeiten verringern und Kontrolle der Abhängigkeiten (Interface / Basisklasse - also Abstraktion) und dadurch auf die Instanziierung (Die sonst auf den konkreten Typen geht), rausziehen.&lt;/li&gt;&lt;li&gt;Dadurch bessere Testbarkeit und Aufbrechung der Anwendung in mehr Einzelteile, wodurch die Komplexität sinkt.&lt;/li&gt;&lt;li&gt;Außerdem globale Konfigurierbarkeit, was genutzt werden soll um Änderungen an vielen, unnötigen Stellen vorzunehmen.&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;Nun wird anhand eines Beispiels wird gezeigt, wie man Lightcore in einer drei Schichten Architektur einsetzen bzw. integrieren kann.&lt;br&gt;Gleichzeitig wird die Registrierung über das integrierte Xml Modul erklärt&lt;br&gt;&lt;br&gt;Was eine drei Schichten Architektur (Tier 3 layer) ist, erklärt &lt;a target="_blank" href="http://code-inside.de/blog/"&gt;Robert Mühsig&lt;/a&gt; in &lt;a target="_blank" href="http://code-inside.de/blog/2008/07/09/howto-3-tier-3-schichten-architektur/"&gt;seinem Post&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Das folgende Beispiel wird eine Solution mit mehreren Projekten beinhalten, die eine Anwendung mit mehreren Schichten darstellt.&lt;br&gt;&lt;br&gt;Die Klassische Struktur sieht wie folgt aus:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Data Access Layer&lt;/li&gt;&lt;li&gt;Business Layer&lt;/li&gt;&lt;li&gt;Presentation Layer&lt;/li&gt;&lt;/ul&gt;Folglich könnten die Projekte so benannt werden:&lt;br&gt;&lt;br&gt;&lt;b&gt;Data&lt;/b&gt;: beinhaltet eine &lt;u&gt;User&lt;/u&gt;&lt;b&gt; &lt;/b&gt;Klasse sowie das dazugehörige &lt;u&gt;Repository&lt;/u&gt;.&lt;br&gt;&lt;br&gt;&lt;b&gt;Service&lt;/b&gt;: beinhaltet einen &lt;u&gt;User Service&lt;/u&gt; mit dem
 Repository als Member, der per Constructor Injection injiziert wird.&lt;br&gt;&lt;br&gt;&lt;b&gt;Web&lt;/b&gt;:
 Die Präsentation&lt;br&gt;&lt;br&gt;&lt;img alt="LightCore Xml Registration Project Tree" src="http://11249.2.sihosting.net/Blog/Images/LightCoreDemoPartTwo.jpg"&gt;&lt;br&gt;&lt;br&gt;Im &lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx"&gt;ersten Teil des Posts&lt;/a&gt; wurde gezeigt, wie man Kontrakte einfach per code (global.asax) registrieren kann. Der erste Schritt wird sein, die Registrierung in die &lt;b&gt;Web/App.config&lt;/b&gt; bzw. einer eigenen Konfigurationsdatei auszulagern.&lt;br&gt;&lt;br&gt;Wer achte gibt sieht, dass beim &lt;a href="http://lightcore.peterbucher.ch/download.aspx"&gt;heruntergeladenen Paket&lt;/a&gt; unter Anderem eine XML Schema Datei (LightCore.xsd), sowie eine Beispiel Konfiguration (SampleConfiguration.xml) dabei ist.&lt;br&gt;Nun die Datei LightCore.xsd dem aktuellen Web Projekt hinzufügen.&lt;br&gt;&lt;br&gt;Es kann eine eigene Konfigurationsdatei erstellt werden, oder aber einfach den entsprechenden Block in die Web/App.config hinzufügen.&lt;br&gt;Wer sich für letzteres entscheidet, den Block, der innerhalb der SampleConfiguration.xml zu finden ist, einfach in den &amp;lt;configuration&amp;gt; Abschnitt packen.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;configuration&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    …&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;LightCoreConfiguration&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;xmlns&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="clr-namespace:LightCore.Configuration;assembly=LightCore.Configuration"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Als erstes kommt die Einstellung über den genutzten Lebenszyklus, also ob Singleton, Transient oder HttpRequest.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;LightCoreConfiguration.TypeAliases&amp;gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;TypeAlias&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Alias&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="HttpRequest"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Type&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="LightCore.Integration.Web.HttpRequestLifecycle, LightCore.Integration.Web"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/LightCoreConfiguration.TypeAliases&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Jetzt die eigentliche &lt;b&gt;Registrierung&lt;/b&gt;.&lt;br&gt;Einfache Registrierungen ohne Gruppen kommen in die LightCoreConfiguration.Registrations Sektion:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;LightCoreConfiguration.Registrations&amp;gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Registration&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyRepository"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ContractType&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyAssembly.IUserRepository, MyAssembly"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ImplementationType&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyAssembly.Repository, MyAssembly"&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/LightCoreConfiguration.Registrations&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Sollte selbsterklärend sein, Namensangabe um den registrierten Kontrakt wiederzufinden, der Kontrakttyp sowie die Klasse mit jeweiliger Angabe des Assembly Namens. Optionale Argumente für den Konstruktor können über Arguments=“Value1, Value2“ mitgegeben werden. Wenn die LightCore.xsd im Projekt eingebunden wurde, sollte auch IntelliSense zur Verfügung stehen!&lt;br&gt;&lt;br&gt;Ist eine gruppierte Registrierung gewollt, um bspw. die Repositories zu sammeln, gibt es auch hierfür eine Sektion:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;LightCoreConfiguration.RegistrationGroups&amp;gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;RegistrationGroup&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="Repositories"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &amp;lt;RegistrationGroup.Registrations&amp;gt;&lt;br /&gt;            &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Registration&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyRepository"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ContractType&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyAssembly.IUserRepository, MyAssembly"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ImplementationType&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="MyAssembly.Repository, MyAssembly"&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &amp;lt;/RegistrationGroup.Registrations&amp;gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;RegistrationGroup&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/LightCoreConfiguration.RegistrationGroups&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Jetzt wo die Registrierung der Repositories gemacht wurde, muss der Container erstellt und das &lt;b&gt;Konfigurationsmodul&lt;/b&gt; zugewiesen werden.&lt;br&gt;&lt;br&gt;Dies sollte in der Globalen Anwendungsdatei (global.asax) in der Application_Start methode gemacht werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;protected&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; Application_Start(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    var builder &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; ContainerBuilder();&lt;br /&gt;    var module &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; XamlRegistrationModule();&lt;br /&gt;    builder.RegisterModule(module);&lt;br /&gt;    _container &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; builder.Build();&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Wenn gewollt, kann die Konfigurationsdatei im Konstruktor des XamlRegistrationModules angegeben werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;var module &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; XamlRegistrationModule(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"~/MyConfiguration.xml"&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Die Objekte können wie gehabt mit resolve aufgelöst werden&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;var myRepository &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; _container.Resolve&amp;lt;IRepository&amp;gt;(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"MyRepository"&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Fazit: Welche Variante ist nun besser?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Registrierung per Code hat den Vorteil, dass weniger Fehler auftreten können.&lt;br&gt;Da es kompiliert werden muss, wird überprüft ob der Kontrakt implementiert ist oder nicht.&lt;br&gt;&lt;br&gt;Somit ist es intuitiver und Refactoring-sicher. Wenn eine Klasse umbenannt wird – wird sie auch hier übernommen.&lt;br&gt;&lt;br&gt;Allerdings hat die Registrierung per Code einen riesen Haken: Es ist eine harte – also feste – Referenz.&lt;br&gt;Wenn eine Assembly, aus welchem Grund auch immer, ausgetauscht wird, muss das komplette Projekt neu kompiliert werden.&lt;br&gt;&lt;br&gt;Sollte das bei einer Produktivumgebung der Fall sein, kann das ein großer Nachteil sein. Dadurch muss ein komplettes Deployment gemacht werden.&lt;br&gt;&lt;br&gt;Was also „besser“ ist, hängt vom Anwendungsfall ab.&lt;br&gt;Ich persönlich finde die „per Code“ Variante bei nicht allzu vielen Klassen übersichtlich.&lt;br&gt;Eine gut durchdachte Anwendungsstruktur von Anfang an ist natürlich Voraussetzung :-) &lt;br&gt;&lt;br&gt;Anbei gibt’s wie immer das oben gezeigte Beispiel als Download.&lt;br&gt;&lt;br&gt;
&lt;div class="DownloadBox"&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216101/download.aspx" title="Download LightCore Demo: Einführung"&gt;LightCore Demo: Einführung&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216102/download.aspx" title="Download LightCore Demo: Registrierung über Xml Modul"&gt;LightCore Demo: Registerirung über Xml Module&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216103/download.aspx" title="Download LightCore Demo: Registrierung von Generics"&gt;LightCore Demo: Registrierung von Generics&lt;/a&gt;&lt;br&gt;
&lt;/div&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=216096" width="1" height="1"&gt;</description><enclosure url="http://www.aspnetzone.de/blogs/robertobez/attachment/216096.ashx" length="82873" type="application/zip" /><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/LightCore/default.aspx">LightCore</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/IoC/default.aspx">IoC</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Xml/default.aspx">Xml</category></item><item><title>DI / IoC Container LightCore Teil 1: Einführung</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx</link><pubDate>Sat, 16 Jan 2010 16:03:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:215449</guid><dc:creator>Roberto</dc:creator><slash:comments>4</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/215449.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=215449</wfw:commentRss><description>&lt;img src="http://11249.2.sihosting.net/Blog/Images/LightCore1.gif" style="margin-right:5px;margin-bottom:5px;margin-top:5px;float:left;" alt="LightCore DI/Ioc Container"&gt;In einer mehrschichtigen Architektur (Oft verwendet die&lt;a title="How to tier 3 Schichten Architektur" target="_blank" href="http://code-inside.de/blog/2008/07/09/howto-3-tier-3-schichten-architektur/"&gt; 3-Tier/3 Schichten Architektur&lt;/a&gt;) wird es immer wichtiger Abhängigkeiten zu minimieren. &lt;br&gt;In großen Projekten kann es leicht vorkommen, dass ein Chaos von Abhängigkeiten entsteht. &lt;br&gt;Nicht alle Abhängigkeiten lassen sich vermeiden, aber viele sind unnötig. Vor allem falsche können die Entwicklung eines Projektes aufhalten.&lt;br&gt;&lt;br&gt;In den diversen Schichten(Data, Web, …)&amp;nbsp; den Code unabhängig voneinander zu halten, hilft dem gesamten Prozess ungemein. &lt;br&gt;Eine Technik, um die Kopplung so gering wie möglich zu halten ist ein Inversion of Control Container. (IoC Container) &lt;br&gt;&lt;br&gt;Mehr dazu in einem Artikel von Martin Fowler: &lt;a title="Inversion of control" target="_blank" href="http://martinfowler.com/articles/injection.html"&gt;Inversion of Control Containers and the Dependency Injection pattern&lt;/a&gt;&lt;br&gt;&lt;br&gt;Genauer eingegangen wird auf den frischen IoC Container „&lt;a title="LightCore" target="_blank" href="http://lightcore.peterbucher.ch/"&gt;LightCore&lt;/a&gt;“ von &lt;a target="_blank" href="http://www.peterbucher.ch"&gt;Peter Bucher&lt;/a&gt;. &lt;br&gt;Wie das Wort schon sagt, ist dieser lightweight und kann mit Performance und Einfachheit punkten, muss aber nicht in Sachen Features einpacken. &lt;br&gt;&lt;br&gt;Eine Feature List von Lightcore finder sich &lt;a target="_blank" href="http://lightcore.peterbucher.ch/features.aspx"&gt;hier&lt;/a&gt;.&lt;br&gt;Weiter Argumente die für LightCore sprechen finden sich in einem &lt;a target="_blank" title="LightCore im Vergleich" href="http://www.des-eisbaeren-blog.de/post/2010/01/01/LightCore.aspx"&gt;Blogeintrag&lt;/a&gt; von &lt;a title="Golo Roden" target="_blank" href="http://www.des-eisbaeren-blog.de/"&gt;Golo Roden&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/01/16/inversion-of-control-di-ioc-container-lightcore.aspx" title="LightCore - Einführung"&gt;1. LightCore – Einführung&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-xml-module.aspx" title="LightCore - Registrierung über Xml Module"&gt;2. LightCore – Registrierung über Xml Module&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.aspnetzone.de/blogs/robertobez/archive/2010/02/21/ioc-container-lightcore-registration-generics.aspx" title="LightCore - Registrierung von Generics"&gt;3. LightCore – Registrierung von Generics&lt;/a&gt;&lt;br&gt;&lt;br&gt;Der Erste Teil der Einführung wird ein einfaches Beispiel mit LightCore behandeln. &lt;br&gt;Um etwas tiefer in die Materie einzusteigen wird im zweiten Teil gezeigt, wie man mit LightCore die Unabhängigkeit einer 3-Schichten Architektur verbessern kann, wie man mit dem integrierten Registrations-Modul über Xml bzw. XAML arbeitet und wie man Generics registrieren kann.&lt;br&gt;&lt;br&gt;&lt;b&gt;Einbinden von Lightcore&lt;/b&gt;&lt;br&gt;&lt;br&gt;Wer auf die Entwicklungsversion zugreifen will, muss sich diese mit &lt;a title="Subversion SVN" href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; laden.&lt;br&gt;Diese wurde vor allem laut den Prinzipien von CCD (&lt;a title="Clean code developers" target="_blank" href="http://www.clean-code-developer.de/"&gt;Clean code development&lt;/a&gt;) und mit einer kompletten Unit Test Abdeckung entwickelt – somit auf jeden Fall einen Blick Wert!&lt;br&gt;&lt;br&gt;Für das folgende Beispiel reichen die DLLs, die es ebenfalls &lt;a title="Download lightcore" target="_blank" href="http://lightcore.peterbucher.ch/download.aspx"&gt;hier zum Download&lt;/a&gt; gibt.&lt;br&gt;&lt;br&gt;&lt;img src="http://11249.2.sihosting.net/Blog/Images/LightCore2.jpg"&gt;&lt;br&gt;&lt;br&gt;Als Erstes müssen die gewünschten Kontrakte (Schnittstellen) registriert werden. Dies kann über zwei Varianten erfolgen:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Registrierung über Code&lt;/li&gt;&lt;li&gt;Registrierung über eine XML Konfigurations- Datei&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;Wenn die Registrierung codeseitig gewünscht ist, sollte dies in der Globalen Anwendungsdatei (Global.asax) erfolgen&lt;br&gt;&lt;br&gt;Der Container wird als static member deklariert&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;static&lt;/span&gt; IContainer _container;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;In der Methode Application_Start wird der IoC Container initialisiert.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;protected&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; Application_Start(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    var builder &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; ContainerBuilder();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Es gibt mehrere, optionale Features, die bei der Registrierung angegeben werden können. Für das Beispiel wird ein Logger registriert.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Einfache Registrierung&lt;/span&gt;&lt;br /&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;();&lt;br /&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Angabe eines Namen, um eine klare Trennung zu behalten&lt;/span&gt;&lt;br /&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;().WithName(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"MyLogger"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Angabe einer Gruppe, um bestimmte Kontrakte zu sammeln&lt;/span&gt;&lt;br /&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;().WithGroup(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"MyGroup"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Angabe von Argumenten für den Konstruktoraufruf&lt;/span&gt;&lt;br /&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;().WithArguments(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Test Argument"&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Gemischte Angabe&lt;/span&gt;&lt;br /&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;().WithName(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"MyLogger"&lt;/span&gt;).WithArguments(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Test Argument"&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Wenn alles registriert ist, den Container noch erstellen:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;_container &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; builder.Build();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Die Registrierten Kontrakte können manuell über resolve aufgelöst werden&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// Einfach&lt;/span&gt;&lt;br /&gt;var myLogger &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; _container.Resolve&amp;lt;ILogger&amp;gt;();&lt;br /&gt;&lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;//Mit Namen&lt;/span&gt;&lt;br /&gt;var myLogger &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; _container.Resolve&amp;lt;ILogger&amp;gt;(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"MyLogger"&lt;/span&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Lifecycle&lt;/b&gt;&lt;br&gt;&lt;br&gt;Der Lebenszyklus besagt, ob bei jedem Anfordern einer Instanz über &amp;lt;Container&amp;gt;.Resolve&amp;lt;Icontract&amp;gt;() ein neues Objekt erstellt wird (Identisch zum new-Operator), oder das Objekt wiederverwendet werden kann.&lt;br&gt;&lt;br&gt;Für die Wiederverwendung von Instanzen werden Folgende Lebenszyklen unterstützt, wobei auch weitere Lebeszyklen geschrieben werden können:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Transient&lt;/li&gt;&lt;li&gt;Singleton&lt;/li&gt;&lt;li&gt;ThreadSingleton&lt;/li&gt;&lt;li&gt;HttpRequest&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;Als Standard wird der transient Lebenszyklus verwendet. Dies besagt, dass bei jedem Aufruf eine neue Instanz der Klasse erstellt wird. Singleton würde bedeuten, dass eine einzige Instanz pro Anwendung erzeugt wird.&lt;br&gt;&lt;br&gt;Der Lebenszyklus wird einmal pro Kernel wie folgt gesetzt:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;builder.DefaultControlledBy&amp;lt;TransientLifecycle&amp;gt;();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Klarer weiße kann man den Lebenszyklus auch pro Registration angeben:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;builder.Register&amp;lt;ILogger, Logger&amp;gt;().ControlledBy&amp;lt;SingletonLifecycle&amp;gt;();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Die Lebenszyklen können ohne Probleme beliebig erweitert werden.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Das Ergebnis&lt;/b&gt;&lt;br&gt;&lt;br&gt;Angenommen wir haben den Logger registriert und möchten nun die Instanz in einer normalen Page Klasse&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; partial &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; _Default : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; ILogger Logger&lt;br /&gt;    { &lt;br /&gt;        get; &lt;br /&gt;        set;&lt;br /&gt;    }&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;In der Page Load wird der logger nun benötigt:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;protected&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; Page_Load(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    ILogger logger &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;this&lt;/span&gt;.Logger;&lt;br /&gt;    logger.log(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Page Loaded!"&lt;/span&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Und wie von Magie haben wir eine Instanz der Klasse ohne direkte Erstellung auf der aktuellen Seite.&lt;br&gt;&lt;br&gt;Was ist passiert?&lt;br&gt;Ein http Modul in Lightcore macht automatisch ein resolve auf die Eigenschaften, die registriert sind. Somit entfällt die manuelle Auflösung und man ist komplett vom Dependency Injection Container unabhängig.&lt;br&gt;&lt;br&gt;Damit das auch klappt, muss das Modul in der Web config im Abschnitt &amp;lt;httpModules&amp;gt; hinzugefügt werden:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;httpModules&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    ...&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;add&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;name&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="LightCoreDependencyInjectionModule"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;type&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="LightCore.Integration.Web.DependencyInjectionModule, LightCore.Integration.Web, Version=1.0.0.0, Culture=neutral"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;httpModules&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Mit ein bisschen Kreativität kann diese Vorgehensweise in allen möglichen Stellen eingesetzt werden – und schon ist man ein klein wenig Unabhängiger!&lt;br&gt;&lt;br&gt;Der zweite Teil des Posts wird mit folgenden Themen in Kürze folgen: Registration über Web/App Config oder eigene Konfigurationsdatei, Einsatz in einer 3 Schichten Architektur und Registrierung von Generics!&lt;br&gt;&lt;br&gt;Anbei gibt’s wie immer das oben angeführte Beispiel!&lt;br&gt;&lt;br&gt;
&lt;div class="DownloadBox"&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216101/download.aspx" title="Download LightCore Demo: Einführung"&gt;LightCore Demo: Einführung&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216102/download.aspx" title="Download LightCore Demo: Registrierung über Xml Modul"&gt;LightCore Demo: Registerirung über Xml Module&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.aspnetzone.de/files/folders/216103/download.aspx" title="Download LightCore Demo: Registrierung von Generics"&gt;LightCore Demo: Registrierung von Generics&lt;/a&gt;&lt;br&gt;
&lt;/div&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=215449" width="1" height="1"&gt;</description><enclosure url="http://www.aspnetzone.de/blogs/robertobez/attachment/215449.ashx" length="48217" type="application/zip" /><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/LightCore/default.aspx">LightCore</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/IoC/default.aspx">IoC</category></item><item><title>Dynamic Objects in C# 4.0</title><link>http://www.aspnetzone.de/blogs/robertobez/archive/2009/11/24/DLR-AspNet-Dynamic-Objects-csharp-4.aspx</link><pubDate>Tue, 24 Nov 2009 00:00:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:214739</guid><dc:creator>Roberto</dc:creator><slash:comments>1</slash:comments><comments>http://www.aspnetzone.de/blogs/robertobez/comments/214739.aspx</comments><wfw:commentRss>http://www.aspnetzone.de/blogs/robertobez/commentrss.aspx?PostID=214739</wfw:commentRss><description>Eine neues Feature in C# 4 ist die „Dynamic Language Runtime“ (DLR). Mit dem „&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/dd264741%28VS.100%29.aspx"&gt;dynamic&lt;/a&gt;“ Schlüsselwort ist es möglich zur Laufzeit Properties und Methoden an Objekten zu binden. Dabei gibt es allerdings keinerlei Überprüfung ob diese auch existieren – dafür erhöht sich die Flexibilität der Anwendung.&lt;br&gt;Eigene Klassen können durch die Implementierung des &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject%28VS.100%29.aspx"&gt;DynamicObject &lt;/a&gt;und durch die Überschreibung der gewünschten Methoden erstellt werden.&lt;br&gt;&lt;br&gt;&lt;b&gt;Ein praktisches Beispiel dazu:&lt;/b&gt;&lt;br&gt;Wer kennt das Problem nicht, es gibt eine Javascript Komponente die im Header der Seite einiger Einstellungen bedarf.&amp;nbsp; Diese möchte man aber nicht per Javascript, sondern per Asp.Net setzen. Ist ja kein Problem, aber jede einzelne Property Serverseitig abzubilden kostet viel Zeit, insbesondere wenn die Komponente ständig weiterentwickelt wird.&lt;br&gt;&lt;br&gt;Das Ausgabe sollte in JavaScript etwa so aussehen:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;var&lt;/span&gt; myObject &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; new JavaScriptComponent();&lt;br /&gt;myObject.width &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; 400;&lt;br /&gt;myObject.show &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; false;&lt;br /&gt;…&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Dynamic to the rescue!&lt;/b&gt;&lt;br&gt;Wie oben beschreiben ist es möglich an dynamischen Objekten beliebige Properties und Methoden zu binden.&lt;br&gt;Dafür einfach eine Klasse ClientScriptCreator die von &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject%28VS.100%29.aspx"&gt;DynamicObject &lt;/a&gt;ableitet.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; ClientScriptCreator : DynamicObject&lt;/span&gt;&lt;/code&gt; &lt;br&gt;&lt;br&gt;Um die dynamischen Properties zu speichern wird ein &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/xfhwa508.aspx"&gt;Dictionary &lt;/a&gt;verwendet&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Dictionary&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt; _members;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Für die Benennung der clientseitigen Klasse und des Objekts werden zwei weitere Member deklariert&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; _clientClassName;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; _clientObjectName;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Die drei Member werden nun im Konstruktor der Klasse übergeben/gesetzt&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; ClientScriptCreator(&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; clientClassName, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; clientObjectName)&lt;br /&gt;{&lt;br /&gt;    _members &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;,&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt;();&lt;br /&gt;    _clientClassName &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; clientClassName;&lt;br /&gt;    _clientObjectName &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; clientObjectName;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Mit der Überschreibung der Methode &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trysetmember%28VS.100%29.aspx"&gt;TrySetMember&lt;/a&gt; werden die Properties (falls noch nicht vorhanden) in das Dictionary gespeichert.&lt;br&gt;Diese liefert einen &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.dynamic.setmemberbinder%28VS.100%29.aspx"&gt;SetMemberBinder&lt;/a&gt; und ein Objekt mit dem Wert.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;override&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;bool&lt;/span&gt; TrySetMember(SetMemberBinder binder, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; value)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (!_members.ContainsKey(binder.Name))&lt;br /&gt;    {&lt;br /&gt;        _members.Add(binder.Name, value);&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;false&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Ähnlich dazu gibt es die &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trygetmember%28VS.100%29.aspx"&gt;TryGetMember&lt;/a&gt; Methode, welche den gesetzten Wert (falls vorhanden) zurückgibt&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;override&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;bool&lt;/span&gt; TryGetMember(GetMemberBinder binder, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;out&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; result)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (_members.ContainsKey(binder.Name))&lt;br /&gt;    {&lt;br /&gt;        result &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; _members[binder.Name];&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;;&lt;br /&gt;    } &lt;br /&gt;    result &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;null&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;false&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Nun ist die Klasse im Stande dynamisch Properties zu setzen und zurück zu geben.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;dynamic clientScriptCreator &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; ClientScriptCreator();&lt;br /&gt;clientScriptCreator.PropertyOne &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"'Some string'"&lt;/span&gt;;&lt;br /&gt;clientScriptCreator.PropertyTwo &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"false"&lt;/span&gt;;&lt;br /&gt;clientScriptCreator.PropertyThree &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"4711"&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Das client Script muss nun zusammengesetzt werden um in den Header geschrieben zu werden. &lt;br&gt;Dafür eine Methode GetDefaultScript die den Dictionary Member durchläuft und diesen in ein &amp;lt;script type=“test/javascript“&amp;gt; Konstrukt wiedergibt.&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt; GetDefaultScript()&lt;br /&gt;{&lt;br /&gt;    StringBuilder sb &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;    sb.Append(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"&amp;lt;script type=\"text/javascript\"&amp;gt;"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; Environment.NewLine);&lt;br /&gt;    sb.Append(_clientObjectName &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;" = new "&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; _clientClassName &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"();"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; Environment.NewLine);&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;foreach&lt;/span&gt; (KeyValuePair&amp;lt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;string&lt;/span&gt;, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;&amp;gt; kvp &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;in&lt;/span&gt; _members)&lt;br /&gt;    {&lt;br /&gt;        sb.Append(_clientObjectName &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"."&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; kvp.Key &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;" = "&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; kvp.Value &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;";"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; Environment.NewLine);&lt;br /&gt;    }&lt;br /&gt;    sb.Append(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"&amp;lt;/script&amp;gt;"&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; sb.ToString();&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;Das Script soll anschließend in einem Literal Control im head Bereich der Seite stehen&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;head&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;asp:Literal&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ID&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="ClientScriptLiteral"&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;runat&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;="server"&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: Maroon;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;head&lt;/span&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br&gt;
&lt;br&gt;Was noch fehlt ist der Aufruf der Methode, die das client Script zurückgibt.&lt;br&gt;Dafür die TryInvokeMember überschreiben, damit dynamische Methoden aufgerufen werden können. In dem folgenden Abschnitt wird auf die Methode „ToDefaultScript“ überprüft – wenn diese vorkommt, wird das Script zurückgeliefert:&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;override&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;bool&lt;/span&gt; TryInvokeMember(InvokeMemberBinder binder, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt;[] args, &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;out&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;object&lt;/span&gt; result)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (binder.Name == &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"ToDefaultScript"&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        result &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; GetDefaultScript();&lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    result &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;null&lt;/span&gt;;&lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;false&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;In der Page_Load der Seite erfolgt der Aufruf wie folgt&lt;br&gt;&lt;br&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;ClientScriptLiteral.Text &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; clientScriptCreator.ToDefaultScript();&lt;/span&gt;&lt;/code&gt;&lt;br&gt;
&lt;br&gt;Das Ganze ist nun wirklich dynamisch. Wird die JavaScript Komponente weiter entwickelt, braucht man sich nicht mehr darum zu kümmern und kann die Objekte wo gewünscht einfach erweitern.&lt;br&gt;&lt;br&gt;Anbei gibt’s noch das Beispiel als Visual Studio 2010 Projekt dazu.&lt;br&gt;&lt;img src="http://www.aspnetzone.de/aggbug.aspx?PostID=214739" width="1" height="1"&gt;</description><enclosure url="http://www.aspnetzone.de/blogs/robertobez/attachment/214739.ashx" length="14397" type="application/zip" /><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Dynamic/default.aspx">Dynamic</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.aspnetzone.de/blogs/robertobez/archive/tags/C_2300_%204/default.aspx">C# 4</category></item></channel></rss>