Sonntag, Oktober 05, 2008

ASP.NET Ajax: Scripte zusammenfassen

Ich bin etwas spät, aber bevor ich es niemals mehr blogge kommt heute der Artikel zu JS. Ich habe mir endlich mal wieder Zeit für das Bloggen genommen und bin auch froh. Meine Arbeitslage hat sich sehr plötzlich etwas entspannt.

Der ScriptManager aus dem .NET Framework 3.5 kann JavaScripte auf dem Server zusammenfassen. Das bedeutet, dass eine Anzahl von Scripten in ein größeres Script zusammengefasst wird. Es gibt mehrere Vorteile, die durch das zusammenfassen entstehen:

- weniger Server-Roundtrips für den Download der Script

- optimierte Script-Files (entfernte Kommentare, entfernte Zeilenumbrüche)

Das schwierige für das Zusammenfassen von Scripten ist allerdings herauszubekommen, was alles geladen werden muss. Hierfür existiert allerdings auch ein passendes Tools, mittels dem der Konfigurationsblock sehr einfach erzeugt werden kann. Der ScriptReferenceProfiler ist ein Server-Control, dass einfach auf der Webseite eingebunden wird. Beim Aufruf der Webseite erhählt man einen Script-Block als Ausgabe. Der Script-Block wird 1:1 in die ASP.NET-Seite eingefügt und zwar beim eingebundenen Script-Manager. Eine sehr gute Anleitung kann unter video-296.aspx angeschaut werden.

Ursprünglich eingebundener ScriptManager:

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>

Eingefügte Scripte, die zusammengefasst werden:

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <CompositeScript>
        <Scripts>
            <asp:ScriptReference Name="MicrosoftAjax.js" />
            <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />
            <asp:ScriptReference Name="”AjaxControlToolkit.Common.Common.js”" Assembly="”AjaxControlToolkit,"
                Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" />
            <asp:ScriptReference Name="”AjaxControlToolkit.ExtenderBase.BaseScripts.js”" Assembly="”AjaxControlToolkit,"
                Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>

Eigentlich ist das alles super einfach, allerdings kann es passieren, dass durch sehr viele Scripte die URL zu lang wird. Als Fehler kommt die Meldung "The resource URL cannot be longer than 1024 characters. If using a CompositeScriptReference, reduce the number of ScriptReferences it contains, or combine them into a single static file and set the Path property to the location of it." Das ganze hört sich wesentlich dramatischer an, als es ist. Um das Problem zu lösen, muss man die Scripte aufteilen. Dazu werden ScriptManagerProxy-Controls verwendet. Die Proxy-Instanzen sind ursprünglich für die Verwendung auf Unterseiten gedacht, um weitere Scripte oder Services einzufügen.

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <CompositeScript>
        <Scripts>
            <asp:ScriptReference Name="MicrosoftAjax.js" />
            <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>
<asp:ScriptManagerProxy ID="proxy1" runat="server">
    <CompositeScript>
        <Scripts>
            <asp:ScriptReference Name="”AjaxControlToolkit.Common.Common.js”" Assembly="”AjaxControlToolkit,"
                Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" />
            <asp:ScriptReference Name="”AjaxControlToolkit.ExtenderBase.BaseScripts.js”" Assembly="”AjaxControlToolkit,"
                Version="3.0.20229.17016," Culture="neutral," PublicKeyToken="28f01b0e84b6d53e”" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManagerProxy>

Ein sehr guter Artikel zu dem Thema wurde von Samir Bellouti geschrieben.

Technorati-Tags: ,

Dienstag, September 09, 2008

ASP.NET MVC Preview 5 - Arrrggghhh

An diesem Wochenende war nun wirklich mal wieder beschäftigen mit ASP.NET MVC dran, das Preview 5 wollte ich natürlich nicht länger hinaus schieben, also wurde das installiert. Vorher habe ich die Release Notes studiert, ob es etwas gibt, dass bei mir Probleme machen könnte. Eigentlich sollte die Migration von Preview 4 nach Preview 5 ohne Komplikationen verlaufen, dachte ich. Übrigens eine nette Übersicht über die Änderungen gibt es unter http://www.coderjournal.com/2008/08/aspnet-mvc-preview-release-5/.

Ich habe den halben Tag damit zugebracht nur eine kleine Funktion in meiner Anwendung zu fixen, allerdings war das mehr Arbeit als ich dachte. Die "Html.RenderUserControl" wurde aus dem Html-Helper entfernt, allerdings ohne Kommentar und Ersetzungsempfehlung. Ein UserConrol kann über den klassischen Weg mit Register und anschließend hinzufügen auf der Seite einbinden. Was macht man allerdings mit den Daten und die Parameter, die alle übergeben wurden. Nunja, ein UserControl habe ich über den klassischen Weg abgebildet, doch die anderen .... Also der Klassiker googlen, ich bin mit Sicherheit nicht der einzige, der auf diese Problem gestoßen ist. Die beste Hilfe war das ASP.NET Forum, in dem wenigstens einer auch den Lösungsweg aufzeigte. Letztendlich muss man sein Control und den Aufruf umschreiben. Bei der Verwendung der RenderPartial-Methode können nicht die Parameter die Control-View als AnonymousType übergeben werden. Ich habe meine Lösung anschließend so angepasst, dass alle Parameter in den Model-Daten übergeben werden und mittels der Eval-Methode extrahiert werden. Der Aufwand war schon recht groß, nun bin ich erstmal froh, dass alles funktioniert.

