Alt und bewährt vs. Neu und innovativ

 Windows Forms  vs. WPF …

 Kennen Sie auch das Sprichwort, dass Developer keine guten Designer sind? Vor allem Projektleiter trifft diese Problematik öfter, da sie die Aufgaben für ein gesamtes Projektteam sinnvoll verteilen müssen und oftmals keiner die GUI mit übernehmen will. Insbesondere bei WinForms ist es schwer, die grafische Benutzeroberfläche vom eigentlichen Programmcode zu trennen. In WPF hingegen kann die GUI komplett vom eigentlichen Programmcode getrennt werden.

Die Windows Presentation Foundation ist im Gegensatz zum bisher gängigen WinForms ein GUI Framework, welches auf allen Auflösungen und Größen gut dargestellt wird. Die gesamte grafische Benutzeroberfläche wird komplett vom Programmcode getrennt und kann so völlig unabhängig vom eigentlichen Programm entwickelt werden. Die GUI wird in der Auszeichnungssprache XAML (Extensible Application Markup Language) beschrieben. In XAML werden die Oberflächenhierarchien deklarativ als XML Code dargestellt. Somit ist es möglich, eine Version einer GUI für verschiedenste Technologien zu verwenden. Das Recyceln einer GUI ermöglicht eine effizientere Entwicklung, da man nun auf bereits bestehende Elemente einer Benutzeroberfläche zurückgreifen kann. Der XAML Code kann hierbei sowohl in einem einfachen Texteditor als auch in komplexen IDE’s wie Visual Studio entwickelt werden. Speziell für Designer bietet Microsoft das Softwarepaket Expression Blend an, wofür die ppedv auch einen zweitägigen Kurs anbietet, welches ein vielseitiges Baukastensystem für die Erstellung komplexer grafischer Benutzeroberflächen mithilfe von Drag & Drop bereitstellt.

Ohne tiefgreifende Programmierkenntnisse muss ich mit WinForms meine Grafische Benutzeroberfläche mithilfe des Baukastensystems zusammensetzen. Mithilfe von WPF bzw. XAML kann ich durch die leicht zu verstehende Syntax schnell und professionell Grafische Oberflächen in Form von Code schreiben.

Am folgenden Beispiel zeige ich wie leicht sich eine Grafische Oberfläche erstellen lässt. Für das Beispiel habe ich einen farbigen Button mit Farbverlauf, eine Textbox und eine Passwordbox eingefügt. Und jeder schonmal in WinForms einen Farbverlauf erstelle hat, weiß wie kompliziert das geht, doch in WPF eine Sache von vier einfachen Zeilen. Für die schönere Darstellung habe ich das ganze in 3 “Row” (Zeilen) aufgeteilt die egal bei welcher Fenstergröße in diesem dynamischen Verhältnis bleiben werden.

image

Und hier der XAML Code dazu.

   1: <Window x:Class="WpfApplication1.MainWindow"
   2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:         xmlns:ee="http://schemas.microsoft.com/expression/2010/effects"
   5:         Title="WPF-Beispiel" Height="350" Width="525">
   6:     <Grid>
   7:         <Grid.RowDefinitions>
   8:             <RowDefinition></RowDefinition>
   9:             <RowDefinition></RowDefinition>
  10:             <RowDefinition></RowDefinition>
  11:         </Grid.RowDefinitions>
  12:         <Button Grid.Row="0" FontSize="30" Content="Das ist ein farbiger Button" Margin="10" >
  13:             <Button.Background>
  14:                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
  15:                     <GradientStop Color="Red" Offset="0"/>
  16:                     <GradientStop Color="Yellow" Offset="1"/>
  17:                 </LinearGradientBrush>
  18:             </Button.Background>
  19:  
  20:         </Button>
  21:         <TextBox Grid.Row="1" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center">Das hier ist eine Textbox</TextBox>
  22:         <PasswordBox Grid.Row="2"></PasswordBox>
  23:     </Grid>
  24: </Window>

