Single Page Applications und Azure Video Walkthrough

Mit fünfzehn kurzen Videos erhält man gesamt fünfsiebzig Minuten eine Einführung in die Welt der Web Apps auf Azure mit Visual Studio 2013.

Teil 1 2:39
Web Projekt in Visual Studio anlegen
Teil 2 2:53
Nuget Paket Manager
Teil 3 2:58
SQL Data Tools in Visual Studio 2013
Teil 4 2:40
ORM Model mit Entity Framework 6.1 erstellen
Teil 5 3:11
REST Service mit ASP.NET Web API
Teil 6 4:32
Bootstrap responsive Design
Teil 7 2:59
Bootstrap Formular Designen
Teil 8 2:26
Einführung in AngularJS
Teil 9 7:10
Angular JS Module, Service und $Ressource HTTP Client
Teil 10 8:48
AngularJS Controller und Listen
Teil 11 7:50
AngularJS Controller und Listen (second try)
Teil 12 8:32
Angular JS Formular speichern und Datum per Filter formatieren
Teil 13 5:19
publish einer Website zu Azure Web App und SQL Azure
Teil 14 6:02
Azure publish Settings aus Visual Studio managen
Teil 15 6:23
Signalr Hub Methode aus ASP.NET Web Api aufrufen
Teil 16 5:22
SignalR AngularJS Client registrieren und Daten empfangen

Die Videos sind stark komprimiert. Da Vimeo nur 10 Videos pro Tag erlaubt, folgt der Rest später.

Azure Blob Storage lokal nutzen und deploy

Wer Azure Websites Apps entwickelt, stolpert schnell mal über den Anwendungsfall Datei Upload. Dabei stellt sich die Frage, wohin mit den Daten? Ein Bild Upload ins Dateisystem ist zwar möglich, aber nicht im Sinne moderner Architektur. Dafür sieht Microsoft Windows Azure schon von Anfang an den Blob Storage vor.

Wer für die Cloud entwickelt sollte das Windows Azure SDK für .net mit dem Web Plattform Installer installieren. Damit erhält man mehr Funktion für Visual Studio 2013 und einige Tools. Unter anderem den Windows Azure Storage Emulator. Damit lassen BLOB Services auch lokal entwickeln. Ein UI sucht man dafür vergeblich. Lediglich auf der Kommandozeile lässt sich der Storage Emulator starten und administrieren.

WAStorageEmulator.exe init

azure11

Nach dem  das Azure SKD (hier 2.5.1) installiert wurde enthält Windows Azure Storage Explorer für Visual Studio 2013 eine Reihe neuer aufklappbarer Einträge.

azure9

Der Bereich Development beinhaltet den lokalen Azure Storage. Für die Nutzung wird in der Datei web.config ein Connection String angelegt der folgenden Eintrag enthält.

   1:    <connectionStrings>
   2:      <add name="fotosblob" connectionString="UseDevelopmentStorage=true" />

Intern verwendet der Service eine SQL Datenbank. Unser .NET Code soll es dem Benutzer ermöglichen Bilder per Web Browser hochzuladen. Benötigt wird noch die Azure Client Bibliothek WindowsAzure.Storage,, die dem Visual Studio Web Projekt per Nuget hinzugefügt wird.

 azure7

Das HTML5 Frontend enthält ein Input Type File Element. Per Post wird der Upload von einer oder mehreren Dateien durchgeführt.

Die bereits im Azure Blob gespeicherten Objekte wird per Liste angezeigt. Nicht ganz elegant aber funktionell direkt mit dem CloudBlockBlob Typ.

   1:   <form id="form1" runat="server" method="post" enctype="multipart/form-data">
   2:          <div>
   3:              <input type="file" id="File1" name="File1" runat="server" />
   4:              <br>
   5:              <input type="submit" id="Submit1" value="Upload" runat="server" />
   6:              <hr />
   7:   
   8:    <asp:ListView ID="ListView1" runat="server"
   9:          ItemType="Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob"
  10:          SelectMethod="ListView1_GetData">
  11:          <ItemTemplate>
  12:                      <%#Item.Uri%>
  13:                      <br />
  14:          </ItemTemplate>
  15:    </asp:ListView>
  16:  </div>

Wenn nach einem Request im Input Element Dateien vorhanden sind, werden diese im Blob abgelegt. Dazu benötigt man noch ein wenig konzeptionelles Background Wissen. In Zeile 2 wird ein Storage Objekt erstellt. Aus diesem eine Art Proxy Client um mit dem Dienst zu sprechen.

Ein Azure Storage kann 0-n Container enhalten. In Zeile 4 wird der Foto Container identifiziert und bei Bedarf auch erzeugt. Um die hochgeladenden Bilder für jedermann per URL abrufbar zu halten, dient Zeile 6. Ab dann wird das BLOB Objekt per Referenz auf das Upload Objekt erzeugt und gefüllt.

   1:  If IsNothing(Request.Files("File1")) = False Then
   2:     Dim storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.ConnectionStrings("fotosblob").ConnectionString)
   3:     Dim blobClient = storageAccount.CreateCloudBlobClient()
   4:     Dim container = blobClient.GetContainerReference("meinefotos")
   5:     container.CreateIfNotExists()
   6:     container.SetPermissions(New BlobContainerPermissions With
{.PublicAccess = BlobContainerPublicAccessType.Blob})
   7:     Dim blockBlob = container.GetBlockBlobReference(
Path.GetFileName(File1.PostedFile.FileName()))
   8:     blockBlob.UploadFromStream(File1.PostedFile.InputStream)