Wichtig ist bei der Umstellung auf das Preview 5 die Versionsnummern in der web.config entsprechend den Release Notes anzupassen, da durch das Final-Release des SP1 einige Versionsnummern final sind und zu dem auch noch niedriger als in den Test-Builds.

Außerdem muss man bei den ErrorHandler-Attribute aufpassen. Man muss CustomErrors in der Konfiguration aktivieren, damit der ErrorHandler arbeitet, andernfalls werden die Fehlerdetails ausgegeben.

Technorati-Tags: ,,

Dienstag, September 02, 2008

Lost in Work, But still alive

Der letzte Post ist schon verdammt lange her und wenn ich mal den kurzen Beitrag zum SP1 herauslasse, dann ist inzwischen fast 1 Monat vergangen. Ich bin die Tage einfach nicht zum bloggen gekommen, nach 10+h auf Arbeit inkl. Wochenende, hatte ich einfach keine Kraft/Lust mehr zum bloggen. Ich konnte auch kaum Themen neben der Arbeit angehen, geschweige denn die Wohnung aufräumen. Der große hektische Brocken ist geschafft, jetzt droht "nur" das übliche Kundengeschäft. Ich habe jetzt wieder Zeit viel Zeit an jemanden zu denken. Es fällt mir noch immer schwer, wie dumm!

Letzten Monat haben ein Kollege und ich, partiell mit weiterer Unterstützung, einen Prototypen für eine Tourenanwendung auf Basis von SCSF erstellt. Wie der Prototyp angekommen ist, habe ich leider noch nicht erfahren, ich hoffe, dass die Arbeit sich gelohnt hat und entsprechend auch in weitere Entwicklungsarbeit endet. Geklärt ist die Aufwandsentschädigung noch nicht, aber ich gehe davon aus, dass sich das Thema in den nächsten Tage/Wochen klärt.

Der Ausblick auf meine Projekteinsätze sieht jetzt schon extrem schlecht aus. Zumindest richtig schlecht, wenn die Kunden alle "Drohungen" wahr machen und entsprechend beauftragen. Aus irgendeinem Grund gibt es noch kein Klonen. Aber andererseits würde das bei mir auch nicht helfen, da dann 2 herumrennen würden, die die gleiche Frau vermissen.

Meine ursprüngliche Überlegung war mal den Urlaub im September abzufackeln, aber daraus wird mit Sicherheit nichts mehr. Bisschen frage ich mich, ob dieses Jahr noch der Urlaub unter zu bekommen ist. Vermutlich muss ich darüber mit meiner GF reden, denn verfallen lassen will ich den Urlaub nicht.

Ich muss mich in der nächsten Zeit mal wieder auf mein MVC-Projekt stürzen, da dieses für meine Ziele enorm wichtig ist. Außerdem ist damit der Umstieg auf die neuen Versionen von Trac und SVN verbunden, bei beiden Projekten gibt es super Interessante Features, die ich einsetzen möchte.

Das nächste Thema, in das ich mich endlich mal einarbeiten möchte ist WPF und Composite WPF. Ich bin so gespannt, wie sich die Performance im Vergleich zu SCSF sich verhält.

Montag, September 01, 2008

ASP.NET MVC Preview 5

Am Wochenende wurde vom MVC-Projektteam das PR5 veröffentlicht!

Etwas überrascht war ich im August, dass das MVC nicht Bestandteil des Frameworks wurde. Ich habe eigentlich stark gehofft, allerdings wäre der Zeitplan extrem sportlich geworden. Nun ja, ich find es wiederum auch gut, dass lieber die Qualität stimmen musste, bevor man das Fx v

eröffentlicht.

Ich bin noch nicht zur Umstellung meiner Version gekommen, hoffe allerdings das es diesmal weniger Probleme gibt, als beim letzten mal. Da habe ich 2 Tage zum Modifizieren und Testen benötigt. Bin gespannt auf die Posts zu den aktuellen Themen von Phil und Scott. Evtl. geht es auch mit der Screencast Serie weiter.

Download: http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=16775

Technorati-Tags: ,,

Dienstag, August 12, 2008

.NET Framework SP1 und Visual Studio Service Pack 1 Released

Endlich gibt es die beiden Service Packs zum download. Alle Informationen sind sehr gut über diese Link verfügbar Visual Studio 2008 SP1 and .NET 3.5 SP1 Release to Manufacturing.

Der Download ist wirklich gewaltig, Visual Studio SP1 sind mal eben 800MB dazu kommt noch das TFS Service Pack 1 und .NET Framework.

Ich werde in den nächsten Tage meine aktuellen VMs anpassen und alle notwendigen Installationen durchführen.

Schnell noch einige Snapshots machen! ...

Sonntag, August 03, 2008

Windows PerformanceCounter Komponente