Mit WPF habe ich nicht nur die Möglichkeit leicht, anspruchsvolle dynamische Grafische Oberflächen zu erstellen, zusätzlich steht mir noch ein breites Spektrum an Effekten und Designmitteln zur Verfügung sowie vielseitige Möglichkeiten von Animationen. Die Effekte und Animationen kann ich entweder über XAML oder aber auch über den eigentlichen Programmcode steuern. Wer mehr über die ganze Thematik wissen will kann sich gerne den 4 tägigen WPF Kurs der ppedv anschauen.

Viele werden sich jetzt denken:”Warum soll ich von meinem funktionierenden System jetzt umsteigen und was neues verwenden?”. Die Antwort ist eigentlich ganz einfach:”Mehr Möglichkeiten, bessere Anpassung an alle Auflösungen, dynamische vektorbasierte Darstellung und vieles vieles mehr”.

EF: “There ist already an open DataReader associated with this Command…”

Manchmal erlebt man als Entwickler seine Überraschungen. Mein heutiges Learning: kleine Änderungen haben eine große Auswirkung.

Aber der Reihe nach. Ich habe ein simples WebAPI Projekt das Daten aus einer Datenbank holt und intern aufbereitet, so dass eine geeignete Objektstruktur zurückgeliefert wird und ich in der JavaScript Anwendung nicht viel machen muss.

Im Code wird eine LINQ Abfrage ausgeführt und für jedes Element der Ergebnismenge wird in einer Schleife eine weitere LINQ Abfrage durchgeführt. D.h. von der äußeren Abfrage ist der Datareader offen und innerhalb der Schleife kann kein neuer geöffnet werden.