Theoretisch sind wir nun fertig. Die Images lassen sich im Visual Studio Server Explorer abrufen aus der Liste der Blob Elemente.

image

In der Praxis wird man eher eine Anwendung diesen Job machen lassen.  Der Code ist bis Zeile 5 ident mit dem vorigen VB.NET Azure Code Beispiel. Refactoring! Für Demo Zwecke ist ein funktioneller Code Block durchaus sinnvoll. In Zeile 6 wird eine Referenz auf den Blob Container gezogen. Danach recht verkürzt per LINQ die erhaltenen Objekte direkt in eine Liste von BlockBlob Objekten gecastet.

   1:   Public Function ListView1_GetData() As List(Of CloudBlockBlob)
   2:          Dim storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.ConnectionStrings("fotosblob").ConnectionString)
   3:          Dim blobClient = storageAccount.CreateCloudBlobClient()
   4:          Dim container = blobClient.GetContainerReference("meinefotos")
   5:          container.CreateIfNotExists()
   6:          Dim blockBlob = container.GetBlockBlobReference("meinefotos")
   7:          Dim q = container.ListBlobs().OfType(Of CloudBlockBlob)()
   8:          Return q.ToList
   9:  End Function

Dieses Beispiel ist mit Vorsicht zu genießen, da es verschiedene Types geben kann (CloudBlockBlob, CloudPageBlob, CloudBlobDirectory) Wer mehr dazu Wissen will findet in diesem Microsoft Blog C# Sample Code.

Im letztem Schritt wird die Frage behandelt wie aus der Web APP eine Azure Web App wird. Bevor es zum Publish bzw Deploy der Code Daten kommen kann, wird ein Azure Storage Account angelegt.

azure8

Wei zuvor schon direkt aus dem Visual Studio Server Explorer mit der Context Menü Option Create Storage Account. In den Eigenschaften (Propertys) findet sich dann der Connection String ohne den Key. Per Klick auf dei drei Punkte ganz rechts des Connection Strings öffnet sich ein weiterer Dialog.

azure10

Aus diesem kopiert man den Connection String und ergänzt die Datei Web.release.config. Sollte die nicht vorhanden sein, auf die Datei mit der Endung pubxml (im Verzeichnis PublishProfiles) rechts klick und  Add Config Transform auswählen.

   1:   <connectionStrings>
   2:        <add name="fotosblob" 
   3:          connectionString="DefaultEndpointsProtocol=https;
AccountName=ppedvdemo;AccountKey=dP6Cu"
   4:          xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
   5:      </connectionStrings>

Beim Publish der Web App wird dann von msbuild der Connection String automatisch angepasst.

Ergänzend sei der Azure Deploy Blog Artikel empfohlen.

Natürlich bieten wir das Thema Azure Development auch als Training an.

ASP.NET Datenbank Website deploy nach Azure

Microsoft macht es einem ziemlich leicht Azure zu nutzen. Kompliziert ist höchstens aus den unzähligen Optionen zu wählen. Mit Visual Studio 2013 lässt sich eine SQL Server basierte Website mit allem Pipapo nach Azure publishen ohne das Azure Portal zu benötigen.

Eine übliche Website im ASP.NET Umfeld besteht aus einem HTML Part, Code per ASPX oder MVC Controller, einem EF Datenmodell und einer SQL Datenbank. Dabei spielt es keine Rolle ob das Datenmodell per Code First oder direkt in der Datenbank erstellt worden ist. Die bei Code Frist nötigen und durchaus nützlichen EF Migrations erzeugen einen mehr Aufwand, der in mini Projekten nicht zu rechtfertigen ist.

Mein ASP.NET Webforms Demo Projekt beginnt deshalb lokal und mit einer Datenbank. Im Verzeichnis APP_DATA wird eine SQL Server Database (database1.mdf) angelegt. Per Doppelklick wird diese dynamisch im SQL Express Attached und kann im SQL Server Object Explorer direkt in Visual Studio bearbeitet werden. Es wird eine Tabelle mit dem Namen table und Felder angelegt. Außerdem können dort direkt Daten erfasst werden. 

Anschließend wird aus den Daten ein Entity Framework Model erzeugt. Darin finden sich auch die Klassen für die Daten Objekte.

Meine Web Forms VB.NET Datenbank Anwendung ist supersimpel.

   1:  <h1>Hello World</h1>
   2:  <asp:ListView ID="ListView1" runat="server" 
ItemType="TestDBAzure.Table" SelectMethod="ListView1_GetData">
   3:              <ItemTemplate>
   4:                  <%#Item.Name%>
   5:              </ItemTemplate>
   6:   </asp:ListView>

Die Daten werden in einer Art Viewmodel aus dem EF Model geladen.

   1:   Public Function ListView1_GetData() As IQueryable(Of TestDBAzure.Table)
   2:          Dim ef As New Model1
   3:          Return ef.Table
   4:      End Function

Nun kommt der spannende Teil. Wie kommt meine Web Anwendung auf den Webserver? Wer diese selbst hostet auf z.B. einem IIS benötigt folgende Schritte

  • Web im IIS anlegen
  • DNS Namen konfigurieren
  • Verzeichnis auf Server per FTP kopieren
  • FTP Zugang konfigurieren
  • SQL Datenbank anlegen
  • SQL User anlegen
  • SQL Datenbank per SQL Skript anlegen
  • Connection Strings in Web.config ändern
  • Debug Option in Web.Config deaktivieren