In der letzten Woche habe ich mich gleich in 2 Projekten mit Windows Performance Countern beschäftigt. Das war nicht das erste mal, so dass mir dabei auch aufgefallen ist, dass in einer früheren Implementierung von mir eine Reihe von Fehlern waren.

Allgemeines

Mittels Performance Countern kann man sehr gut Leistungsdaten eines Server/Anwendung erfassen und protokollieren. Man kann damit zum Beispiel die Anzahl der Aufrufe auf einen Dienst/Webservice/Layer verfolgen oder die Laufzeit. Es gibt wahnsinnig viele interessante Indikatoren in einer Anwendung. Performance Counter sind ebenso extrem wichtig, wenn mit Monitoring Software eine Anwendung überwacht wird. Sehr interessant für die Verwaltung und Administration von Servern ist auch die Möglichkeit Alarme zu definieren. Einen sehr netten Artikel zum Thema Andrew Z. Tabona Windows 2003 Performance Counter.

Coding

Ich wollte eine Komponente erstellen, die von jeder beliebigen Klasse und große Kenntnisse genutzt werden kann. Leider ist es nicht möglich einfach zu sagen, dass man jetzt in Ziel X etwas ausgeben will. Performance Counter müssen vor der Benutzung angelegt werden, zu dem sind für erhöhte Rechte notwendig. Aber Schritt für Schritt:

Prinzipiell ist das Schreiben von Performance-Counter-Werten sehr einfach.

    1 PerformanceCounter c = new PerformanceCounter("myCategory", "CountCalls",false)

    2 c.Increment();

    3 c.Decrement();

    4 c.IncrementBy(5);

Allerdings muss vorher sichergestellt sein, dass der Counter existiert und zugegriffen werden kann. Da Counter immer auch einer Category zugeordnet sind, muss diese ebenso angegeben werden.

    1 CounterCreationDataCollection creation = new CounterCreationDataCollection();

    2 creation.Add(new CounterCreationData(c.CounterName, c.CounterHelp, c.CounterType));

    3 PerformanceCounterCategory.Create(category, "", PerformanceCounterCategoryType.Unknown, creation);

Beim Anlegen eines Counters hat man immer die Wahl, ob ein Multi-Instanz Counter oder ein Single-Instanz Counter angelegt wird. Die Idee dahinter ist relativ simpel. Jede Applikation/Komponente kann bei einem Multi-Instanz Counter verfolgt werden, entsprechend werden für alle Einträge erzeugt. Bei einem Single Instanz Counter werden alle Log-Informationen für den gesamten Server protokolliert. Eine Differenzierung wäre in dem Fall nicht möglich, aber auch nicht immer sinnvoll.

Wird ein Counter vom Typ "PerformanceCounterType.AverageTimer32" angelegt, so muss zusätzlich auch der BaseCounter "PerformanceCounterType.AverageBase" angelegt werden, da es sonst zu Fehler kommt. Bei der Verwendung des Counters soll man die StartZeit in Ticks - der Endzeit der Aktion angeben, ehrlich gesagt, ich habe es noch nicht 100% verifiziert, ob der Counter richtig funktioniert. Ich nutze am meisten den einfachen Zähler oder Aufrufe pro Sekunde.

ABER, ist eine Category angelegt, kann man keine Counter hinzufügen, zumindest nicht mit Managed Code, ich kenne auch keinen anderen Weg, evtl. ist dies über Registry-Manipulation möglich. Aus diesem Grund muss die Category immer gelöscht werden, wenn ein Counter zu der Category hinzugefügt wird. Anschließend werden alle Counter erneut hinzugefügt.