1 var header = from h in ctx.FeedbackSeminarFeedbackHeaders 2 where h.SeminarAppointmentID == AppointmentID 3 select h; 4 5 foreach(var fh in header) 6 { 7 FeedbackHeader hd = new FeedbackHeader() 8 { 9 Firma = fh.FirmenName, 10 Teilnehmer = fh.FirstName + " " + fh.LastName, 11 Datum = fh.Date.Value, 12 Anmerkung = fh.Note + " " + fh.Opinion, 13 Trainer = appointment.Trainer, 14 Ort=appointment.Location, 15 Seminar=appointment.Seminar 16 }; 17 var fragen = from f in ctx.FeedbackSeminarFeedbackAnswers 18 where f.FeedbackID == fh.ID 19 orderby f.QuestionCategoryID, f.Sort 20 select f; 21 22 foreach(var fr in fragen) 23 { 24 hd.Fragen.Add(new FeedbackAnswer{ 25 Frage = fr.Question, 26 Antwort=fr.Answer, 27 Sort = fr.Sort.Value 28 }); 29 } 30 ret.Add(hd);
Die Fehlermeldung tritt in Zeile 22 auf.

Zu meiner heutigen Überraschung stellte ich fest, dass der Code lokal ausgeführt funktioniert aber wenn das Projekt auf Azure gehosted wird nicht mehr! Beide Varianten greifen auf die selbe Datenbank zu. Somit konnte ich Datenungleichheiten ausschließen.

Meine erste Überlegung war, dass Azure anders ist. Und zumal ich ja am Code nichts geändert habe, dieses Projekt bereits funktioniert hatte, kann es ja nur der “böse Azure-Admin” gewesen sein, der ein neues Update eingespielt hat.

Nichts von dem war es: Im Connectionstring fehlte der Eintrag: MultipleActiveResultSets=True;

In der lokalen Web.config Datei war er eingetragen, daher funktionierte der Code. In der Web.Config für Azure war zwar die selbe Datenbank angegeben, aber der Eintrag fehlte. Früher hat das Projekt aber funktioniert. Das ist leicht erklärt: vor ein paar Wochen wurde der SQL Server getauscht. Ich passte den Config Eintrag an, und dabei habe ich wohl den MultipleActiveResultSets-Eintrag überschrieben. Natürlich tritt der Fehler nur an einer wenig genutzten Funktion der Anwendung aus. Worauf er nicht gleich gesehen wurde…. usw. wir kennen das. Wieder mal ein Grund für umfangreiche UnitTests…

Geht es auch ohne MultipleActiveResultSets=True;?

Ja. Es muss nur sichergestellt werden, dass die LINQ Abfrage gleich komplett ausgeführt wird. Das kann man erreichen indem die Ergebnismenge gleich mit der Funktion .ToList() in eine neue Liste geschrieben wird. Dann ist der DataReader auch gleich wieder geschlossen und steht für die nächste Abfrage zu Verfügung.

Also sieht die Abfrage nun so aus:

1 var header = (from h in ctx.FeedbackSeminarFeedbackHeaders 2 where h.SeminarAppointmentID == AppointmentID 3 select h).ToList();

Visual Studio User Group Wien– Unterlagen

Danke für die Teilnahme am Usergroup Meeting in Wien gestern Abend (23.4.2015)

Wie versprochen die Linksammlung:

Präsentation: http://1drv.ms/1JjpvV3

ChromeControl: http://blog.ppedv.de/post/2013/06/21/ChromeControl-in-Provider-Hosted-App-einbinden.aspx

Cross Domain Lib: http://blog.ppedv.de/post/2013/08/29/SharePoint-2013-App-Zugriff-auf-das-HostWeb-mittels-Javascript.aspx

Konfiguration für Apps: http://blog.ppedv.de/post/2013/10/29/sharepoint-2013-server-fur-app-development-vorbereiten.aspx

Microsoft Office 365

Seit längerer Zeit werden wir Trainer oft mit dem Thema Office 365 konfrontiert, doch nur wenige wissen genau was Office 365 ist und welche Funktionen die Webanwendung zur Verfügung stellt.

In diesem Blogeintrag werden wir Office 365 vorstellen und einige Funktionen genauer erläutern:

Office 365 ist grundsätzlich eine Kombination aus Office-Webanwendungen, Serviceleistungen und einem Office-Software-Abonnement. Der Grundgedanke hinter dieser Sammlung an Webanwendungen ist die dauerhafte Verfügbarkeit des Microsoft Office-Paketes. Getreu dem Motto „Office zu jeder Zeit, an jedem Ort“ kann man Office - Anwendungen über das Internet auf allen Endgeräten, wie zum Beispiel einem Desktop-Rechner, einem Laptop, einem Smartphone oder einem Tablet, ohne eine vorherige Installation verwenden. Mithilfe eines Microsoft-Accounts kann ein Benutzer somit jederzeit auf die Office-Webanwendung zugreifen.

Microsoft Office 365 wird im Gegensatz zu Konkurrenzprodukten, wie zum Beispiel Google Apps, mit mehreren Tarifen angeboten. Der kostenlose „Office Online“ Tarif stellt dem Benutzer die Funktionen von Word, Excel, Outlook, OneNote und PowerPoint als Webanwendung zur Verfügung. Die kostenpflichtigen Tarife, die sich zumeist an kleine oder mittelständische Unternehmen richten, bieten darüber hinaus noch erweitere Funktionalitäten, wie zum Beispiel Websitepostfächer, Office-Desktopanwendungen oder VoIP für den regulären Unternehmensbetrieb an.
Microsoft garantiert hierbei eine Verfügbarkeit von 99,9% für alle zur Verfügung gestellten Webanwendungen.

Die Vorteile von Microsoft Office 365 liegen klar auf der Hand: Da alle Programme in der Basisversion im Webbrowser dargestellt werden, muss man sich nicht um lästige Softwareinstallationen und zeitraubenden Updates kümmern. Alle Webanwendungen sind immer am neusten Stand und die Dokumente können in einer 15GB großen OneDrive Cloud gespeichert werden. So hat man seine Dokumente und Werkzeuge immer dabei, egal ob man auf dem Tablet, auf dem Desktop-PC oder auf dem Smartphone arbeitet.

Sie möchten mehr zu Office 365 erfahren? ppedv teilt Wissen auch in Form von Office 365 Schulungen.

Verfasst von Marko Bradaric und Michael Zöhling

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.

Wie ein guter Domänen-Name aussieht – und wie nicht.

Auf den ersten Blick klingt das für viele sicher nach einer trivialen Frage: “Wie soll die neue AD Domäne denn heißen?” – aber so trivial ist diese Frage gar nicht.

Zunächst einmal muss man sich natürlich an die Vorgaben halten:

  • Der volle Domänenname (“Fully Qualified Domain Name, FQDN”) darf maximal 255 Zeichen lang sein und darf dabei aus Kleinbuchstaben, Großbuchstaben, Zahlen und dem “-”-Zeichen bestehen. Pro Label sind 63 Zeichen zulässig.
  • Der NetBIOS Name der Domäne ist auf 15 Zeichen beschränkt sowie auf Unicode-Zeichen und ein paar wenige Sonderzeichen

Ein AD Domänen-Name ist immer auch ein DNS-Name. Ein Domänen-Name besteht daher in der Regel aus einem oder mehreren Präfixen und einem Suffix, nach dem Aufbau-Prinzip

Präfix1.Präfix2.Suffix

Nun findet man heute sehr viele Domänen-Name nach dem Aufbau “Firma.local”, “.site”, “.lan” und so weiter. Die Wahl dieses Namens ist in der Regel auf die frühere Empfehlung, als Suffix keine öffentlichen Internet-Toplevel-Domänen wie “.com”, “.net” oder “.de” zu verwenden, da es sonst zu dem Problem kommt, dass man eine gesplittete DNS-Verwaltung benötigt oder aus dem internen Netz heraus eine Webseite nicht erreichen kann, wenn diese aus dem selben Prä- und Suffix besteht.

Diese Empfehlung hat heute keine Gültigkeit mehr!

Erstens werden auch diese “selbsterdachten” Suffixe mittlerweile von den Anbietern als Toplevel-Domänen verkauft. Das von einem selbst verwendete “FIRMA.LOCAL” könnte also zeitnah Eigentum einer anderen Firma werden! Und zweitens gibt es in gewissen Szenarien ganz klare Vorgaben, die die Verwendung dieser selbsterdachten Suffixe verbieten. Eines davon ist, dass keiner der großen SSL-Zertifikat-Anbieter Zertifikate für derartige Domänen- oder Hostnamen mehr ausstellt! (Vergleich dazu auch: https://www.cabforum.org/Guidance-Deprecated-Internal-Names.pdf)

Also, wir halten zunächst fest: “.site”, “.local” oder ähnlich sind keine guten Suffixe! Besser ist es, offizielle TLD-Suffice wie “.com”, “.net” oder “.de” zu verwenden.

Aber was ist dann mit dem oder den Präfix(en)?

Wie wäre es, wenn man nun als “Firma Foo”, die “www.foo.com” als Webseite verwendet, “foo.com” als internen Domänennamen wählt? Das kann (besser: wird) zu Problemen führen. Hierzu ein kleines Beispiel:

Wenn ein Benutzer sich an einer Workstation innerhalb einer Domäne anmeldet, dann ist hierbei der Name (z.T. auch nur der NetBIOS-Name) der Domäne angegeben. Der Computer muss aber einen Domänencontroller kontaktieren können. Daher wird der Domänen-Name in den Namen eines DCs und dieser wiederum in eine IP-Adresse eines DCs übersetzt. Also, aus “foo.com” wird dann die IP eines DCs, hinter “foo.com” verbirgt sich ebenso die interne DNS-Zone.

Und was passiert, wenn nun jemand in dieser Firma “foo.com” in seinen Browser eingibt? Seine Browser würde versuchen, einen DC per HTTP anzusprechen, was in der Regel scheitert, weil ein DC kein Webserver ist!

Nun gibt es für den (ersten) Präfix zwei Optionen:

  • Man registriert eigens für diesen Zweck eine öffentliche Domäne, die aber nicht öffentlich sondern nur für die interne AD Domäne genutzt wird
  • Man nutzt eine Subdomäne einer bereits existierenden Domäne, die man auch öffentlich verwendet, im Idealfall die, die auch für die Webseite genutzt wird.

Wenn also “Firma Foo” die Domäne “foo.com” als Domäne für ihre Webseite nutzt, dann müsste der Name der obersten (ersten) interne AD-Domäne ABC.foo.com heissen. Dabei sollte “ABC” ein möglichst kurzes Wort sein, um die FQDN aller kommenden AD-Objekte nicht unnötig lang zu machen. Eine Option wäre z.B. “AD.FOO.COM”.

Damit nun bei der Anmeldung nicht “AD\User” sondern “FOO\User” genutzt wird, muss man einfach bei der Installation des ersten (!) Domänencontrollers der Domäne als NetBIOS-Namen anstatt des vorgeschlagenen “AD” das Wort “FOO” verwenden. (Achtung: Das nachträgliche Ändern des NetBIOS-Namen ist nicht trivial!)

Die Verwendung eines solchen DNS- und Domänen-Namens hat viele Vorteile:

  • Es muss nur ein einziger Domänen-Name (auf oberster Ebene) genutzt und verwaltet werden
  • Eine Trennung zwischen intern und extern ist problemlos möglich
  • Jeder interne Domänen- und Hostname ist weltweit einmalig (wer kann das bei “SERVER1.corp.local” schon behaupten?)
  • Für Zertifikate, E-Mail und co., wo naturgemäß externe Domänen nötig sind, ist bereits alles passend
  • Eine Anmeldung an den Systemen des Unternehmens kann mit der (öffentlichen) E-Mail-Adresse der Benutzer erfolgen. Niemand muss sich neben seiner Mail-Adresse noch einen (u.U. komplizierten) Benutzernamen merken.

Als Referenz und zum Weiterlesen empfehle ich folgende Links:

Callback Hell ? Promises in JavaScript !

Vielleicht kennen Sie das – sie möchten Teile Ihrer Webseite mittels AJAX asynchron nachladen. Problematisch ist dabei nur, dass sie auf mehrere unterschiedliche Ressourcen zugreifen müssen die irgendwie voneinander abhängig sind und daher die AJAX Aufrufe verschachtelt werden müssen. Dieses Phänomen bzw. diese Problematik ist in der Webentwicklung auch als ‘Callback Hell’ oder ‘Pyramid of Doom’ bekannt.

Aushilfe liefern in diesem Fall Promises in JavaScript. Im Gegensatz zu aynchronen Funktionen, die das jeweilige Ergebnis des Funktionsaufrufes an einen Callback-Handler übergeben, sind Promises Objekte, die selbst das Ergebnis einer asynchronen Funktion enthalten. Das Promise Objekt verfügt schließlich über zwei Methoden: resolve() um über das Ergebnis zu informieren und reject() um über den Fehler zu informieren. Die native Implementierung von Promises in Ecmascript 6 hat die folgende Syntax:

var promise = new Promise(function(resolve, reject){
     var berechnung = 99; // asynchrone Berechnung hier   
     if (berechnung < 42) {
           reject('Die Berechnung ist kleiner 42');
     } else {
           resolve(berechnung);
     }
});

Das Promise Objekt kann intern drei Zustände annehmen:

  1. Pending: Die Funktion ist noch nicht fertig ausgeführt, Warten
  2. Fulfilled: Die asynchrone Funktion wurde erfolgreich ausgeführt, Erfüllt
  3. Rejected: Die asynchrone Funktion wurde nicht erfolgreich ausgeführt, Abgelehnt

Der wesentliche Vorteil von Promises liegt also darin, dass keine Callbacks mehr notwendig sind. Die Parameter werden als nicht mehr an eine Callback Funktion übergeben, sondern an das Promise Objekt. Dadurch ist ein Verketten von Funktionen möglich. Promises bieten die Methode .then() an, um das Ereignis schließlich zu behandeln.

asyncFunction().then(
   function(success){
      console.log(success);
   },
   function(error){
      console.log(error)
   }
);

 

Das Konzept von Promises ist in der Programmierung schon seit Mitte der 1970er Jahre bekannt. In JavaScript halten sie in Ecmascript 6 Einzug. Aktuell befindet sich ES6 noch im Entwicklunsstadium, weshalb native Promises noch nicht von allen gängigen Browsern unterstützt werden. Es gibt jedoch einige JavaScript Bibliotheken, wie jQuery, die sich um diese Problematik bereits vor ein paar Jahren angenommen haben. Abschließend noch ein kurzes Beispiel für ein Promise mit jQuery:

// 1. 
var getCustomer = $.ajax({
    type: 'GET',
    url:'../../data/customer.json'
});

// 2.
getCustomer.then(
    function(data){
        console.log(data);
    }, function(xhr, state, error){
        console.log(arguments);
    }
);

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.

Training, Schulung, April Aktion

Month List