Vermutlich wurde sogar die ein oder andere Option in der Auflistung vergessen.

Mit Visual Studio klappt das viel einfacher. Keine Admin Aufgaben am Webserver, keine Config Änderungen. Vorausgesetzt man setzt auf die Dienste Azure Web Apps (vormals Web Sites) und SQL Azure.

Im Visual Studio 2013 Web Projekt wird per Rechtsklick der Publish Assistent gestartet.

azure1

Dafür ist natürlich eine Microsoft ID und ein Azure Konto nötig. Die Basic Web App wird von Microsoft mit einem Übertragungslimit kostenfrei angeboten.

In diesem Dialog kann man auch die nötige Datenbank samt SQL Azure erzeugen lassen.

Der Publishing Dienst ist so clever, das er automatisch die Connection Strings in der Web.Config austauscht um statt der lokalen Datenbank die Web Datenbank zu verwenden. Die nötigen Einstellungen dazu werden im Assistenten vorgenommen.

Azure2

Dieser Schritt ist Segen und Fluch zugleich. Es existieren zwei unterschiedliche Versionen der Datei Web.config. Die lokale und eine Remote Version. Im Server Explorer (aus Visual Studio) finden sich im Bereich Azure – Web Sites – Files – eine Möglichkeit die Remote Dateien direkt zu öffnen und sogar zu editieren.

azure4

Die Einstellungen dazu werden in einem Publishing Profil abgelegt. Dieses basiert auf XML und endet auf pubxml.

image

Diese Deployment Deklaration ist mächtig und erlaubt es auch zusätzliche Inhalte per Publis zu deployen. XML typisch findet sich die Regeln für die Connections Strings auf leicht im Code.

   1:   <ItemGroup>
   2:      <MSDeployParameterValue Include="$(DeployParameterPrefix)DefaultConnection-Web.config Connection String">
   3:        <ParameterValue>Data Source=tcp:lm7utauvto.database.windows.net,1433;
   4:  Initial Catalog=ppedvdemo1_db;User Id=ppedv@lm7utauvto;Password=seherGeheim</ParameterValue>
   5:      </MSDeployParameterValue>

Mit Rechtsllick auf diese pubxml Datei im Visual Studio Solution Explorer öffnet sich ein weiteres Stück Redmonder Magie- “Add Config Transform” erzeugt für die debug und release Varianten der Web.Config Transformatonslogik in einer Schema Definitions Sprache. Wer für Release den Debug Switch entfernen möchte findet in der Datei Web.Release.Config folgende Anweisung.

   1:   <system.web>
   2:      <compilation xdt:Transform="RemoveAttributes(debug)" />

Beim ersten Deploy werden alle Assemblies kopiert und die leere Datenbank auf Azure angelegt. Dies dauert ein wenig länger und kann ganz gut im Visual Studio Output Window verfolgt werden.

Dabei fällt auf, das auch die .mdf Datei aus dem APP_DATA Verzeichnis kopiert wird. Da dies unnötig ist, kann man das in den Publish Web Settings auch deaktivieren.

image

Nun sollen die Daten aus der Azure Datenbank direkt editiert werden.  Im Server Explorer erscheint die neue SQL Azure Datenbank. Zwischen mir und Azure steht nun nur noch die Azure Firewall. Diese beschränkt den Zugriff auf bestimmte IP Adressen.  Um von zuhause den SQL Manager zu nutzen muss die dabei genutzte IP Adresse meines Providers beim Azure Dienst freigegeben werden. Auch das macht Visual Studio quasi von alleine.

Azure3

Das Einfügen von neuen Datensätzen geschieht dann auch ohne zusätzliche Software- nur Visual Studio.

azure5

Weitere Einstellungen, wie die Wahl des genutzten .NET Frameworks lassen sich in den Einstellungen der Azrure Web Site einrichten. Auch hier führt eine Rechtsklick auf einen weiteren Settings Dialog.

azure6

Dessen Möglichkeiten erinnern an die Management Console des IIS Webservers. So kann man das Logging dort aktivieren und auch die Logfiles sichten.

Jedes weiter Publishing erfordert lediglich einen Rechtsllick auf das Projekt oder auf einen einzelne Datei.

HTML5 Input Type Number als Ganzzahl

Eigentlich wollte ich diesen Blog Post irgendwie ala “die wundersamen Abenteuer des Robinson Crusoe” nennen. Aber Google und SEO verbietet das. Worum geht es? Wieder einmal um was banales in HTML5. Benutzer sollen nur Integer Zahlen eingeben können.

imageNun hat dieser JavaScript Stack an und für sich schon Probleme mit der Tatsache, das die IT Welt nicht einfach nur Number ist. HTML5 erbt diese “Errungenschaft”.

Mit dem Input Type Number lassen sich Benutzereingaben auf Zahlen einschränken. Anhand von Ergänzenden Attributen wie Min und Max lässt sich der Bereich ins positive begrenzen. Zusätzlich dient das Attribut Step dazu auf Ganzzahlen zu beschränken. Step=1 sollte also nur Integer Werte abbilden, was übrigens auch der Default Wert ist.

Soweit der Standard, der wenig überraschend je Browser unterschiedlich implementiert ist.