Nach soviel Kleinigkeiten, hier mal ein ganzer Code-Block:

   63 private static readonly IDictionary<string, IDictionary<string, PerformanceCounter>> categoryDict =

   64     new Dictionary<string, IDictionary<string, PerformanceCounter>>();

   65 private PerformanceCounter GetCounter(string category, string counterName, bool useInstance, PerformanceCounterType type)

   66 {

   67     if (string.IsNullOrEmpty(category) || string.IsNullOrEmpty(counterName))

   68         return null;

   69     try

   70     {

   71         return EnsureWithCategory(category, counterName, useInstance, type, false);

   72     }

   73     catch (Exception ex)

   74     {

   75         System.Diagnostics.Trace.WriteLine("Get counter failed! " + ex.ToString(), "EnterpriseLoggingService.GetCounter");

   76     }

   77     return null;

   78 }

   79 private static ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

   80 

   81 private PerformanceCounter EnsureWithCategory(string category, string counterName, bool useInstance, PerformanceCounterType type, bool deep)

   82 {

   83     PerformanceCounter counter;

   84     cacheLock.EnterUpgradeableReadLock();

   85     try

   86     {

   87         if (categoryDict.ContainsKey(category))

   88         {

   89             IDictionary<string, PerformanceCounter> perf = categoryDict[category];

   90             return EnsureCounter(category, counterName, useInstance, type, perf);

   91         }

   92         else

   93         {

   94             if (deep)

   95                 return null;

   96             return EnsureCounter(category, counterName, useInstance, type, null);

   97 

   98         }

   99 

  100     }

  101     finally

  102     {

  103         cacheLock.ExitUpgradeableReadLock();

  104     }

  105 }

  106 

  107 private static PerformanceCounter EnsureCounter(string category, string counterName, bool useInstance, PerformanceCounterType type, IDictionary<string, PerformanceCounter> perf)

  108 {

  109     PerformanceCounter counter;

  110     if (perf != null && perf.ContainsKey(counterName))

  111     {

  112         counter = perf[counterName];

  113     }

  114     else

  115     {

  116         cacheLock.EnterWriteLock();

  117         try

  118         {

  119             bool exists = false;

  120             Dictionary<string, PerformanceCounter> counterDict;

  121             CounterCreationDataCollection creation = new CounterCreationDataCollection();

  122             if (PerformanceCounterCategory.Exists(category))

  123             {

  124                 exists = PerformanceCounterCategory.CounterExists(counterName, category);

  125                 PerformanceCounterCategory pc = new PerformanceCounterCategory(category);

  126                 PerformanceCounter[] counters;

  127                 if (pc.CategoryType == PerformanceCounterCategoryType.MultiInstance)

  128                     counters = pc.GetCounters(AppDomain.CurrentDomain.FriendlyName);

  129                 else

  130                     counters = pc.GetCounters();

  131 

  132                 foreach (PerformanceCounter c in counters)

  133                 {

  134                     creation.Add(new CounterCreationData(c.CounterName, c.CounterHelp, c.CounterType));

  135                 }

  136                 if (!exists)

  137                 {

  138                     if (perf != null)

  139                     {

  140                         foreach (PerformanceCounter p in perf.Values)

  141                         {

  142                             p.Dispose();

  143                         }

  144                         perf.Clear();

  145                         perf = null;

  146                     }

  147                     PerformanceCounterCategory.Delete(category);

  148                 }

  149             }

  150             if (!exists)

  151             {

  152                 creation.Add(new CounterCreationData(counterName, "", type));

  153                 if (type == PerformanceCounterType.AverageTimer32)

  154                     creation.Add(new CounterCreationData(counterName + "Base", "", PerformanceCounterType.AverageBase));

  155                 PerformanceCounterCategory.Create(category, "", PerformanceCounterCategoryType.Unknown, creation);

  156             }

  157             counterDict = new Dictionary<string, PerformanceCounter>(creation.Count);

  158             foreach (CounterCreationData ccd in creation)

  159             {

  160                 counter = new PerformanceCounter(category, ccd.CounterName, useInstance ? AppDomain.CurrentDomain.FriendlyName : "", false);

  161                 counterDict.Add(ccd.CounterName, counter);

  162             }

  163             counter = counterDict[counterName];

  164             perf = counterDict;

  165             if (categoryDict.ContainsKey(category))

  166                 categoryDict[category] = counterDict;

  167             else

  168                 categoryDict.Add(category, counterDict);

  169         }

  170         finally

  171         {

  172             cacheLock.ExitWriteLock();

  173         }

  174     }

  175     return counter;

  176 }

  177 public void NumberCounter(string category, string counterName, bool useInstance, int incrementValue)

  178 {

  179     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.NumberOfItems32);

  180     if (c != null)

  181     {

  182         if (incrementValue == 1)

  183             c.Increment();

  184         else

  185         {

  186             if (incrementValue == -1)

  187                 c.Decrement();

  188             else

  189                 c.IncrementBy(incrementValue);

  190         }

  191     }

  192 }

  193 

  194 public void RateCounter(string category, string counterName, bool useInstance, int incrementValue)

  195 {

  196     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.RateOfCountsPerSecond32);

  197     if (c != null)

  198     {

  199         if (incrementValue == 1)

  200             c.Increment();

  201         else

  202         {

  203             if (incrementValue == -1)

  204                 c.Decrement();

  205             else

  206                 c.IncrementBy(incrementValue);

  207         }

  208     }

  209 }

  210 

  211 public void AvarageCounter(string category, string counterName, bool useInstance, long incrementValue)

  212 {

  213     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.AverageTimer32);

  214     if (c != null)

  215     {

  216         PerformanceCounter cBase = GetCounter(category, counterName + "Base", useInstance, PerformanceCounterType.AverageTimer32);

  217         c.IncrementBy(incrementValue);

  218         cBase.Increment();

  219     }

  220 }

  221 

  222 public void RemoveCurrentCounterInstance(string category, string counterName)

  223 {

  224     cacheLock.EnterReadLock();

  225     try

  226     {

  227         if (categoryDict.ContainsKey(category) && categoryDict[category].ContainsKey(counterName))

  228         {

  229             if (PerformanceCounterCategory.CounterExists(counterName, category) && PerformanceCounterCategory.InstanceExists(AppDomain.CurrentDomain.FriendlyName, category))

  230             {

  231                 PerformanceCounter c = categoryDict[category][counterName];

  232                 c.InstanceName = AppDomain.CurrentDomain.FriendlyName;

  233                 c.RemoveInstance();

  234             }

  235 

  236         }

  237     }

  238     finally

  239     {

  240         cacheLock.ExitReadLock();

  241     }

  242 }

  243 

  244 public void SetNumberCounterValue(string category, string counterName, bool useInstance, int newValue)

  245 {

  246     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.NumberOfItems32);

  247     if (c != null)

  248     {

  249         if (useInstance)

  250             c.InstanceName = AppDomain.CurrentDomain.FriendlyName;

  251         c.RawValue = newValue;

  252     }

  253 }

  254 public void SetAvarageCounterValue(string category, string counterName, bool useInstance, long newValue)

  255 {

  256     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.AverageTimer32);

  257     if (c != null)

  258     {

  259         PerformanceCounter cBase = GetCounter(category, counterName + "Base", useInstance, PerformanceCounterType.AverageTimer32);

  260         if (useInstance)

  261             c.InstanceName = AppDomain.CurrentDomain.FriendlyName;

  262         c.RawValue = newValue;

  263         if (newValue == 0)

  264             c.RawValue = 0;

  265     }

  266 }

  267 public void SetRateCounterValue(string category, string counterName, bool useInstance, int newValue)

  268 {

  269     PerformanceCounter c = GetCounter(category, counterName, useInstance, PerformanceCounterType.RateOfCountsPerSecond32);

  270     if (c != null)

  271     {

  272         if (useInstance)

  273             c.InstanceName = AppDomain.CurrentDomain.FriendlyName;

  274         c.RawValue = newValue;

  275     }

  276 }

