Montag, 22. Februar 2010

Microsofts Concurrency Coordination Runtime (CCR) - Asynchron und doch zusammen

Wenn man mit asynchronen Tasks arbeitet, steht man oft vor dem Problem, das man diese zwar asynchron aufrufen möchte, aber dennoch im Haupttask auf das Ergebnis der losgelaufenen Prozesse warten möchte.

Einen Ansatz, wie dies mit WCF-Mitteln zu lösen ist, liefern uns in der Dotnetpro 3/2010 die Autoren Tobias Richling et al. in folgendem Artikel. Einen alternativen Ansatz unter Verwendung des Kommunikationsframework Xcoordination Application Space zeigt uns Ralf Westphal in seinem Beitrag One Man Think Tank Gedanken: Asynchronizität. Das Xcoordination Application Space (AppSpace)-Framwork ist eine Open Source Komponente, die bei CodePlex liegt und die Verteilung von Anwendungen erlaubt, die mit Microsofts Concurrency Coordination Runtime (CCR) arbeiten.

Ein einfaches Beispiel für einen Worker-Prozess (in mehreren Threads) sieht dann so aus:

   1: using System;
   2: using System.Threading;
   3: using Microsoft.Ccr.Core;
   4: using XcoAppSpaces.Core;
   5:  
   6: namespace MainDemo
   7: {
   8:     class Demo01SimpleWorker
   9:     {
  10:         public static void Main()
  11:         {
  12:             Console.WriteLine("Xco Application Space - Simple Worker Demo / Running on thread {0} / [Enter] to finish", Thread.CurrentThread.GetHashCode());
  13:  
  14:             using (XcoAppSpace space = new XcoAppSpace())
  15:             {
  16:                 // Start a worker locally. Using the call the worker is registered in the AppSpace instance
  17:                 // and listed as active. It´s now ready to received messages through its contract instance.
  18:                 // Workers are singletons.
  19:                 space.RunWorker<PWorker, MyWorker>();
  20:  
  21:                 PWorker w = space.Resolve<PWorker>();
  22:                 w.Post(1);
  23:                 w.Post("hello");
  24:                 w.Post(2);
  25:                 w.Post("world!");
  26:  
  27:                 // Without stopping here the process would terminate before the work
  28:                 // in the background has been finished.
  29:                 Console.ReadLine();
  30:             }
  31:  
  32:             Console.ForegroundColor = ConsoleColor.Green;
  33:             Console.WriteLine("Done! Some output has been generated.");
  34:         }
  35:  
  36:  
  37:         internal class PWorker : PortSet<int, string>{}
  38:  
  39:         // Workers need to implement a CCR Port or PortSet as its contract
  40:         internal class MyWorker : PWorker
  41:         {
  42:             // Mark methods to process contract messages with an Xco App Space attribute
  43:             // to have them automatically wired to a contract port.
  44:             [XcoConcurrent]
  45:             void ProcessInt(int msg)
  46:             {
  47:                 Console.WriteLine("  Received int {0} on thread {1}", msg, Thread.CurrentThread.GetHashCode());
  48:             }
  49:  
  50:             [XcoConcurrent]
  51:             void ProcessString(string msg)
  52:             {
  53:                 Console.WriteLine("  Received string '{0}' on thread {1}", msg, Thread.CurrentThread.GetHashCode());
  54:             }
  55:         }
  56:     }
  57: }

Freitag, 19. Februar 2010

Silverlight Data Binding with RIA Services

Mittels der WCF RIA Services kann man in seiner Silverlight Applikation jetzt auch seine Daten deklarativ an die Controls binden. Genutzt werden muss hier DomainDataSource von den RIA Controls. Dieses Control kann auf folgende Art und Weise mit/ohne Filterkriterien oder zusätzlichen Gruppierungsmerkmalen definiert werden:

   1: <riaControls:DomainDataSource x:Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
   2:     <riaControls:DomainDataSource.DomainContext>
   3:         <ds:OrganizationContext/>
   4:     </riaControls:DomainDataSource.DomainContext>
   5:     <riaControls:DomainDataSource.SortDescriptors>
   6:         <riaData:SortDescriptor PropertyPath="VacationHours" Direction="Ascending" />
   7:     </riaControls:DomainDataSource.SortDescriptors>
   8:     <riaControls:DomainDataSource.FilterDescriptors>
   9:         <riaData:FilterDescriptorCollection>
  10:             <riaData:FilterDescriptor 
  11:  PropertyPath="VacationHours" 
  12:  Operator="IsGreaterThanOrEqualTo">
  13:                 <riaControls:ControlParameter 
  14:  ControlName="vacationHoursText" 
  15:  PropertyName="Text" 
  16:  RefreshEventName="TextChanged" />
  17:             </riaData:FilterDescriptor>
  18:         </riaData:FilterDescriptorCollection>
  19:     </riaControls:DomainDataSource.FilterDescriptors>
  20: </riaControls:DomainDataSource>
  21: <data:DataGrid Name="dataGrid1" MinHeight="100" IsReadOnly="True" Height="Auto" ItemsSource="{Binding Data, ElementName=employeeDataSource}" />