Zum Test dient folgender ASP.NET Webforms und VB.NET Code.

   1:  <Script runat="server">
   2:          Protected Sub ButtonClick(sender As Object, e As EventArgs) 
   3:              Label1.Text = TextBox1.Text
   4:          End Sub
   5:      </Script>
   6:  <body>
   7:      <form id="form1" runat="server">
   8:      <div>
   9:          <asp:TextBox ID="TextBox1" runat="server" 
  10:              min="0"
  11:              step="1"
  12:              TextMode="Number"></asp:TextBox>
  13:          <asp:Button ID="Button1" runat="server" Text="Button"  OnClick="buttonclick"/>
  14:          <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
  15:      </div>
  16:      </form>

 

Der Chrome Browser versucht mit einem Doppelplfeil einen sanften Hinweis auf die erwarteten Eingaben zu geben.

html5-b

Wenn das Formular ohne novalidate definiert ist, wird der Browser eine Fehlermeldung ausgeben. Falls andere Validierungsframeworks wie aus JQuery eingesetzt werden, wird novalidate im FORM Element gesetzt. Allerdings kann der Benutzer dann Komma und Tausender Trennzeichen Punkt eingeben.

image

Den absoluten Burner (O-Ton Carmen Geiss) liefert der Internet Explorer 11.

html5-a

Ist schon seltsam genug, aber nun treiben wir das auf die Spitze. Im Codebehind wird der Rückgabewert per CInt in einen Integer umgewandelt.

IE 11 rundet erwartungsgemäß auf

image

Chrome ändert die Dimension, was einigermaßen überraschende Konsequenzen haben kann

image

Chrome macht aus dem Komma beim Post einen Tausender Trennpunkt.

Im Ergebnis ist der Input Type Number kaum zu gebrauchen.  Vermutlich sinnvoller ist der Regular Expression unterstützende Typ Text in Verbindung mit Pattern (\d*).

HTML5 ist eben ein fluent Standard.

Azure Web Apps Mail senden

Erst gestern gab es von Scott Guthrie eine Reihe neuer Azure Service Ankündigungen. Azure Websites heißen nun Azure Web Apps. Daneben noch API Apps, mobile Apps und Logic Apps. Ein Problem bleibt aber, wie sende ich eMail aus einer Azure Website App? Einige Blogs und die Suche nach “how to send mail from azure website” deutet auf einen Dienst Namens Sendgrid hin.

Gleich eines vorab. Man kann eMails auch in Azure wie gewohnt mit dem SMTPClient Objekt senden. Folgender .NET Code funktioniert, wenn man einen SMTP Server als Relay Host nutzen kann.

   1:  Dim sc As New SmtpClient
   2:  sc.Host = "mail.ppedv.de"
   3:  sc.Send("xxxx@outlook.com", "hannesp@ppedv.de", "test", "test")

Dabei sind wir auch schon bei den Problem. Azure stellt keinen SMTP Dienst bereit. Jedenfalls bisher nicht, mal sehen was sich in den API Apps noch verbirgt.

Wer über Dienste wie Google Mail oder Outlook live senden möchte, muss sich am SMTP Server authentifizieren um Spammern das Leben zu erschweren. Auch das klappt bei Azure grundsätzlich mit folgendem VB.NET Code Beispiel

   1:  Dim sc As New SmtpClient
   2:  sc.Host = "smtp.live.com"
   3:  sc.EnableSsl = True
   4:  sc.Port = 587
   5:  sc.Credentials = New NetworkCredential("hannesp@ppedv.de", "passwort?")
   6:  sc.Send("xxxxx@outlook.com", "hannesp@ppedv.de", "test", "test")

Allerdings wird vermutlich eine Fehlermeldung in der Website auftauchen ala

Mailbox unavailable. The server response was: 5.7.3 requested action aborted; user not authenticated

Der Grund ist, das diese Website und damit die Anmeldung von einem Azure Web Server kommen. In meinem Fall aus den Niederlanden. Über das Live Portal kann man den Activity Request erkennen und markieren als “von mir stammend”

image

Wenn aber der Mail Server gerade keine Mails entgegen nehmen möchte, wird mein Code Laufzeit Fehler verursachen, die sehr schwer zu behandeln sind. Mail erzeugen und Mail versenden sollten zwei verschiedene Prozesse sein. Vor allem da das Senden asynchron funktioniert, bei Retry versuchen mit mehrstündiger Dauer.

Korrekterweise werden die Einstellungen zum Versand von emals in der Datei Web.Config vorgenommen. Hier im Bereich system.net.  Dort kann man auch festlegen, das die erzeugten Mails in einem Verzeichnis gespeichert werden.

   1:  <system.net>
   2:      <mailSettings>
   3:        <smtp deliveryMethod="SpecifiedPickupDirectory">
   4:          <specifiedPickupDirectory 
pickupDirectoryLocation="D:\home\site\wwwroot\pickup"/>
   5:        </smtp>
   6:      </mailSettings>
   7:   
   8:    </system.net>

Wie erhält man den physikalischen Pfad einer Web Seite die auf Azure läuft. Ganz einfach per Server.MapPath("."). Im Unterverzeichnis Pickup wird dann das email als eml Datei erzeugt.

image

Solche Dateien kann man auf einem Windows System per Doppeltclick öffnen. Auch das enthaltene Text Format ist leicht lesbar.