Deployment

Beim Deployment sollte man die Empfehlung von MS usw. berücksichtigen und bei der Installation alle Counter anlegen. Counter zu nutzen ist nicht sehr "teuer", allerdings ist es sehr aufwendig und langsam, wenn Counter angelegt werden. Zu mal immer alle Counter inklusive Category gelöscht wird.

Der einfachste Weg bei der Installation ist es eine Installer-Klasse zu erstellen, die alles Counter der Anwendung anlegt. hierfür ist ein bisschen Coding notwendig und anschließend einfach "installutil" aufrufen.

Technorati-Tags: ,,,

Freitag, Juli 11, 2008

ASP.NET MVC Authorization (EntLib Rules)

Das letzte Wochenende habe ich mich mal wieder mit ASP.NET MVC beschäftigt, diesmal schon das 2. Wochenende mit der Autorisierung  von Benutzern. Ich glaube, die Variante über den Enterprise Library Rules Provider ist der beste Weg.

Hier mal kurz die verschiedenen Möglichkeiten

Also man hat sehr viele Möglichkeiten und wer sich mal durch die Links durchgeklickt hat, der wird auch mitbekommen haben, dass es sehr viele Diskussionen über den richtigen Weg gibt. Den Ausschlag für die Enterprise Library bei mir hat den Einsatz sowohl in Services, Web-Apss und WinForms  mit externer Konfiguration gegeben. Man kann auch einige andere der oben aufgeführten Konzepte damit verbinden.

Aus meiner Sicht ist es schon sehr Vorteilhaft, wenn man ein Konzept einsetzt, dass über den Applikationstyp hinweg eingesetzt werden kann. Zum anderen bietet die Enterprise Library durch das Konfigurationstool eine einfache grafische Möglichkeit der Konfiguration, so dass Administratoren nicht unbedingt in die Tiefen eingeführt werden müssen. Aber bestimmt für Administratoren, die auf Sicherheit sehr viel Wert legen ist die Möglichkeit den AzMan einzusetzen. Hierbei handelt es sich um eine Konfiguration die im Active Directory abgelegt werden kann. Der Rules-Provider kann so verwendet werden, dass Geschäftsvorfälle als Regeln dienen. Es gibt noch eine Reihe weiterer netter Vorteile, also durchaus mal nachlesen.

Nun genug zu den Vorteilen, hier noch ein Verwendungsbeispiel:

    1 <securityConfiguration defaultAuthorizationInstance="" defaultSecurityCacheInstance="">

    2   <authorizationProviders>

    3     <add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

    4       name="ProjectRuleProvider">

    5       <rules>

    8         <add expression="R:Administrators OR  R:Chef"

    9           name="CreateProject" />

   12         <add expression="R:Administrators OR  R:Chef"

   13           name="DeleteProject" />

   16         <add expression="R:Administrators OR  R:Chef"

   17           name="EditProject" />

   18       </rules>

   19     </add>

   20   </authorizationProviders>

   21 </securityConfiguration>

Wie zu sehen ist, sind die einzelnen Regeln nur eine Zeile lang. Aber keine Angst, die Syntax ist einfach und es gibt zu dem das Konfigurationstool in dem sich noch weitere Sachen einfach zusammen klicken und testen lassen. Zur Konfiguration gehört eine solche Abfrage (die Zeilennummer sind nicht von oben):

   26 IAuthorizationProvider auth = AuthorizationFactory.GetAuthorizationProvider("ProjectRuleProvider");

   27 return auth.Authorize(principal, "EditProject");

Bei Prinzipal handelt es sich um ein IPrinzipal-Objekt, dass zum Windows Nutzer oder zum Web-Nutzer gehört.