Das Binding zum Control – im Beispiel ein DataGrid - erfolgt dann auf die gewohnte Art und Weise. Jetzt muss man nur noch den Namespace angeben, welcher den DomainContext zur Verfügung stellt. Dies geschieht durch

xmlns:ds="clr-namespace:HRApp.Web"

Wen der Webservice auf der Web-Seite jetzt entsprechend definiert (mehr dazu weiter unten) dann wird das Grid nun über die GetSalariedEmployees gefüllt.

Doch wo ist der Proxy für den Webservice definiert?

Dies ist bei Nutzung der RIA Services nicht nötig, da diese Klassen alle automatisch generiert werden. Zu finden im Ordner Generated_Code im Client (Silverlight) – Projekt. Dieser sollte natürlich nicht überschrieben werden, da dieser ja bei jeder Änderung der Webservice-Klassen neu erzeugt wird.

Schaubild der RIA Services

Ee707359_RIA_CodeGeneration(en-us,VS_91)

Wenn man ein Projekt zur Repräsentation der middle-tier Projekt mit einer Projekt der Präsentationsschicht (z.B. Silverlight)  mittels der RIA Services verknüpft, werden durch die RIA Services Proxy Klassen für die Client Anwendung basiered auf den Entities und Methoden der middle tier generiert. Man kann auch sogenannte shared-Klassen auf der middle-tier Seite zur Implementierung der Applikationslogik definieren, die dann auch auf der Client-Seite zur Verfügung stehen (Namenskonvention <ServiceName>.shared.cs). Eine Definition von Meta-Klassen zur Definition der Validierungen über DataAnnotations ist auch möglich:

[Required]
[CustomValidation(typeof(HRApp.Web.GenderValidator), "IsGenderValid")]
public string Gender;

Der Webservice