X-Sender: xxxx@outlook.com
X-Receiver: hannesp@ppedv.de
MIME-Version: 1.0
From: xxxx@outlook.com
To: hannesp@ppedv.de
Date: 24 Mar 2015 18:36:52 +0000
Subject: test
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

test

 

Wenn man nun diese Dateien in ein Pickup Verzeichnis eines Windows SMTP Servers kopiert, werden diese als eMail versandt. Dazu aber später mehr.

Azure Websites Verzeichnis schützen

Microsoft hat ein Geschenk für uns. Azure Websites erlauben das gratis Hosting einer Web Anwendung. Einzig eine Microsoft ID wird benötigt und schon kann man zehn Websites mit bis zu 1GB Speicherplatz nutzen. Bis zu 165MB Datentransfer täglich sind ebenfalls gratis inkludiert. Allerdings ist der Umstieg von einem eigenen IIS zu Azure Websites nicht ganz barrierefrei.

Zu den typischen Aufgaben einer Website gehört der Upload von Dateien durch den Benutzer. In der Regel schreibt der ASP.NET Entwickler einen http Handler (Erweiterung axd) um den Uploadstream entgegen zu nehmen und auf dem Web Server zu speichern. So behält man volle Kontrolle über Größe, Format, Namen und Speicherort. Bisher hat man diese Dateien in einem Verzeichnis der Website gespeichert und möchte das auch weiter so lösen. Alternativ dient dazu auch der Azure Blob Storage.

Fileupload in ein Web Verzeichnis kann ein potentielles Sicherheitsproblem sein. Ein Benutzer kann eine ausführbare Datei (z.B. ASPX) hochladen und somit Code einschleusen. Das Upload Verzeichnis muss also vor ausführbaren Programmcode geschützt werden. Einige ASP.NET Directorys werden out of the box mit besonderen Rechten versehen. So ist alles was in APP_DATA existiert automatisch und zwingend vor Download geschützt. In der Praxis legt man dort seine Datenbanken ab.

Wer einen dedizierten Server mit IIS betreibt hat volle Kontrolle über das NTFS Dateisystem und kann die Rechte dort passend pro User (appool) einstellen.

Beim Publish auf Azure stehen diese Möglichkeiten nicht offen. Man behilft sich mit einer Ausnahmeregel in der Web.config. Sämtliche Datei Handler werden entfernt und mit dem Static File Handler ersetzt so das man nach wie vor Images, Videos oder auch HTML anzeigen bzw. Downloaden kann. Die Ausführung von Code in einer ASPX Datei wird mit einer 404er Fehlermeldung beantwortet.

 

   1:  <location path="app_upload">
   2:      <system.webServer>
   3:        <handlers>
   4:          <clear />
   5:          <add name="StaticFile" path="*" verb="*" 
modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule"
   6:  resourceType="Either" requireAccess="Read" />
   7:        </handlers>
   8:      </system.webServer>
   9:    </location>
  10:  </configuration>

No SQL mit DocumentDB und Azure

Es gibt etwas, was andere total cool finden und Sie nicht den Ansatz einer möglichen Nutzung sehen? Nein ich spreche nicht von der Apple Watch, ich spreche von NoSQL Datenbanken und im besonderen von neuen Azure Dienst DocumentDB. Ein Versuch einer Erklärung für etwas, was die wenigsten vermutlich brauchen werden.

Wenn man wenig weis, hilft immer ein Wikipedia Zitat

NoSQL (englisch für Not only SQL) bezeichnet Datenbanken, die einen nicht-relationalen Ansatz verfolgen und damit mit der langen Geschichte von relationalen Datenbanken brechen. Diese Datenspeicher benötigen keine festgelegten Tabellenschemata und versuchen, Joins zu vermeiden, sie skalieren dabei horizontal. Im akademischen Umfeld werden sie häufig als „strukturierte Datenspeicher“ (engl. structured storage) bezeichnet.

Ein neuer Dokumenten orientierter Vertreter ist documentDB, als Microsoft Azure Service aber nur online Verfügbar. Relativ vereinfacht, werden dabei JSON strukturierte Informationen gespeichert.  Für die Entwicklung steht JavaScript oder auch eine .NET API zur Verfügung.

Abfragen lassen sich mit einer ANSI SQL ähnlichen, reduzierten Syntax oder im .NET Umfeld auch per LINQ durchführen. Sämtliche CRUD Operationen werden unterstützt und lassen sich sogar per REST API ausführen. Unterstützt werden auch Transaktionen, Trigger und Stored Procedures.

Man kann nun stundenlang sinnieren, warum die Aufgabenstellung nicht per RDBMS und SQL Server löst. Microsoft preist documentDB als günstige und skalierbare Lösung. In jedem Fall stößt ein SQL Server bei sehr großen Datenmengen (über 50GB) und/oder vielen Schreiboperationen an Performance Grenzen. In jedem Fall sind Cloud basierte Lösungen für diese Probleme noch anfälliger. Wer rein aus der JavaScript Welt kommt, nutzt documentDB sozusagen als native Datenbank, fern von .net oder SQL.