An dem Artikel habe ich jetzt eine Woche "gedoktort", dadurch ist er nicht besser geworden. :( MVC macht immer noch sehr viel Spass, aber nun muss ich auch mal an die Dokumentation ran, damit auch mal ein anderer das Zeug pflegen kann. Testfälle formulieren fehlt auch noch. :(

Sonntag, Juni 29, 2008

Der Juni Monat

Ist nun schon eine Weile her, dass ich rein privates geschrieben habe. Daher nun mal ein kleiner Rückblick auf den Juni.

Der Juni ist immer ein Familienfeiermonat, meine Schwägerin hatte Geburtstag, ich hatte Anfang des Monats Geburtstag und schließlich auch noch mein Neffe. (übrigens, ähnlich war auch der Mai) Um nicht zu viel zu feiern, haben wir wenigstens 2 Geburtstage zusammen gelegt (1Tag vor meinem eigentlichen Geburtstag gefeiert). Es war aber schon eine ganze Menge zu tun, Salate, Fleisch einkaufen und noch bisschen kochen. Das Wetter war richtig Klasse und sehr warm, so hat es bei meinem Bruder im Garten richtig Spass gemacht. Meinen Geburtstag habe ich anschließend mit meinen besten Freunden in Berlin verbracht. Wir (inkl. 2 kleinen Kindern) haben schön Kaffee gegessen und anschließend ging es noch etwas durch die Stadt und anschließend zum grillen. War angenehm mit den 4 den Geburtstag zu verbringen.

Im Juni war dieses Jahr außerdem noch ein 4 tägiges Firmenevent. Um alle aus der Arbeit herauszureißen ging es etwa 150km Richtung Norden in den Robinson Club. In den 4 Tagen habe ich massig gegessen, es ist unglaublich, was in den Bauch alles so rein geht. Das nette an dem Event war, dass auch die Familien mit-/nachkommen durften, bei mir gab es niemanden, aber war interessant auch mal die Kinder der Kollegen zu sehen. Insgesamt ein schönes Event, das mit einem Sportlichen und Erholsamen Sonntag echt schön war. Anschließend hatte ich auch noch 3 Tages Muskelkater.

Den restlichen Monat habe ich nur mit Arbeit verbracht, fast nur. Ich bin zur Zeit mal wieder auf Dienstreisen und treibe mich in Deutschland rum. Ein Tag war noch Kirschernte bei meinen Bruder, natürlich nicht nur ernten sondern auch entspannen im Garten.

Mit einigen Kollegen wollten wir schon seit Anfang Mai endlich mal wieder Volleyball spielen. Aber wie die Welt so spielt, wir haben es einfach nicht hinbekommen. Aber der nächste Anlauf folgt demnächst.

Ansonsten ist bei mir aber nix los. Viele Freunde habe ich schon lange nicht mehr gesehen und ....

Nun noch schön auf das Deutschland-Spiel heute Einstimmen, die Fan-Meile ist wohl schon geschlossen und ich muss morgen gegen 5:00 aufstehen. Wir werden endlich mal wieder Europameister!

UPDATE: Leider war es nix mit dem Titel, aber wenigstens war das Fußballspiel ansehnlich. Spanien war im ganzen Spiel besser, zumindest mit den klar besseren Chancen. Gratulation! Nun ins Bett!

Sonntag, Juni 22, 2008

Kämpfen mit ASP.NET MVC

Ich habe mir dieses Wochenende mal wieder etwas Zeit für ein Projekt genommen, in dem das ASP.NET MVC-Framework zum Einsatz kommt. Das Arbeiten mit dem MVC-Framework macht mir richtig Spass. Aber dennoch gibt es einige Hacken, die einem den nerv rauben.

MVC Routing Trouble

Allgemein ist es wichtig, dass Routen nach der Reihenfolge des hinzufügen ausgewertet werden. Meistens sollte dass auch mit der Lesereihenfolge in der Global.asax übereinstimmen.

Meine erste Baustelle war das Routing bzw. die Übergaben von Parametern. Mir ist noch nicht klar, warum die Standardwerte in der Global.asax nicht weitergegeben werden. Meine Nullable-Parameters haben erhalten nicht den Wert. Für das Problem habe ich 2 mögliche Lösungsszenarien, zum einen kann man die Parameter nicht Nullable machen oder innerhalb der Methode ggf. den Standardwert setzen.

Bei einer meiner Routen wurden einer der 1. Parameter nur ab und zu gesetzt. Zur besseren Darstellung mal ein Beispiel:

Die Route:

new Route("Projects/Results/{client}/{customerName}/{projectName}/{page}/{pageSize}/{order}", new MvcRouteHandler())
{
    Defaults = new RouteValueDictionary(new { controller = "Projects", action = "Results", client = ClientEnum.SDC, customerName = "", projectName = "", page = 1, pageSize = 20, order = "Default" }),
}

Signatur:

public void List(ClientEnum client, long page, long pageSize, string order)
{
    this.Results(client, null, null, page, pageSize, order);
}

Die Url:

http://localhost/Projects/search/customerPart/myProjectPart

In meinen Routen soll eigentlich die nicht mehr die Default.aspx aufgerufen werden, hierfür habe ich noch nicht die Lösung gefunden. Das Verhalten muss ich mir noch mal zu Gemüte führen und die Videos dazu anschauen, Vielleicht schon morgen im Zug.

SQL Paging Trouble

In der Anwendung greife ich auf einen Sql Server oder Sql Server Express mittels Paging zu, leider ist es kompliziert eine ordentliche Abfrage dafür zu erstellen. Normalerweise soll man für Paging-Abfragen RowNumber oder Rank benutzen, alternativ wird oft über Temp-Tables das Select erstellt. Allerdings ist das mit dem Sql Express nicht möglich, in dem Fall ist ein anderer Weg notwendig. Ich bin auf eine recht einfache Lösung im Internet gestoßen, dabei wird Top verwendet um die Ergebnismengen zu reduzieren. Das Grundprinzip für die Abfrae verwendet TOP mit unter Queries und könnte so aussehen:

SELECT top(ANZAHL) * 
FROM (
    SELECT top(OFFSET + ANZAHL) * 
    FROM MyTable
    ORDER BY xyz ASC
) as maxLimit 
ORDER BY xyz DESC

SETUP

Wer das MVC unter IIS6 benutzen will, sollte mal in die Blog-Einträge How to enable pretty urls with Asp.Net MVC and IIS6 oder Using ASP.NET MVC on IIS 6 without the .MVC Extension schauen. Besser kann man das nicht mehr beschreiben. Bei beiden Techniken wird Url-Rewriting eingesetzt. Ich würde aber den IIS7 empfehlen, da sind solche Umwege nicht mehr notwendig.

Donnerstag, Juni 19, 2008

Subversion 1.5 ist da!

Endlich, Endlich ist Subversion 1.5 verfügbar. Ich warte schon so lange auf das Release und nun kann man sich auf die vielen neuen Features freuen. Ursprünglich war das Release mal für Ende 2007 angekündigt, aber es zog sich dann. Ich finde es aber nicht so schlimm, dass es länger gebraucht hat, wenn die Qualität stimmt. Die wichtigsten Features sind das Merge Tracking und WebDav transparent wirte-through proxy, alle anderen Features sind in den Release notes aufgeführt.

Natürlich habe ich gleich den Download (Source) begonnen, allerdings gibt es aktuell noch keine Binaries, aber die kommen sicher in den nächsten Stunden. (Binaries download) Die 2. wichtige Komponente TortoiseSVN wird sicher ebenfalls in den nächsten Stunden oder Tagen released werden.

Ich werde bei uns das update unseres Versions-Servers in den nächsten Wochen durchführen. Es ist nur immer problematisch Sicherzustellen, dass es nicht zu Seiteneffekten mit anderen Anwendungen kommt. Ich kann es ehrlich gar nicht mehr erwarten damit zu arbeiten.

Noch ein ganz anderes Thema: Ich habe heute von einem Projekt gehört, dass Nunit für Team Builds verfügbar macht. Das Projekt nennt sich Nunit4MSBuild. Wer fleißig mit Nunit und TFS arbeitet, sollte sich das Projekt durchaus mal anschauen. Ich bin allerdings eher ein SVN-/TRAC-/TortoiseSVN-/NUnit-/CCNET-Fan.

Mittwoch, Juni 18, 2008

Endlich MCSD

Puuuh, ich habe es geschafft, seit dem 12.6. bin ich nun ein Microsoft Certified Solution Developer und auch ein Microsoft Certified Technology Specialist. Das interessante ist, dass der MCSD rückwirkend zum 5.3. ausgestellt wurde und der Technology Specialist zum 12.6.. (Transcript download)

Die BizTalk-Prüfung war nicht so schwer, wie meine anderen Prüfungen. Das Ergebnis von mir und auch einem Kollegen in der Prüfung, zeigt, dass es sehr einfach war. Man musste einige Sachen noch einmal Prüfen und nachlesen, aber dann sollt die Prüfung zu schaffen sein. Besonders hilfreich sind die prüfungsähnlichen Anwendungen.

Nun mal die nächsten Schritte überlegen. Es gibt leider so viele Prüfungen.

Dienstag, Juni 03, 2008

Die Beste Band der Welt

Vorgestern war Ärzte Konzert in der Kindl Bühne Wuhlheide, den Title "Beste Band" haben sie sich selber gegeben, das ist nicht meine Idee. Ich kann mir ein Ärzte Konzert außerhalb der Wuhlheide gar nicht vorstellen, dass ist einfach der beste Ort dafür. Heute bin ich dadurch etwas KO, aber mal von Anfang an.

Letztes Jahr habe ich 2 Karten für das Konzert gekauft, damals hatte ich noch eine Freundin und somit hatte ich eine Karte zuviel und wußte bis wenige Tage vorher nicht, wen ich mit hinnehme. Ich habe letztendlich einen Freund gefragt, den ich lange nicht gesehen hatte. Eine Freundin, die ich mehrfach gefragt hatte, wollte/konnte nicht so richtig. Ich fand es schon ziemlich schade, dass ich nicht mit meiner Freundin hingehen konnte. Der Zug war aber schon lange abgefahren.

Als Vorbereitung auf das Konzert hieß es zu erst mal ordentlich eincremen. Es war extrem heiß, aber besser als zu kühl. Nach dem eincremen ging es los zur Tram und wie kann es anders sein, ich schnappe die falsche und verträume das aussteigen. Aber alles kein Problem, in Berlin fährt nicht nur eine Bahn. Durch die Hitze sind alle total begeistert vom Tram fahren. Angekommen, hieß es anschließend noch auf den Rest warten um zum Eingang der Bühne zu marschieren. Wir waren nicht die einzigen die hinein wollten. ;)

Diesmal war das Konzert ohne Vor-Band, die Ärzte fingen direkt an. Direkt heißt dann auch mal Eben mit einer Verspätung von über 1h. Statt 19:00 nach 20:00. Aber das Konzert entschädigt einfach für alles und hat sehr viel Spass gemacht. Interessant waren die Leute im inneren Kreis, die massig Staubwolken produziert haben und das freiwillig. Manchmal sind massen wie die Bekloppten aufeinander zu gerannt. Ich bin kein Fan des "poken", daher für mich auch völlig unverständlich.

Die Staubwolken wurden am Ende für jeden nochmal ein Genuß, beim herausgehen wurden unweigerlich Unmengen davon provoziert und jeder mußte es einatmen. Die Weg in der Wuhlheide sollten mal mit Licht ausgestattet werden. Total finstere Wege die zum Glück von vielen Handy-Displays ausgeleuchtet wurden. Ich habe mich an Ausgang entschlossen den langen Weg zur Tram zu nehmen, was ein längerer Fußmarsch war als ich dachte. Am Ende war ich gegen 00:30 zu Hause, schnell noch geduscht und versuchen etwas schlaf zu finden. Übrigens, ich war anschließend seit 5:45 unterwegs Richtung Kassel und dort war dann arbeiten bis 19:00.

Den Post hatte ich eigentlich schon gestern geschrieben, aber nicht mehr online published.

Sonntag, Juni 01, 2008

Fehlende Zeit, aber kurz ...

Ich habe zur Zeit nicht so richtig einen Schimmer, über was ich am besten bloggen soll. Gibt einiges an interessanten Themen, momentan komme ich nicht so richtig dazu mit den neuen Sachen zu spielen. Ich bereite mich mal wieder auf eine Prüfung vor.

Ein andere Grund für meine mangelnde Zeit ist das Schauen von Web- oder Screencasts von David Hayden. Ich habe nun schon beim 2. Projekt mit der Web Client Software Factory zu tun. Das Konzept gefällt mir recht gut, wobei ich MVC noch ein ganzes Stück besser finde. Mittels der WCSF kann man super moduare Webseiten erstellen und pflegen. Außerdem ist es (zumindest nach den bisherigen Erfahrungen) relativ einfach die Logik auf einen Smart Cient (SCSF) zu portieren oder sogar zu nutzen. Ich glaube, ich würde meine ASP.NET Projekte nie wieder ohne WCSF oder MVC erstellen.

In einem meiner aktuellen Projekte versuche ich Kollegen in die Lage zu versetzen, mittel .NET die Vision der IT umzusetzen. Dabei muss ein Framework realisiert werden und die Kollegen fit in .NET werden. Einzige umgesetzt. Nach meinen bisherigen Erfahrungen ist das die schlechteste Entscheidung. Ich finde, es gibt so viele Mängel mit der Sprache:

  • Aufblähen des Codes (Generics IList(of Object), Properties)
  • Kein Refactoring Support
  • Namespaces verhalten sich etwas anders (Ordner)
  • Attribute müssen auf der gleichen Zeile sein, wie deren Bezugspunkt
  • Man muss überlegen ob nun Inheritance (Klasse) oder Implements (Interface) eingesetzt werden soll.
  • Man muss dem Projekt erst sagen, dass es sicher sein soll
  • Formatierungen sind extrem wichtig
  • Case-Insensitiv
  • IL-Code wird größer ->langsamer?
  • Arrays sind schwerer zu erkennen, da sie nur mit Klammer () merkiert werden, ebenso die Indexer
  • kein Using-Statement!
  • Übergabe von Parametern ist verwirrend (Function MyFunc(ByVal o as Object) as Boolean)

Hier noch ein Link zum Thema VB/C# Visual Basic .NET & C# Die Qual der Wahl?.

Ich habe jetzt schon auf 3 oder 4 Rechnern versucht das Visual Studio 2008 SP1 zu installieren, leider immer ohne Erfolg. Dabei war einer wirklich nur rudimentär installiert. Das Framework 3.5 war dagegen problemlos zu installieren und ich habe damit wenig sorgen.

Wir haben in 2 Wochen ein Firmenevent (SD&C/CapeVision) über 4 Tage, ich bin mal gespannt, was da so alles passiert. Am Anfang habe ich überlegt, ob ich da wirklich mit hin will. Irgendwie bringt jeder Freundin oder Familie mit. Irgendwie werde ich das schon überstehen. Zurück aus dem Firmenevent und gleich weiter zum Projekt Reisen, so wird es laufen. Wobei es sich wenig von den letzten Wochen unterscheidet. Momentan hört man bei fast allen Kollegen und Leuten in der IT das gleiche, es gibt zu viel zu zu tun und alle sind momentan mit Projekten überfüllt.

Übrigens das ist mein erster Post mit Live Writer, ich bin darauf gespannt, was wirklich auf der Seite erscheint. Das Tool ist wirklich sehr nett und es macht Spass damit zu schreiben. Vorher habe ich die Posts als Emails in Outlook erstellt, das war schon nett, aber nicht der Renner.