Damit ein Webservice für die RIA Services verwendet werden kann, muss dieser von einer DomainService-Klasse abgeleitet werden. Im Beispiel ist dies die LinqToEntitiesDomainService-Klasse. Des weiteren ist die Class-Annotation [EnableClientAccess()] erforderlich, weil hierdurch den RIA Services signalisiert wird, dass die Proxy Klassen (siehe oben) generiert werden.

   1: namespace HRApp.Web
   2: {
   3:     using System;
   4:     using System.Collections.Generic;
   5:     using System.ComponentModel;
   6:     using System.ComponentModel.DataAnnotations;
   7:     using System.Data;
   8:     using System.Linq;
   9:     using System.Web.DomainServices;
  10:     using System.Web.DomainServices.Providers;
  11:     using System.Web.Ria;
  12:     using System.Web.Ria.Services;
  13:  
  14:     [EnableClientAccess()]
  15:     public class OrganizationService : LinqToEntitiesDomainService<AdventureWorks_DataEntities>
  16:     {
  17:         public IQueryable<Employee> GetEmployee()
  18:         {
  19:             return this.ObjectContext.Employee.OrderBy(e => e.EmployeeID);
  20:         }
  21:         public IQueryable<Employee> GetSalariedEmployees()
  22:         {
  23:             return this.ObjectContext.Employee.Where(e => e.SalariedFlag == true).OrderBy(e => e.EmployeeID);
  24:         }
  25:  
  26:         public void InsertEmployee(Employee employee)
  27:         {

Weitere Details siehe Client Code Generation.

Donnerstag, 18. Februar 2010

SEO mit ASP.NET 3.0, Visual Studio 2008

Wie ja vielleicht viele wissen, wird es mit ASP.NET 4.0 und Visual Studio 2010 einige SEO-Erweiterungen geben. Nachzulesen zum Beispiel im MSDN Magazin im Artikel Search Engine Optimization with ASP.NET 4.0, Visual Studio 2010 and IIS7. Doch man muss nicht auf ASP.NET 4.0 warten, um seine Seiten für Suchmaschinen zu optimieren. Ich möchte hier nicht die üblichen statischen SEO Tipps - wie zum Beispiel Images mit Title und beschreibenden Alt-Tag bestücken, auf Keyword Density achten, usw. – beschreiben, sondern auf zwei effektive dynamische Methoden hinweisen.
Zum einem kann man durch URL Rewriting die normalerweisen kryptischen URL’s, wie z.B. show_album.aspx?ID=4711 zum Anzeigen eines speziellen Photoalbums, in die Suchmaschinen freundliche Schreibweise /Bilder_Lufthansa_Halbmarathon_Frankfurt ersetzen oder durch dynamisches Ergänzen der Metatags im Page_Load die entsprechenden Keywords in Abhängigkeit vom konkreten Inhalt versorgen.

SEO-Tip: URL-Rewriting

Für das URL-Rewriting gibt es normalerweise unzählige Tools, die einem das URL-Rewriting auf IIS-Ebene oder durch Erweiterungen wie URL Mapping (Tip/Trick: Url Rewriting with ASP.NET - ScottGu's Blog) ermöglichen. Doch es gibt auch einen sehr pragmatischen Ansatz, wenn man sich wieder auf die etwas verstaubte global.asax besinnt.
Hier kann man im Application_BeginRequest auf folgende Art und Weise prüfen, ob es sich bei der aktuellen URL, um eine optimierte URL (z.B. bilder_Lufthansa_halbmarathon) handelt. Dann aus dem extrahierten Titel die ID des Fotoalbums ermitteln und dann die eigentliche URL (z.B. PhotoAlbum_Contents_s.aspx?Albumid=4711) zusammenbauen. Durch die RewritePath-Methode wird dann der Request auf diese URL umgebogen.
void Application_BeginRequest(Object sender, EventArgs e)
{
string originalPath = HttpContext.Current.Request.Path.ToLower();
Regex rewrite_regexBilder = new Regex(@"bilder_((.+)\.aspx)", RegexOptions.IgnoreCase);
try
{
//see if we need to rewrite the URL
Match match_rewrite = rewrite_regexBilder.Match(originalPath);
if (match_rewrite.Success)
{
string[] cap1 = match_rewrite.Groups[0].Captures[0].ToString().Split('/');
string titleComp = "";
if (cap1.Length > 0)
titleComp = cap1[cap1.Length - 1];
else
titleComp = match_rewrite.Groups[0].Captures[0].ToString();
// Bilder_ abschneiden und .aspx abtrennen
string title = titleComp.Substring(7, titleComp.Length - 12).Replace("_", " ");
int albumid = lnAppFactory_P.getAlbumIDByTitle(title);
if (albumid != 0)
{
string newURL = originalPath.Replace(titleComp, "PhotoAlbum_Contents_s.aspx?Albumid=" + albumid.ToString());
Context.RewritePath(newURL, true);
}
}


SEO-Tip: Metatags dynamisch ergänzen

Um eine dynamische Seite mit den Keywords vom konkreten Inhalt zu füllen, kann man diese Keywords zunächst ermitteln. Dies kann man zum Beispiel dadurch lösen, das man in der Datenbanktabelle noch eine Zusatzspalte Keywords anlegt und diese dann über die entsprechende ID im Page_Load-Event ausliest. Danach muss man im Page-Load-Event nur noch die Metatags neu setzen:


HtmlMeta description = new HtmlMeta();
HtmlMeta keywords = new HtmlMeta();
Page.Title = sTitle;
keywords.Name = "Keywords";
description.Name = "Description";
description.Content = sDescription;
keywords.Content = sKeywords;
Page.Header.Controls.Add(keywords);
Page.Header.Controls.Add(description);

Mittwoch, 17. Februar 2010

XAML Powertoys: Do you speak XAML?

Für alle die kein akzentfreies XAML (Extensible Application Markup Language) sprechen und auch nicht zu den Notepad-Puristen gehören, benötigen entweder Expression Blend oder ein adäquates Tool, um das UI-Design für eine Silverlight- oder WPF-Anwendung zu erstellen.
Diese Tool könnte das Visual Studio Plugin XAML PowerToys sein, welches einem einiges an Tipparbeit erspart und mittels einer Oberfläche die Erstellung von XAML Fragmenten erlaubt. So kann man z.B. über die Business Form eine Tabellenstruktur (=Raster) für seine UI-Elemente festlegen und diese dann mit den Controls befüllen.
Die PowerToys erkennen dabei, ob eine Silverlight- oder WPF-Applikation erstellt wird und generieren die entsprechenden XAML Statements.

Samstag, 13. Februar 2010

Silverlight Toolkit: Themes benutzen

Zusätzlich zu einigen Controls enthält das Silverlight Toolkit auch eine schöne Sammlung von professionellen Themes, die man einfach benutzen und so die eigene Silverlight Anwendung aufpeppen kann.
Die Themes beinhalten zur Zeit (Toolkit November 2009):
  • Bureau Black
  • Bureau Blue
  • Expression Dark
  • Expression Light
  • Rainier Purple
  • Rainier Orange
  • Shiny Blue
  • Shiny Red
  • Whistler Blue
Beispiele dieser Silverlight Themes kann man hier sehen.
Wie verwendet man jetzt die Themes?
Schritt 1: Eine Referenz auf die Themes im Projekt hinzufügen
  1. Im Solution Explorer “References” und “Add Reference” wählen.
  2. Den Ordner mit den Silverlight Toolkit binaries auswählen (C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Bin).
  3. Hinzufügen von Microsoft.Windows.Controls.Theming.
  4. Zusätzlich eine Referenz zu dem ausgewählten Theme einfügen (z.B. Microsoft.Windows.Controls.Theming.BureauBlue.dll aus dem \Themes Ordner).
Schritt 2: Eine Namespace Deklaration in die XAML-Seite
  1. Die gewünschte XAML-Seite aufmachen und eine Referenz auf das Theme einfügen
image
Schritt 3: Ein Control (z.B. dataForm) mit dem Theme verknüpfen
image

Freitag, 12. Februar 2010

Microsoft .NET WCF RIA Services

Mit den WCF RIA Services bietet Microsoft ein Pattern, um die Erstellung von n-tier Applications zu vereinfachen. Die Präsentation kann hierbei mit Silverlight und die Applikationslogik mit ASP.NET erstellt werden. Außerdem werde solche Dinge wie Authentifizierung, Validierung mit Silverlight Komponenten unterstützt.
Weitere Informationen sind hier zu finden.

Dienstag, 9. Februar 2010

ASP.NET MVC 2 – Design Pattern and Framework

Model View Controller (MVC, ‚Modell/Präsentation/Steuerung‘) ist ein Architekturmuster zur Strukturierung der Software-Entwicklung in die drei Einheiten Datenmodell (engl. model), Präsentation (engl. view) und Programmsteuerung (engl. controller). Ziel des Musters ist ein flexibler Programmentwurf, der eine spätere Änderung oder Erweiterung erleichtert und eine Wiederverwendbarkeit der einzelnen Komponenten ermöglicht.
Implementiert wird dieses Entwurfsmuster von Microsoft durch das ASP.NET MVC Framework. Dies wurde Mitte 2008 von Microsoft released und liegt jetzt in einer zweiten Version als Release Candidate 2 vor. Im folgenden möchte ich kurz aufzeigen, welche entscheidenden Neuerungen es in dieser zweiten Version geben wird. Seit April 2009 ist das ASP.NET MVC unter der Microsoft Public License (MS-PL) released worden.

Neue typgebundene HTML Helper Methoden

Neue typgebundene HTML Helper Methoden sind nun in ASP.NET MVC zu finden. Diese Methoden benutzen eine "Html.HelperNameFor()” Namenskonvention. Zum Beispiel: Html.TextBoxFor(), Html.CheckBoxFor(), Html.TextAreaFor(), usw.  Diese unterstützen nun die bekannten Lamda-Ausdrücke um sowohl den Wert als auch die ID des Controls zu referenzieren:
image


Hierüber wird sowohl der Wert gebunden, als auch der Textbox die ID “FirstName” gegeben. Bei der Auswahl der gebundenen Properties wird darüber hinaus Intellisense angeboten!
HTML Element Helpers:
  • Html.TextBoxFor()
  • Html.TextAreaFor()
  • Html.DropDownListFor()
  • Html.CheckboxFor()
  • Html.RadioButtonFor()
  • Html.ListBoxFor()
  • Html.PasswordFor()
  • Html.HiddenFor()
  • Html.LabelFor()
Other Helpers:
  • Html.EditorFor()
  • Html.DisplayFor()
  • Html.DisplayTextFor()
  • Html.ValidationMessageFor()
Typgebundene HTML Helpers in den Templates
Die neuen typgebundenen HTML Helpers Methoden werden auch durch die Templates bei der View-Generierung unterstützt. Hier kann man dann im Add/View-Dialog die Möglichkeit der Auswahl der typgebundenen oder normalen Variante.

ASP.NET MVC 2 Validierungen

ASP.NET MVC 2 unterstützt jetzt DataAnnotations im Modell, wodurch man Validierungsregeln direkt im Modell hinterlegen kann. Das ganze sieht dann so aus:
image
Hier werden also bereits im Modell die üblichen Validierungen, wie Pflichtfeld, Begrenzungen und Bereiche festgelegt. Darüber hinaus sind auch reguläre Ausdrücke (habe ich im Beispiel aus Platzgründen weggelassen) möglich. Durch “DisplayName” lässt sich übrigens im Modell die Default-Beschriftung eines Feldes festlegen. Dies ist dann anwendungsübergreifend und kann natürlich auch aus einem Ressource-File referenziert werden (näheres siehe here.).
Wichtig ist die Nutzung von: using System.ComponentModel;
Clientseitige Validierung mit AJAX
Möchte man statt der serverseitigen Validierung einen clientseitige Prüfung verwenden, so ist dies ohne viel Aufwand über einen Dreizeiler mit AJAX möglich (Definition im Viewer – aspx-Seite):
image
Eigene Customvalidierungen
Für eigene Customvalidierungen kann man sich einfach eine eigene Validierungsklasse – z.B. in der Model-Klasse -nach folgendem Muster definieren:
image

DataAnnotations bei LINQ to SQL oder ADO.NET EF Designer

Aber was macht man, wenn man die Zugriffsklassen und das Mapping zu den Daten nicht selbst machen möchte, sondern z.B. den LINQ to SQL oder ADO.NET Entity Designer verwenden will?
Hier kommen die sogenannten “Buddy classes” ins Spiel. Zuerst legt man eine separate Klasse mit seinen Meta-Daten und Validierungen an und verlinkt diese dann zu der vom Designer generierten Klasse über das “MetadataType” Attribut zu einer partiellen Klasse (partial class) der generierten Klasse. Diese werden dann vom Compiler wieder zusammengefügt, man hat aber im Code eine strikte Trennung.
Beispiel:
image

ASP.NET MVC 2 (RC 2) now available

Jetzt wurde der Release Candidate 2 des ASP.NET MVC 2 für VS 2008/.NET 3.5 freigegeben und kann hier herunter geladen werden.
Das RC2 Release von ASP.NET MVC 2 enthält neben einigen Bug fixes auch Performanceverbesserungen und einige endgültige Änderungen im Bereich des Standardverhaltens bei den Hinzufüge- bzw. Änderungsfunktionen. Einige der Änderungen zwischen RC1 und RC2 sind in ScottGu’s Blog aufgeführt (release notes für mehr Infos).

Donnerstag, 4. Februar 2010

Windows Azure - Lock Mechanismen

Wenn man sich mit der Architektur von Windows Azure Applikationen beschäftigt kommt man irgendwann zwangsläufig an die Stelle, wo man sich fragt: Wie verhindere ich eigentlich, das auf meine Ressourcen nicht von einem anderen parallelen Worker-Prozess zugegriffen werden.

WORKERROLE RESPONSIBILITIES
  1. Message lesen
  2. Message unsichtbar machen, während der Verarbeitung (automatisches Verhalten !!!).
  3. Task beenden
  4. Message löschen

Also brauchen wir uns bei den Queues darum gar nicht nicht kümmern :-). Es gibt übrigens noch eine zweite Methode PeekMessage, welche die Message für andere Prozesse nicht unsichtbar macht.

Montag, 1. Februar 2010

Windows Azure Storage Explorer

Um den Inhalt des Storage anzeigen zu lassen, zum Beispiel zu Testzwecken, kann man den Windows Azure Storage Explorer von Codeplex verwenden.