Stellen wir uns also vor, eine klassische Aufgabenstellung einer Warenwirtschaft mit einer NoSQL Architektur zu lösen. Eine Rechnung stellt dann das Dokument dar. Mit Kopfdaten und Positionen. Die Positionen können sich in der Struktur erheblich unterscheiden. Schrauben haben andere Eigenschaften als Hosen. Einzelne Artikel können sich wiederrum aus Stücklisten zusammen setzen. Alles in einem Dokument und mit erheblich redundanter Datenmenge. Im Ergebnis jedes Document mit unterschiedlicher Struktur innerhalb einer Sammlung.

Zu allererst wendet man sich an das neue Azure Portal und erstellt dort ein documentDB Konto. Das dauert ziemlich lange. Als Ergebnis erhält man einen HTTP Endpunkt und einen Key für die Anmeldung.

documentd4

Als nächstes kann man im Web basierten Management Portal eine oder mehrere Datenbanken hinzufügen. Jede Datenbank enthält Collections (Sammlungen), die auf den ersten Blick Tabellen ähneln- allerdings ohne Struktur. Darin werden die Dokumente gesammelt, z.B. Rechnungen. Aufgrund der Schema Freiheit aber auch gemixt Adressen und Rechnungen.  Eine Sammlung wird immer auf einem Server gehostet, mit Azure typischen zwei zusätzlichen Kopien. Da die Preview Version (stand Feb 2015) ein Limit von 3 Sammlungen aufweist, wird man in der Praxis viel weniger davon nutzen, als bei RDBMS Tabellen und eher um die Daten zu partitionieren.

Auch eine  Sammlung kann man im Portal anlegen. Diese Funktion ist schwer zu finden und erscheint erst nach Auswahl der Datenbank im Azure DocumentDB-Kontobereich. Um den Abschnitt Datenbank zu erreichen, muss man nach unten scrollen.

image

Aber genau das macht NoSQL eben aus, das die Struktur und damit das Datenbank Schema nicht am Anfang steht. Deshalb wird in der Praxis häufig der Code die Aufgabe übernehmen die Collections anzulegen.

Abfragen kann man die Daten direkt im Azure Portal, per Dokument Explorer oder per Abfrage Explorer.

image

Die Abfragen erlauben ähnlich einem SQL Query Tool die Dokumente anhand der Attribute zu selektieren und zeigt die Ergebnisse als JSON an.

image

Hier sieht man das documentDB intern GUID ähnliche ID Werte verwendet.

Wesentliche Part der Struktur geschieht im Code. Wie von mir gewohnt per ASP.NET Webforms und VB.NET. Im Visual Studio Projekt muss per Nuget eine Referenz auf die Documents Clients Assembly eingefügt werden. Da im Stadium Prerelease (oder Preview) nur unter Auswahl der passenden DropDownliste auffindbar.

documentdb7

Es wird ein Client Objekt instanziiert, das später die Methoden für den Datenbank Zugriff kapselt.

 

   1:  Private Url As String = "https://ppedv.documents.azure.com:443/"
   2:  Private key As String = "w9t7JWW...qeZzKMS7pAmbspSKK5gw=="
   3:  Private _client As DocumentClient = New DocumentClient(New Uri(Url), key)

 

So lässt sich die Datenbank und darin die Document Collection per Code erzeugen.

   1:  _client.CreateDatabaseAsync(New Database With {.Id = "miniSAP"})
   2:  ...
   3:    col = Await _client.CreateDocumentCollectionAsync(
   4:                  db.SelfLink,
   5:                  New DocumentCollection With {.Id = "Rechnungen"})

 

Fehlen nur noch Rechnungen. Diese werden im folgenden Code Schnipsel aus zwei TextBoxen und einer passenden Klasse erzeugt.

   1:  Dim p = New rechnung With {
   2:                                   .firma = TextBox1.Text,
   3:                                   .betrag = TextBox2.Text,
   4:                                   .datum = Date.Now}
   5:   
   6:  Await _client.CreateDocumentAsync(col.SelfLink, p)

 

Natürlich will man die Daten auch anzeigen. Webforms hilft per ModelBinding, setzt dann allerdings wieder ein typisierte Liste voraus. Der HTML Code der ASPX Seite.

   1:  <asp:ListView ID="ListView1" ItemType="documentdb1.rechnung" 
   2:              SelectMethod="ListView1_GetData"
   3:               runat="server">
   4:              <ItemTemplate>
   5:                  <%#Item.firma%><br />
   6:              </ItemTemplate>
   7:  </asp:ListView>

 

Etwas komplexer ist die Codebehind Logik. Datenbank abfragen, Rechnungsliste abfragen und dann per SQL das oder die passenden Dokumente laden.

   1:  Public Async Function ListView1_GetData() As Threading.Tasks.Task(Of List(Of rechnung))
   2:          Dim db As Database
   3:          db = _client.CreateDatabaseQuery().Where(
   4:  Function(x) x.Id.Equals("miniSAP")).AsEnumerable().FirstOrDefault()
   5:   
   6:          Dim col As DocumentCollection
   7:          col = _client.CreateDocumentCollectionQuery(db.SelfLink).Where(
   8:  Function(c) c.Id.Equals("Rechnungen")).ToArray).FirstOrDefault
   9:   
  10:          Dim q = _client.CreateDocumentQuery(Of rechnung)
(col.SelfLink, "select * from Rechnungen").ToList
  11:   
  12:          Return q
  13:  End Function

 

Azure DocumentDB  macht die ORM Brücke Entity Framework überflüssig. Die Objekte stecken eben in der Datenbank. Die Programmierung geht leicht von der Hand. Allerdings muss der Entwickler komplett umdenken und das wird das größere Problem darstellen. Zusätzlich stellt sich die Frage was wir gewonnen haben. In diesem Fall nichts. Wenn man aber Amazon ist und pro Sekunde hunderte derartige Transaktionen durchführen will, könnte documentDB das Leben leichter machen. Dieser Azure Service steht  noch am Anfang.

Danke an Rainer Stropek für review.

WPF mit Expression Blend

Zum Schulungsangebot gehört auch eine 2tägige Blend Schulung. Eigentlich adressiert dieser Kurs eher Designer und fokussiert das Werkzeug Expression Blend. Immer öfter wird aber Blend das Programmierer Tool und die UI Designer machen nach wie vor Photoshop. Im letzten Expression Blend Training saß nur ein Kurs Teilnehmer und schnell wurde aus einer Schulung eine coworking Fragerunde.

Konkret taucht die Frage auf, wie man den Inhalt der RadioButtons abhängig vom Check Status darstellt. Je nachdem ob man Silverlight, METRO Apps oder WPF Desktop Anwendungen adressiert, fällt die Antwort unterschiedlich aus. WPF setzt von Anfang an auf Trigger um Status Änderungen wie Hoover zu verwalten. Die neuere Technologie aus Silverlight ist der ViewStateManager. Diese States sind zwar in WPF nun möglich, aber die Templates der Standard Controls verwenden immer noch Trigger.

Hier wird nun gezeigt, wie mit Expression Blend die Vordergrund Farbe des Textes eines Option Steuerelements am einfachsten verändert.

Zuerst wird ein Radio Button Steuerelement aus der Werkzeugleiste auf das Formular gezogen oder per Doppelklick erzeugt. Das Control erscheint nun im Designer und in der Objects und Timeline Übersicht.

image

Entweder dort, im Designer oder im Objects Bereich wird per Recht klick im Kontext Menü der Eintrag “Edit Template”  und daraus “Edit a Copy” ausgewählt. Blend generiert aus dem Control den kompletten XAL Code der das UI des Steuerelements beschreibt. In Summe werden das knapp 100 Zeilen XAML Code.

Um das Style Template global verfügbar zu machen, wird keine ID vergeben (apply to all). Die zuweisung erfolgt im XAML Implizit über die TargetType Eigenschaft für alle passenden Controls. Je nachdem ob man im Dokument oder in der Anwendung das Style erzeugen lässt mit entsprechender hierarchischer Gültigkeit.

image

Hier werden nun alle Radiobuttons im aktuellen XAML Dokument neu gestylt.

Da man im Editor sowohl Eigenschaften des Controls, wie Farbe, als auch im Template arbeiten kann, muss der Benutzer die Breadcrumb Navigation am oberen Rand im Auge behalten.

Folgendes zeigt, das man sich sozusagen im Template befindet.

image

Im seitlichen Bereich Objects und Timeline werden deshalb die Bestandteile des Steuerelements aufgelistet.

image

So kann man den Auswahl Nubbel, der üblicherweise ein schwarzer Kreis ist, zu einem grünen Kreis umfärben. Das das Ding ziemlich klein und zierlich ist zoomt man am besten richtig ran (hier 800%)

image

Dabei fällt auf, das der Kreis weis bleibt. Das liegt daran das dieser aktuell, da nicht ausgewählt, transparent ist. Genauer gesagt wird die Opacity per Trigger gesteuert. Um an die passende Stelle im Blend WPF Editor zu kommen wählt man den Tab Trigger aus.Der Editor wird rot umrahmt und befindet sich nun im Recording Modus. Hier am besten Finger weg vom Formular. Der Fokus liegt auf dem Trigger ischecked=true. Dieser löst eine Veränderung der Opacity Eigenschaft aus. 1 steht für gefüllt, also das Gegenteil von 0 und transparent. Deswegen ist der Nubbel nun auch grün.

image

Die eigentliche Frage der Teilnehmerin zielt aber auf den Text rechts von der Auswahl. Dieser soll auch grün werden. Das Problem dabei ist, das es sich aber nicht immer um Text handeln muss, da der komplette XAML Subtree aus dem Content Bereich des eigentlichen UI Elements dort im Template an die Stelle des ContentPresenters eingefügt wird. Das ganze nennt sich Template Binding.

Trotzdem klappt es die Farbe des Textes über das Attribut Foreground zu setzen. Dabei wird aber nicht der Content Bereich sondern das umgebende Content Control benutzt.

Beim auslösen des Triggers soll so eine weitere Eigenschaft des Grid verändert werden, dies ist templateroot benannt und wird in den Objektbaum ausgewählt.

image

Nun wird zunächst die Eigenschaft Hintergrund auf Grün verändert. Dies vor allem weil die gesuchte Eigenschaft Foreground nicht angeboten wird.

image

Nicht nur das der komplette Bereich des Radiobuttons nun grün ist, wird auch in den Triggern ein weiterer Eintrag hinzugefügt.

image

Jetzt fehlt nur aus Background den Foreground zu zaubern. Das kann Blend für Visual Studio 2013 nicht per click. Außerdem fehlt es an der direkten Eigenschaft, diese muss per Attached Property TextElement.Foreground quasi reingemogelt werden. Dies kann im XAML Quellcode Editor einfach ersetzt werden.

image

Im Trigger Eigenschaftsfenster wird die neue Eigenschaft korrekt angezeigt und die WPF Anwendung verhält sich korrekt.

image

Azure Website Connection Fehler

Dieser Blog Post dient nur zur Dokumentation eines SQL Connection Fehlers in Azure.

Nach einem Publish der Web Anwendung auf eine Azure Website, liefert die Website folgenden Fehler

Server Error in '/' Application.

Invalid object name 'rooms'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'rooms'.
Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[SqlException (0x80131904): Invalid object name 'rooms'.]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +1787814
   System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +5341674

 

Der Kollege hat aus einem Irrtum heraus, eine lokale Kopie deployed die per localdb mit einer SQL Express Datenbank gearbeitet hat. Nach manueller Änderung der web.config auf Azure selbes problem. Die Anwendung läuft lokal aber durchaus mit der SQL Azure Datenbank.

Erinnerungsgemäß hat mich ein ähnlicher Fehler schon mal Stunden gekostet. Damals hatte ich irgendwas gelöscht. Nur weis ich nicht mehr was und wo.

Check All Checkboxen mit AngularJS

Wieder einmal komme ich von einer Angular.JS Schulung nach Hause. Wieder einmal hatten die Teilnehmer des Trainings durchaus Probleme die Konzepte von Angular mit ihren bestehenden Skills zu verbinden. Konkret ging es um den Anwendungsfall eine Liste von HTML Checkboxen mit einem Klick zu aktivieren. Bei der Rückreise vom Angular Kurs mit der Bahn, hat man Zeit darüber nachzudenken und das Ergebnis ist nicht was man erwarten würde.

Kennen Sie den? Wer einen Hammer besitzt, für den ist das Leben voller Nägel. Kann man so interpretieren, das man das tut was man kann. In einer Angular Single Page Application ist das ein HTML View und ein Viewmodel Scope per JavaScript Controller. Dieser stellt die Methoden bereit um aus dem View Änderungen am Scope bla bla bla.

Schon sind wir in ein kleines Buzz Word Bingo mit Angular eingestiegen. Also lassen sie uns einen Schritt zurück treten. Worum geht es eigentlich in einer Web Site? Das völlig konstruierte Beispiel hat folgende Benutzer Anforderungen.

  • Eine Liste Namen anzeigen
  • max 2 Namen einzeln auswählen
  • die ausgewählten Namen zählen und anzeigen
  • Alle Namen aus oder abwählen können

Mancher JavaScript Developer fängt nun an Tests zu schreiben, andere einen Controller. Ich bin der visuelle Typ und zeichne das UI zuerst.

image

Der dazu notwendige Angular.JS Controller

   1:   angular.module('App', [])
   2:          .controller('myController', function ($scope) {
   3:              $scope.liste = [{ wert: "hannes", checked: false },
   4:                  { wert: "maria", checked: true },
   5:                  { wert: "franz", checked: false },
   6:                  { wert: "Hias", checked: false }];
   7:          });

 

Nun könnte man in den Controller einen Watcher einbauen, der die Liste überwacht und bei Änderung einen Zähler anwirft. Der Wert wird dann einer Scope Variablen zugewiesen. Noch wach?

Warum muss sich eine User Interface Geschichte im Controller abspielen? Wo steht das geschrieben?

Angular ist relativ mächtig, wenn es um Datenbindung per Expressions geht. Ausgehend von der Liste der Namen wird mit einem Filter Ausdruck nur die ausgewählten selektiert. Einmal Klammer außen rum und mit lengt die Anzahl ausgeben.

   1:  gesamt {{(liste | filter:{'checked':true}).length }} 

 

Das Ergebnis sieht man am obigen Bild. Well die Grundidee durchaus bestechend ist, wird das gleiche Konzept verwendet um bei mehr als einem ausgewählten Namen die übrigen zu deaktivieren. So kann der Benutzer maximal zwei Namen auswählen, aber die gewählten auch wieder deaktivieren.

   1:  <x ng-repeat="mensch in liste">
   2:     <input type="checkbox" name="test" class="chklist"
   3:         ng-model="mensch.checked"  
   4:         ng-disabled="mensch.checked==false && 
(liste | filter:{'checked':true}).length>1"
   5:     />{{mensch.wert}}
   6:  </x>

Auch das kann man im Screenshot oben erkennen, hannes und hias sind graue Boxen.

Ausgerüstet mit der Erkenntnis, das nicht alles Angular Code Behind sein muss, nun die letzte Aufgabe. Wie kann man alle Checkbocen anhaken oder eben nicht. Wenn man im UI bleibt, ist JQuery das beste Tool um  DOM Manipulationen vorzunehmen. Dafür gibt es verschiedene Selektoren, über ID oder Typ oder eben CSS Klassen, hier chklist genannt.

   1:<input type="checkbox" onclick=" $('.chklist').prop('checked', this.checked)" />Alle<br />

 

Cool oder? Alternative Lösungen die im Web diskutiert (oder gebloggt ) werden kommen auf ein vielfaches an Code.

Eine kleine Randnotiz. JavaScript’s fähigkeiten Objekte zu jeder Zeit zu erzeugen wird mit Angular.js noch magischer. Obiges Beispiel funktioniert auch ohne die checked Eigenschaft der Liste.

   1:   $scope.liste = [{ wert: "hannes" },
   2:                  { wert: "maria" },
   3:                  { wert: "franz" },
   4:                  { wert: "Hias"}];
Training, Schulung, April Aktion

Month List