Marco Scheel: Links for 2016-08-26 [del.icio.us]

  • blog.mastykarz.nl
    Recently Microsoft announced the SharePoint Framework - a new model for building SharePoint customizations. Although it hasn't been released yet, you can already start preparing for it and here is what you should learn. via Pocket
  • Internet of Things - Do It Yourself, Home Automation - Microsoft Virtual Academy
    Resources To download all course materials, select the compressed .zip file below and click download. To download individual course materials, select the checkbox next to each file that you'd like to download and click download. via Pocket
  • OpenID Certification | OpenID
    The OpenID Foundation enables implementations of OpenID Connect to be certified to specific conformance profiles to promote interoperability among implementations. The foundation’s certification process utilizes self-certification and a conformance test suite developed by the foundation. via Pocket
  • Node Hero - Node.js Project Structure Tutorial | @RisingStack
    This is the 7th part of the tutorial series called Node Hero - in these chapters, you can learn how to get started with Node.js and deliver software products using it. Most Node.js frameworks don't come with a fixed directory structure and it might be challenging to get it right from the beginning. v

Marco Scheel: Links for 2016-08-25 [del.icio.us]

Holger Schwichtenberg: Veranstaltungen für .NET- und Visual-Studio-Entwickler im Herbst 2016

Auch in diesem Herbst gibt es in Deutschland wieder einige Entwicklerkonferenzen für Softwareentwickler, die mit Microsoft-Werkzeugen wie Visual Studio und Visual Studio Code entwickeln.

Johannes Renatus: AngularJs TypeScript Interceptor Template

AngularJs bietet ein interessantes Konzept um AJAX Requests bzw. Response zu manipulieren oder zu prüfen ob ein Response bestimmte Daten enthält. Das ganze nennt sich HTTP Interceptor. Ich verwende es z.B. für die folgenden Aufgaben in meinen Projekten Prüfen ob im Response eine Meldung enthalten ist die angezeigt werden soll, wenn diese vorhanden ist, existiert […]

Marco Scheel: Links for 2016-08-23 [del.icio.us]

Marco Scheel: Links for 2016-08-22 [del.icio.us]

Marco Scheel: Links for 2016-08-21 [del.icio.us]

  • Why does my Authorize Attribute not work? | leastprivilege.com
    Sad title, isn’t it? The alternative would have been “The complicated relationship between claim types, ClaimsPrincipal, the JWT security token handler and the Authorize attribute role checks” - but that wasn’t very catchy. via Pocket
  • Accounts
    During initial device setup, users are required to sign in with the account they want to use on the device. This account can be either a consumer Microsoft account or an enterprise account that has been configured in Azure Active Directory (AAD) or Active Directory Federation Services (ADFS). via Poc
  • All pages
    This is a list of all pages in the Windows Holographic documentation as of 2016-05-31. via Pocket
  • PowerShell on Linux and Open Source! | Windows PowerShell Blog
    Since its inception in 2002 PowerShell has been deeply influenced and improved by the passion and needs of our community. As an example, 80 contributors filed bugs and issues on the “alpha” release. via Pocket
  • Migrate traditional Distribution Groups to Office 365 Groups - You Had Me At EHLO…
    Over the past few months, customers are increasing both the number of Office 365 Groups created and average monthly usage. It’s great to see customers getting value out of the service. via Pocket
  • Object moved
    Today’s customers live in a multi-platform, multi-cloud, multi-OS world - that’s just reality. This world brings new challenges and customers need tools to make everything work together. via Pocket
  • PowerShell on Linux and Open Source | The Hybrid IT Management Channel | Channel 9
    Continuing the commitment to enable an open and flexible platform that meets customers where they are, Microsoft has now open sourced PowerShell and made it available on Linux and macOS. via Pocket

Marco Scheel: Links for 2016-08-20 [del.icio.us]

Sven Hubert: Qualität als Konzept: Qualitätsmetriken in Visual Studio

Um Qualität in Software zu erreichen, muss diese auch messbar sein. Doch wie lässt sich das am einfachsten machen? Was viele hier vergessen, ist, dass bereits Visual Studio die Anzeige von Qualitätsmetriken anbietet. In diesem Teil der Blog-Serie soll gezeigt werden, wie man mit Visual Studio Qualitätsmetriken anzeigt, was diese bedeuten und wie man diese auch automatisiert prüfen kann.

Codemetriken

Visual Studio bietet die Möglichkeit, Codemetriken zu berechnen, und das schon seit Version 2008. Was früher nur in der VS Premium Version vorhanden war, gibt es heute schon mit VS 2015 Community. Codemetriken können einfach für eine ganze Solution oder für ausgewählte Projekte berechnet werden. Die Option hierfür findet man unter Analyse –> Calculate Code Metrics.

image
Visual Studio: Codemetriken berechnen

Das Ergebnis der Berechnung wird dann in einem separaten Fenster ausgegeben. In diesem kann man fünf Qualitätsmetriken sehen: Maintainability Index (MI), Cyclomatic Complexity (CC), Depth of Inheritance (DoI), Class Coupling (CP) und Lines Of Code (LOC). Jeder dieser Metriken wird pro Projekt, Namespace, Klasse und Methode berechnet. Die Ergebnisse können nach Wertebereich zu einer Codemetrik gefiltert werden. Zusätzlich gibt es noch einen Export nach Excel. Nützlich ist auch das direkte Anlegen eines Work Items aus den Ergebnissen heraus. Dabei wird für die selektierte Zeile ein Work Item angelegt, welches das analysierte Projekt, den Scope (Namespace, Klasse, Methode), die Konfiguration (Debug, Release) und die einzelnen Codemetriken automatisch hinterlegt. Dieses Work Item kann dann dazu verwendet werden, um ein Refactoring einzuplanen, welches diese Codemetriken verbessert.

image
Visual Studio: Ergebnis der Codemetriken

Cyclomatic Complexity
Die Cyclomatic Complexity zeigt, wie viele Ausführungspfade es gibt. Je höher die Anzahl Pfade, desto komplexer das Projekt. Je mehr Pfade es gibt, desto höher ist auch die Anzahl an Tests, die diese Pfade abdecken. Die Anzahl Pfade kann nicht unbedingt verringert werden, aber ausgelagert in andere Methoden oder Klassen. Dadurch gibt es zwar mehr Methoden, jedoch sind diese von der Komplexität einfacher zu verstehen.

Depth of Inheritance
Die Depth of Inheritance gibt an, wie tief die Hierarchie einer abgeleiteten Klasse ist. Dabei ist der Standardwert einer Klasse immer eins. Für den Namespace und das Projekt wird jeweils der maximale Wert über alle Klassen verwendet. Je tiefer die Hierarchie einer Klasse, desto komplexer ist diese, bietet auf der anderen Seite jedoch auch eine bessere Wiederverwertbarkeit. Bei der Berechnung der Depth of Inheritance werden nur Klassen und keine Interfaces betrachtet.

Class Coupling
Class Coupling beschreibt, wie viele andere Klassen innerhalb einer Methode oder Klasse verwendet werden. Anhand der verwendeten Klassen kann man erkennen, ob eine Klasse zu viele Abhängigkeiten besitzt, die aufgelöst werden müssen. Dadurch erkennt man auch, ob eine Klasse zu viel Verantwortung hat, die in mehrere Klassen geteilt werden sollte. Bei der Berechnung von Class Coupling gilt zu beachten, dass es hier bestimmte Ausnahmen gibt, wie z.B. gewisse Value Types (string, int, double), die nicht zur Metrik hinzugenommen werden. Das bedeutet jedoch nicht, dass struct’s nicht zum Class Coupling dazugezählt werden.

Lines Of Code
Die Lines of Code können darauf hindeuten, dass ein Projekt, eine Klasse oder eine Methode zu groß ist und aufgeteilt werden sollte. Wie lang zu lange ist, da scheiden sich die Geister. Ein guter Richtwert ist jedoch 100 LOC pro Methode und 1000 LOC pro Klasse als Maximum. Innerhalb der Codemetriken sind die LOC nicht die wirklichen Zeilen C#-Code, sondern vielmehr die Zeilen IL-Code die beim Kompilieren erzeugt werden. Das hat den Vorteil, das zusätzliche Leerzeilen oder Formatierung über mehrere Zeilen keine Auswirkung auf die LOC haben. Am Ende zählen immer nur die Anzahl an IL-Operationen.

Maintainability Index
Der Maintainability Index wird berechnet aus der Halstead Volume, der Cyclomatic Complexity und den Lines Of Code.  Genauer kann hier nachgelesen werden, wie sich diese Metrik berechnet. Die Metrik beschreibt, wie einfach es ist, den Code zu warten. Der Maintainability Index hat einen Wert zwischen 0 und 100, je höher desto besser. Zwischen 20 und 100 ist der Farbindikator grün, zwischen 10 und 19 gelb und zwischen 0 und 9 rot. Als Richtwert sollte der Maintainability Index jedoch nie die 50 unterschreiten.

Wer die Metriken direkt im Code sehen möchte und eine Visual Studio Edition mit CodeLens-Support besitzt, dem wird mit der Extension Microsoft CodeLens Code Health Indicator geholfen. Diese zeigt direkt als CodeLens-Erweiterung die aktuellen Metriken direkt bei der Methode oder Klasse innerhalb des Code-Editors an. Das ist hilfreich, damit man direkt bei der Programmierung erkennt, wann ein Refactoring angebracht ist.

Codeanalyse

Zum kontinuierlichen und auch automatischen Prüfen der Codemetriken, ohne diese immer manuell berechnen und nachschauen zu müssen, gibt es vier Codeanalyseregeln, die genau diese abbilden. Diese Regeln haben eine feste Grenze eingebaut, welche wenn überschritten oder unterschritten, eine Warnung generieren. Die Cyclomatic Complexity darf 25 auf Methodenebene nicht überschreiten. Die Depth of Inheritance darf nicht größer sein als 4. Das Class Coupling darf auf Klassenebene 80 und auf Methodenebene 30 nicht überschreiten. Der Maintainability Index muss größer sein als 19 (grün).

image
Codeanalyse: Codemetrikregeln

Da Codeanalysis eher reaktiv ist und Probleme erst aufzeigt, wenn sie schon vorhanden sind, sollte natürlich kontinuierlich geprüft werden, wie sich die Qualitätsmetriken entwickeln, um hier proaktiv zu sein. Da die Codemetriken auch während eines automatischen Builds über das Commandline-Tool der Code Metrics berechnet und als XML exportiert werden können, ist es möglich, diese auch während des automatischen Builds zu prüfen. Hier können dann auch eigene Grenzwerte gewählt werden, um früher auf mögliche Probleme hingewiesen zu werden.

Fazit

Wem diese fünf Codemetriken ausreichen, der kann ohne großen Aufwand diese in seinen Qualitätsprozess integrieren. Ein wesentlicher Teil ist dabei, die Metriken proaktiv statt reaktiv zu überprüfen und eventuelle Probleme direkt zu beheben. Gleichzeitig heißt es noch lange nicht, dass wenn diese fünf Codemetriken in Ordnung sind, dann auch die Qualität des kompletten Projekts passt. Dies ist lediglich einer von vielen Indikatoren, wie eine mangelhafte Codequalität im Vorfeld erkannt und verbessert werden kann.

Marco Scheel: Links for 2016-08-18 [del.icio.us]

Sven Hubert: HoloLens: App unter Source Control

Bei einer HoloLens App handelt es sich zum Teil um ein Unity Projekt und zum Teil um ein Visual Studio Projekt. Diese gehören genau wie bei anderen Projekten unter Source Control. Doch was genau muss eingecheckt werden? In diesem Teil der Blog-Serie soll geklärt werden, wie ein HoloLens-Projekt aufgebaut ist und was davon eingecheckt werden muss.

Ordnerstruktur

Um die Ordnerstruktur zu erklären, nehmen wir uns als Beispiel den Galaxy Explorer von Microsoft. Gehostet auf GitHub besitzt er bereits eine gitignore-Datei, um irrelevante Dateien herauszufiltern. Interessant ist dies, da wir hier einen direkten Vergleich haben, wie sich die Ordnerstruktur verändert, sobald wir das Projekt zum ersten Mal öffnen und builden. Für den Build wurde in Unity als Platform Windows Store ausgewählt mit dem Universal 10 SDK und D3D als UWP Build Type. Der Buildoutput wurde in den Ordner App nach Microsoft-Vorbild geschrieben.


galaxyexplorer_builtGalaxy Explorer: Ordnerstruktur vor und nach dem erstem BuildGalaxy Explorer: Ordnerstruktur vor und nach dem erstem Build

App / UWP

Der App-Ordner wird beim Build in Unity angelegt. Innerhalb dieses Ordners liegen alle Dateien, um das Unity-Projekt mit Visual Studio als Marketplace UWP-App zu kompilieren. In der darunter liegenden Visual Studio Solution können somit keine Anpassungen mehr an den Assets wie z.B. den C#-Skripten gemacht werden. Dies geschieht direkt in Unity oder in der separat dafür angelegten Visual Studio Solution im Hauptordner.
Da alles innerhalb des App-Ordner beim Build generiert wird, sollte dies auch nicht mit in die Source Control. Wer seine UWP-App für den Windows Store konfigurieren möchte, findet alle Einstellungen der Package.appxmanifest ebenfalls in Unity (Build Settings –> Windows Store –> Player Settings).
Der UWP-Ordner ist ein Nebenprodukt und beinhaltet die NuGet-Paketkonfiguration der UWP-App.

Assets

Im Assets-Ordnet befindet sich alle Assets, die in Unity über den Asset-Manager erstellt und hinzugefügt werden können. Dies beinhalten z.B. alle 3D-Modelle, Shader oder C#-Skripte. Der Assets Ordner ist zentral für das Unity-Projekt und beinhaltet jeglichen Content einer HoloLens-App. Aus diesem Grund sollte dieser auch eingecheckt werden. Das schöne daran ist, dass die Visual Studio Projekte und auch das Unity Projekt auf die gleichen Assets verweisen. Somit können die C#-Skripte in Visual Studio angepasst werden, während Unity die Änderungen mitbekommt.

Library / obj / Temp

Der Library-Ordner wird von Unity generiert und befüllt. Dieser beinhaltet vorkompilierte Assets wie z.B. Shader oder C#-Skripte und dient somit als eine Art File Cache. Den obj-Ordner kennen viele aus dem Visual Studio Umfeld. Dieser beinhaltet die Binaries für die kompilierten C#-Skripte. Bei dem Ordner Temp spricht der Name schon für sich. Alle drei Ordner sollten nicht eingecheckt werden.

ProjectSettings

Alle Einstellungen im Unity Projekt werden im ProjectSettings-Ordner abgespeichert. Dabei wird als Format YAML (Yet another markup language) verwendet, wodurch ein Vergleich von Änderungen an den Projekteinstellungen einfach möglich ist.

Dadurch ergeben sich zwei Ordner, die in die Source Control eingecheckt werden sollten: Assets und ProjectSettings.

Ignore-Dateien

Das GitHub-Projekt gitignore gibt eine erste Anlaufstelle, denn hier werden für unterschiedliche Technologien und Editoren gitignore-Dateien gesammelt, die alle irrelevanten Dateien der entsprechenden Projekte herausfiltern. Hier gibt es bereits für Unity und auch für Visual Studio eine gitignore-Datei. Da sich die Syntax zwischen gitignore für Git und tfignore für den TFS nicht sonderlich unterscheidet, kann man auch gitignore-Dateien für den TFS verwenden.
Die Visual Studio gitignore-Datei ist sehr ausführlich, wobei das meiste nicht benötigt wird. Hier reicht es aus, den App-Ordner und den UWP-Ordner zu ignorieren. Wer auf der Suche nach einem guten Zwischenweg ist, der kann auch die gitignore-Datei des Galaxy Explorer verwenden. Diese findet man im GitHub-Projekt hier.

Wollen Sie mehr über HoloLens erfahren, dann sprechen Sie uns an oder kommen Sie am 14.09.2016 zu uns nach Stuttgart auf’s Holodeck.

Stefan Henneken: IEC 61131-3: Das ‘Command’ Pattern

Durch den Aufruf einer Methode kann an einem Funktionsblock ein Befehl ausgeführt werden. Funktionsblock A ruft eine Methode von Funktionsblock B auf. So weit so gut. Doch wie lässt sich der Austausch solcher “Befehle” zwischen mehreren Funktionsblöcken flexibel gestalten? Das Command Pattern liefert hier einen interessanten Ansatz.

Ein kleines Beispiel aus der Heimautomation soll uns hierbei behilflich sein. Angenommen wir haben mehrere FBs die jeweils ein Gerät bzw. Aktor repräsentieren. Jedes Gerät hat einen individuellen Satz an Befehlen, welche unterschiedliche Funktionen zur Verfügung stellen.

Pic01

Ein weiterer Funktionsblock soll ein 8fach-Tastenfeld abbilden. Dieses Tastenfeld enthält 8 Taster, die den einzelnen Funktionalitäten (Befehlen) der Geräte zugeordnet werden. Durch eine positiven Flanke an den jeweiligen Eingang werden die notwendigen Befehle bei den Geräten aufgerufen.

FUNCTION_BLOCK PUBLIC FB_SwitchPanel
VAR_INPUT
  arrSwitch           : ARRAY[1..8] OF BOOL;
END_VAR
VAR
  fbLamp              : FB_Lamp;
  fbSocket            : FB_Socket;
  fbAirConditioning   : FB_AirConditioning;	
  fbCDPlayer          : FB_CDPlayer;
  arrRtrig            : ARRAY[1..8] OF R_TRIG;
END_VAR

arrRtrig[1](CLK := arrSwitch[1]);
IF arrRtrig[1].Q THEN
  fbSocket.On();
END_IF

arrRtrig[2](CLK := arrSwitch[2]);
IF arrRtrig[2].Q THEN
  fbSocket.Off();
END_IF

arrRtrig[3](CLK := arrSwitch[3]);
IF arrRtrig[3].Q THEN
  fbLamp.SetLevel(100);
END_IF

arrRtrig[4](CLK := arrSwitch[4]);
IF arrRtrig[4].Q THEN
  fbLamp.SetLevel(0);		
END_IF

arrRtrig[5](CLK := arrSwitch[5]);
IF arrRtrig[5].Q THEN
  fbAirConditioning.Activate();
  fbAirConditioning.SetTemperature(20.0);
END_IF

arrRtrig[6](CLK := arrSwitch[6]);
IF arrRtrig[6].Q THEN
  fbAirConditioning.Activate();
  fbAirConditioning.SetTemperature(17.5);
END_IF

arrRtrig[7](CLK := arrSwitch[7]);
IF arrRtrig[7].Q THEN
  fbCDPlayer.SetVolume(40);
  fbCDPlayer.SetTrack(1);
  fbCDPlayer.Start();	
END_IF

arrRtrig[8](CLK := arrSwitch[8]);
IF arrRtrig[8].Q THEN
  fbCDPlayer.Stop();	
END_IF

In Punkto Flexibilität ist dieser Entwurf eher suboptimal. Warum?

Unflexibel. Es besteht eine feste Zuordnung zwischen FB_SwitchPanel und den einzelnen Geräten (FB_Lamp, FB_Socket, FB_CDPlayer und FB_AirConditioning). Soll z.B. FB_Socket durch ein zweites FB_Lamp ersetzt werden, so ist es notwendig die Implementierung von FB_SwitchPanel anzupassen.

Fehlende Wiederverwendbarkeit. Sollen auch die Taster 3 und 4 zum Ansteuern des CD-Players dienen, so muss die notwendige Abfolge von Methodenaufrufen erneut programmiert werden.

Undynamisch. Das 8fach-Tastenfeld wurde als Funktionsblock implementiert. Solange alle Tastenfelder die gleiche Tastenbelegung haben, ist dieser Ansatz lauffähig. Was aber, wenn die Tastenbelegung unterschiedlich sein soll? Entweder müsste für jede Tastenbelegung ein individueller Funktionsblock programmiert werden oder es müssen Programme statt Funktionsblöcke zum Einsatz kommen.

Definition des Command Pattern

Die Lösung des Problems liegt in der Einführung einer Softwareschicht, die sich zwischen dem Tastenfeld und den Geräten einfügt. Diese Schicht kapselt jeden einzelnen Befehl (mit einem Command-FB) und enthält alle relevanten Methodenaufrufe um eine Aktion an einem Gerät auszuführen. Der 8fach-Taster sieht somit nur noch diese Befehle und enthält keine weiteren Referenzen zu den jeweiligen Geräten.

Das Command Pattern definiert drei Schichten:

Invoker FBs dieser Schicht lösen an den Command-FBs den gewünschten Befehl aus. Der Aufrufer (Invoker), in unseren Beispiel das 8fach-Tastenfeld (FB_SwitchPanel), kennt nicht die Empfänger der Befehle. Es weiß aber, wie ein Befehl gestartet wird.
Receiver Dieses sind die FBs, die die jeweiligen Empfänger (Receiver) der Befehle repräsentieren; also FB_Socket, FB_Lamp, …
Commands Jeder Befehl wird durch einen FB abgebildet. Dieser FB enthält eine Referenz auf dem Empfänger. Des Weiteren besitzen diese Befehle eine Methode um den Befehl zu aktivieren. Wird diese Methode aufgerufen, so ist dem Command-FB bekannt, welche Methoden am Empfänger ausgeführt werden müssen, um den gewünschten Effekt zu erzielen.

Schauen wir uns die Command-FBs genauer an.

Ein Command-FB kapselt einen “Auftrag”, indem es einen Satz von Aktionen für einen bestimmten Empfänger enthält. Hierzu werden die Aktionen und die Referenz beim Empfänger zu einem FB zusammengefasst. Über eine Methode (z.B. Execute()) sorgt der Command-FB dafür, das am Empfänger die richtigen Aktionen ausgeführt werden. Der Aufrufer sieht von Außen nicht, welche Aktionen das genau sind. Dieser weiß nur, wenn er die Methode Invoke() aufruft, dass alle notwendigen Schritte ausgeführt werden.

Commands

Hier die Implementierung für den Command-FB um an FB_Socket den On-Befehl auszuführen:

FUNCTION_BLOCK PUBLIC FB_SocketOnCommand
VAR
  refSocket : REFERENCE TO FB_Socket;
END_VAR

Die Variable refSocket enthält die Referenz auf eine Instanz des Bausteins FB_Socket, also den Empfänger des Befehls. Gesetzt wird diese Referenz über die Methode FB_init.

METHOD FB_init : BOOL
VAR_INPUT
  bInitRetains : BOOL;
  bInCopyCode : BOOL;
  refNewSocket : REFERENCE TO FB_Socket;
END_VAR

IF (__ISVALIDREF(refNewSocket)) THEN
  THIS^.refSocket REF= refNewSocket;
ELSE
  THIS^.refSocket REF= 0;
END_IF

Die Methode Execute() führt die notwendige Aktion an FB_Socket aus:

METHOD Execute
IF (__ISVALIDREF(THIS^.refSocket)) THEN
  THIS^.refSocket.On();
END_IF

Je nach Empfänger kann diese Methode aber auch aus mehreren Aktionen bestehen. So sind die folgenden Methodenaufrufe notwendig, um das Abspielen einer CD zu starten:

METHOD Execute
IF (__ISVALIDREF(THIS^.refCDPlayer)) THEN
  THIS^.refCDPlayer.SetVolume(40);
  THIS^.refCDPlayer.SetTrack(1);
  THIS^.refCDPlayer.Start();
END_IF

Da in unserem Bespiel alle Command-FBs die Methode Execute() zum Ausführen des Befehls anbieten, wird diese Methode durch das Interface I_Command vereinheitlicht. Jeder Command-FB muss dieses Interface implementieren.

Invoker

Dem 8fach-Tastenfeld (FB_SwitchPanel) muss jetzt nur noch mitgeteilt werden, welche Command-FBs es nutzen soll. Die Details der Command-FBs müssen nicht bekannt sein. FB_SwitchPanel kennt nur 8 Variablen, die vom Typ I_Command sind. Wird eine positive Flanke an einen der Taster erkannt, so wird über das Interface I_Commnd von dem Command-FB die Methode Invoke() aufgerufen.

FUNCTION_BLOCK PUBLIC FB_SwitchPanel
VAR_INPUT
  arrSwitch    : ARRAY[1..8] OF BOOL;
END_VAR
VAR
  aiCommand    : ARRAY[1..8] OF I_Command;	
  arrRtrig     : ARRAY[1..8] OF R_TRIG;
  nIndex       : INT;
END_VAR

FOR nIndex := 1 TO 8 DO
  arrRtrig[nIndex](CLK := arrSwitch[nIndex]);
  IF arrRtrig[nIndex].Q THEN
    IF (aiCommand[nIndex] <> 0) THEN
      aiCommand[nIndex].Execute();
    END_IF
  END_IF
END_FOR

Zuvor wird durch die Methode SetCommand() das gewünschte Command-FB den einzelnen Tastern zugeordnet. Dadurch ist FB_SwitchPanel universal einsetzbar.

METHOD PUBLIC SetCommand : BOOL
VAR_INPUT
  nPosition   : INT;
  iCommand    : I_Command;
END_VAR

IF ((nPosition >= 1) AND (nPosition <= 8) AND (iCommand <> 0)) THEN
  THIS^.aiCommand[nPosition] := iCommand;
END_IF

Der Invoker FB_SwitchPanel kennt nicht den Empfänger (Receiver). Es sieht nur 8mal das Interface I_Command mit seiner Methode Execute().

Receiver

An den FBs, die einen Empfänger abbilden, brauchen keine Anpassungen durchgeführt werden. Über entsprechende Methoden oder Eingänge kann ein Command-FB die notwendigen Aktionen ausführen.

Anwendung

Hier ein kleines Beispielprogramm, das aus den drei oben gezeigten Softwareschichten eine Anwendung zusammenstellt:

PROGRAM MAIN
VAR
  // Invoker
  fbSwitchPanel                 : FB_SwitchPanel;
	
  // Receiver
  fbSocket                      : FB_Socket;
  refSocket                     : REFERENCE TO FB_Socket := fbSocket;	
  fbLamp                        : FB_Lamp;
  refLamp                       : REFERENCE TO FB_Lamp := fbLamp;	
  fbAirConditioning             : FB_AirConditioning;
  refAirConditioning            : REFERENCE TO FB_AirConditioning := fbAirConditioning;
  fbCDPlayer                    : FB_CDPlayer;
  refCDPlayer                   : REFERENCE TO FB_CDPlayer := fbCDPlayer;

  // Commands
  fbSocketOnCommand             : FB_SocketOnCommand(refSocket);
  fbSocketOffCommand            : FB_SocketOffCommand(refSocket);
  fbLampSetLevel100Command      : FB_LampSetLevelCommand(refLamp, 100);
  fbLampSetLevel0Command        : FB_LampSetLevelCommand(refLamp, 0);
  fbAirConComfortCommand        : FB_AirConComfortCommand(refAirConditioning);
  fbAirConStandbyCommand        : FB_AirConStandbyCommand(refAirConditioning);	
  fbMusicPlayCommand            : FB_MusicPlayCommand(refCDPlayer);
  fbMusicStopCommand            : FB_MusicStopCommand(refCDPlayer);

  bInit                         : BOOL;
END_VAR

IF (NOT bInit) THEN
  fbSwitchPanel.SetCommand(1, fbSocketOnCommand);
  fbSwitchPanel.SetCommand(2, fbSocketOffCommand);
  fbSwitchPanel.SetCommand(3, fbLampSetLevel100Command);
  fbSwitchPanel.SetCommand(4, fbLampSetLevel0Command);
  fbSwitchPanel.SetCommand(5, fbAirConComfortCommand);
  fbSwitchPanel.SetCommand(6, fbAirConStandbyCommand);
  fbSwitchPanel.SetCommand(7, fbMusicPlayCommand);
  fbSwitchPanel.SetCommand(8, fbMusicStopCommand);
  bInit := TRUE;
ELSE
  fbSwitchPanel();	
END_IF

Pro 8fach-Taster (Invoker) wird eine Instanz von FB_SwitchPanel angelegt.

Von jedem Gerät (Receiver) wird ebenfalls je eine Instanz deklariert. Des Weiteren wird von jeder Instanz noch eine Referenz benötigt.

Die erzeugten Referenzen werden bei der Deklaration der Command-FBs (Commands) mit übergeben (an FB_init). Falls notwendig, können hier noch weitere Parameter übergeben werden. So besitzt das Kommando zum Setzen der Beleuchtung noch einen Parameter für die gewünschte Stellgröße.

In diesem Beispiel können mit der Methode SetCommand() die einzelnen Command-FBs den 8 Tastern zugeordnet werden. Die Methode erwartet als ersten Parameter die Tastennummer (1…8) und als zweiten Parameter einen FB, der das Interface I_Command implementiert.

Die erreichten Vorteile sind recht überzeugend:

Entkopplung. Sender (Invoker) und Empfänger (Receiver) sind voneinander entkoppelt. Dadurch kann FB_SwitchPanel generisch entworfen werden. Durch die Methode SetCommand() besteht die Möglichkeit die Zuordnung der Taster zur Laufzeit anzupassen.

Erweiterbarkeit. Es können beliebige Command-FBs hinzugefügt werden. Selbst wenn FB_SwitchPanel durch eine Bibliothek zur Verfügung gestellt wird, kann ein Programmierer beliebige Command-FBs erstellen und mit FB_SwitchPanel verwenden, ohne das Anpassungen an der Bibliothek notwendig werden. Dadurch, dass die zusätzlichen Command-FBs das Interface I_Command implementieren, können diese von FB_SwitchPanel genutzt werden.

Beispiel 1 (TwinCAT 3.1.4020)

UML-Klassendiagramm

 

UML

Das Interface I_Command wird von allen Kommandos implementiert.

Der Invoker besitzt über das Interface I_Command Verweise auf Commands und führt diese bei Bedarf aus.

Ein Command ruft alle notwendigen Methoden des Receivers auf.

MAIN stellt die Verbindungen zwischen den einzelnen Commands und dem Receiver her.

Erweiterungen

Das Command Pattern lässt sich sehr einfach um weitere Funktionen erweitern.

Makro-Befehle

Besonders interessant ist die Möglichkeit, die Befehle beliebig miteinander zu kombinieren und in einem neuen Befehlsobjekt zu kapseln. Man spricht hierbei von sogenannten Makro-Befehlen.

Ein Makro-Befehl hält ein Array von Befehlen. In diesem Beispiel können bis zu vier Command-FBs hinterlegt werden. Da jeder Command-FB das Interface I_Command implementiert, können die Befehle in ein Array vom Typ ARRAY[1..4] OF I_Command gespeichert werden.

FUNCTION_BLOCK PUBLIC FB_RoomOffCommand IMPLEMENTS I_Command
VAR
  aiCommands    : ARRAY[1..4] OF I_Command;
END_VAR

Über die Methode FB_init() werden die einzelnen Command-FBs an den Makro-Befehl übergeben.

METHOD FB_init : BOOL
VAR_INPUT
  bInitRetains : BOOL;
  bInCopyCode : BOOL;
  iCommand01 : I_Command;
  iCommand02 : I_Command;
  iCommand03 : I_Command;
  iCommand04 : I_Command;
END_VAR

THIS^.aiCommand[1] := 0;
THIS^.aiCommand[2] := 0;
THIS^.aiCommand[3] := 0;
THIS^.aiCommand[4] := 0;
IF (iCommand01 <> 0) THEN
  THIS^.aiCommand[1] := iCommand01;
END_IF
IF (iCommand02 <> 0) THEN
  THIS^.aiCommand[2] := iCommand02;
END_IF
IF (iCommand03 <> 0) THEN
  THIS^.aiCommand[3] := iCommand03;
END_IF
IF (iCommand04 <> 0) THEN
  THIS^.aiCommand[4] := iCommand04;
END_IF

Bei Ausführung der Methode Execute() wird über das Array iteriert und bei jedem Befehl Execute() aufgerufen. Somit können mit einem einzigen Execute() des Makro-Befehls gleich mehrere Befehle auf einmal ausgeführt werden.

METHOD Execute
VAR
  nIndex  : INT;
END_VAR

FOR nIndex := 1 TO 4 DO
  IF (THIS^.aiCommands[1] <> 0) THEN
    THIS^.aiCommands[1].Execute();
  END_IF
END_FOR

In MAIN werden bei der Deklaration des Makro-Befehls die 4 Command-FBs übergeben. Da der Makro-Befehl selbst ein Command-FB ist (er implementiert das Interface I_Command), kann dieser bei dem 8fach-Tasten einem Taster zugeordnet werden.

PROGRAM MAIN
VAR
  ...
  fbRoomOffCommand     : FB_RoomOffCommand(fbSocketOffCommand,
                                           fbLampSetLevel0Command,
                                           fbAirConStandbyCommand,
                                           fbMusicStopCommand);
  ...
END_VAR

IF (NOT bInit) THEN
  ...
  fbSwitchPanel.SetCommand(8, fbRoomOffCommand);
  ...
ELSE
  fbSwitchPanel();	
END_IF

Vorstellbar wäre auch eine Methode, welche zur Laufzeit dem Makro-Befehl die einzelnen Command-FBs übergibt. Die Implementierung wäre vergleichbar mit der Methode SetCommand() vom 8fach-Tastenfeld. Somit könnte z.B. ein Szenenbaustein realisiert werden, bei dem der Anwender die Befehle über eine Bedieneroberfläche selbst einer Szene zuordnen kann.

Beispiel 2 (TwinCAT 3.1.4020)

Undo-Funktionalität

Eine weiteres mögliches Feature ist die eine Rückgängigkeits-Funktion. Das 8fach-Tastenfeld erhält einen weiteren Eingang, mit dem der zuletzt ausgeführte Befehl rückgängig gemacht wird. Dazu wird das Interface I_Command um die Methode Undo() erweitert.

UML2

Diese Methode enthält die Umkehrung der Execute-Methode. Wird mit der Execute-Methode die Steckdose eingeschaltet, so wird im gleichen Command-FB mit der Undo-Methode diese wieder ausgeschaltet.

FUNCTION_BLOCK PUBLIC FB_SocketOffCommand IMPLEMENTS I_Command
VAR
  refSocket : REFERENCE TO FB_Socket;
END_VAR

METHOD Execute
IF (__ISVALIDREF(THIS^.refSocket)) THEN
  THIS^.refSocket.Off();
END_IF

METHOD Undo
IF (__ISVALIDREF(THIS^.refSocket)) THEN
  THIS^.refSocket.On();
END_IF

Etwas aufwendiger ist die Implementierung der Undo-Methode für das Setzen der Lampenhelligkeit. In diesen Fall muss der Command-FB um ein “Gedächnis” erweitert werden. Hier wird vor dem Setzen einer neuen Stellgröße, durch die Methode Execute(), die vorherige Stellgröße abgelegt. Die Undo-Methode verwendet beim Aufruf diesen Wert, um die vorherige Stellgröße wiederherzustellen.

FUNCTION_BLOCK PUBLIC FB_LampSetLevelCommand IMPLEMENTS I_Command
VAR
  refLamp        : REFERENCE TO FB_Lamp;
  byNewLevel     : BYTE;
  byLastLevel    : BYTE := 255;
END_VAR

METHOD Execute
IF (__ISVALIDREF(THIS^.refLamp)) THEN
  THIS^.byLastLevel := THIS^.refLamp.Level;	
  THIS^.refLamp.SetLevel(THIS^.byNewLevel);
END_IF

METHOD Undo
IF (__ISVALIDREF(THIS^.refLamp)) THEN
  IF (THIS^.byLastLevel <> 255) THEN
    THIS^.refLamp.SetLevel(THIS^.byLastLevel);
  END_IF
END_IF

Nachdem die Command-FBs um eine Undo-Methode erweitert wurden, muss auch das 8fach-Tastenfeld angepasst werden.

FUNCTION_BLOCK PUBLIC FB_SwitchPanel
VAR_INPUT
  bUndo         : BOOL;
  arrSwitch     : ARRAY[1..8] OF BOOL;
END_VAR
VAR
  aiCommand     : ARRAY[1..8] OF I_Command;	
  arrRtrig      : ARRAY[1..8] OF R_TRIG;
  iLastCommand  : I_Command;
  fbRtrigUndo   : R_TRIG;
  nIndex        : INT;
END_VAR

FOR nIndex := 1 TO 8 DO
  arrRtrig[nIndex](CLK := arrSwitch[nIndex]);
  IF arrRtrig[nIndex].Q THEN
    IF (aiCommand[nIndex] <> 0) THEN
      aiCommand[nIndex].Execute();
      iLastCommand := aiCommand[nIndex];
    END_IF
  END_IF
END_FOR

fbRtrigUndo(CLK := bUndo);
IF fbRtrigUndo.Q THEN
  IF (iLastCommand <> 0) THEN
    iLastCommand.Undo();
  END_IF
END_IF

In Zeile 19 wird der zuletzt ausgeführte Befehl zwischengespeichert. Bei der Aktivierung der Undo-Funktion wird auf diesen Befehl zurückgegriffen und die Undo-Methode ausgeführt (Zeile 27). Die Details für die Umkehrung eines Befehls sind im Command-FB implementiert. Das 8fach-Tastenfeld greift nur über das Interface I_Command auf die einzelnen Befehle zu.

Beispiel 3 (TwinCAT 3.1.4020)

Befehle protokollieren

Da jeder Command-FB das Interface I_Command implementiert, kann jeder Befehl in eine Variable vom Typ I_Command gespeichert werden. Hiervon wurde z.B. bei der Undo-Funktionalität Gebrauch gemacht. Wird diese Variable durch einen Puffer ersetzt, so erhalten wir die Möglichkeit, Befehle zu protokollieren. Die Analyse und die Diagnose einer Anlage kann dadurch erleichtert werden.

Zusammenfassung

Der zentrale Gedanke des Command Pattern ist das Entkoppeln von Invoker und Receiver durch Befehlsobjekte.

  • Ein Entwickler kann neue Command-FBs hinzufügen, ohne das der Code am Invoker (8fach-Taster) geändert werden muss.
  • Die Zuweisung der Befehle an den Invoker kann dynamisch zur Laufzeit erfolgen.
  • Command-FBs können an verschiedenen Stellen wiederverwendet werden. Coderedundanz wird hierdurch vermieden.
  • Befehle können “intelligent” gemacht werden. Somit lassen sich z.B. Makrobefehle und Undo-Befehle realisieren.

Code-Inside Blog: TFS 2015: Adding a new Windows Build Agent

The TFS 2015 Build System

The build system before TFS 2015 was based on a pretty arcane XAML workflow engine which was manageable, but not fun to use. With TFS 2015 a new build system was implemented, which behave pretty much the same way as other build systems (e.g. TeamCity or AppVeyor).

The “build workflow” is based on a simple “task”-concept.

There are many related topics in the TFS world, e.g. Release-Management, but this blogpost will just focus on the “Getting the system ready”-part.

TFS Build Agents

Like the other parts of Microsoft the TFS is now also in the cross-platform business. The build system in TFS 2015 is capable of building a huge range of languages. All you need is a compatible build agent.

My (simple) goal was to build a .NET application on a Windows build agent via the new TFS 2015 build system.

Step 1: Adding a new build agent

Important - Download Agent.

This one is maybe the hardest part. Instead of a huge TFS-Agent-Installer.msi you need to navigate inside the TFS control panel to the “Agent pool”-tab.

You need at least one pool and need to click the “Download Agent” button.

Step 2: Configure the agent

Configuration.

The .zip package contains the actual build agent executable and a .cmd file.

Invoke the “ConfigureAgent.cmd”-file:

We run those agents as Windows Service (which was one of the last config-questions) and are pretty happy with the system.

Step 3: You are done

Now your new build agent should appear under the given build agent pool:

TFS Build Agents.

After googleing around I also found the corresponding TFS HowTo, which describes more or less the complete setup. Well… now it is documented on MSDN and this blog. Maybe this will help my future-self ;)

Karsten Kempe: Was ist Visual Studio Team Services?!

Ein neues Video zu Visual Studio Team Services ist erschienen. Besser hätte ich VSTS auch nicht erklären können. Unbedingt ansehen!

Sven Hubert: ALM Kompakt: Versionieren von Assemblies im Build-Prozess

Um welche Version der Software handelt es sich denn?

Diese Frage wird spätestens dann gestellt, wenn die Software den Entwickler-PC verlässt und von Endanwendern getestet wird. Beim Reproduzieren und fixen von Fehlern ist die Angabe einer Verionsnummer und die Rückverfolgbarkeit zu dem passenden Quellcode-Stand eine zentrale Information. Doch wie werden Versionsnummern richtig vergeben?

Aufbau der Versionsnummern

Die klassische Versionsnummer untergliedert sich in vier Stellen: <Major>.<Minor>.<Build>.<Rev>: Die Haupt- bzw. Nebenversionsnummer des Produktes (Major und Minor Version) werden in der Major und Minor Stelle gespeichert und klassischerweise vom Produkt Management oder der Marketing-Abteilung vorgegeben. Die Buildnummer wird in der Stelle Build gespeichert. In der vierten Stelle (Rev) wird die Revisionsnummer gespeichert.

Mögliche Versionierung

Wichtig bei der Versionierung ist die Generierung einer streng monoton wachsenden und dadurch eindeutigen Versionsnummer. Weiterhin ist zu beachten, dass Installer nur die Major, Minor und Build Stelle einer Datei überprüfen, um zu bestimmen, ob eine Datei bei einem Update ersetzt werden muss.

Die Major und Minor Stelle der Versionsnummer des Produkts sollte von außen vorgegeben werden (Zum Beispiel über Parameter in der Build Definition). Die Build Stelle der Versionsnummer sollte auf das Datum des aktuellen Builds gesetzt werden. Zusammen mit dem in der Revisionsstelle gespeicherten Build des Tages ergibt sich eine monoton wachsende Versionsnummer.

Diese Vergabe der Versionsnummer stellt jedoch nur eine Möglichkeit dar. Eine weitere Variante wäre die semantische Versionierung. Auf die Vor- und Nachteile der verschiedenen Varianten wird an dieser Stelle jedoch nicht weiter eingegangen, da der Fokus auf der Integration in den Buildprozess liegt.

Setzen von Versionsnummern

Die Assembly- und File-Version wird grundsätzlich in der AssemblyInfo.cs festgelegt. Je nach Aufbau der Software kann so für jede Assembly eine separate Version, oder durch die Nutzung einer GlobalAssemblyInfo.cs eine gemeinsame Version, vergeben werden. Das Vergeben der Versionsnummer sollte Grundsätzlich im Buildprozess geschehen, um lokale Builds eindeutig von Server-Builds unterscheiden zu können. Das Grundprinzip besteht nun darin, eine Buildnummer zu erzeugen, welche die Versionsnummer wiederspiegelt. Basierend auf der Buildnummer kann in einem Build-Task die aktuelle Versionsnummer durch die Buildnummer ersetzt werden.

Für die Major- und Minor-Version wird, um sie manuell vergeben zu können, eine Variable im Buildprozess definiert. Die Werte für <Build> und <Rev> werden über bereits vorhandene Variablen im Buildprozess zusammengesetzt. Das Zusammensetzen der <Build>-Stelle kann aus dem Jahr und der Tagesnummer erfolgen. Der Wertebereich von 65535 wird somit erst im Jahr 2066 überschritten. Die resultierende Buildnummer ist nachfolgend dargestellt.

image

$(MajorVersion).$(MinorVersion).$(Year:yy)$(DayOfYear)$(Rev:.rr)

Um die Versionsnummer in der AssemblyInfo patchen zu können, ist ein zusätzlicher Schritt in der Builddefinition nötig. Auf dem Visual Studio Marketplace existiert hierfür eine Extension mit dem passenden Build-Task. Durch die Extension Colin’s ALM Corner Build & Release Tools steht nach der Installation der Build-Task Version Assemblies zur Verfügung.

image

Diese Variante ist jedoch erst ab dem TFS 2015 Update 2 verfügbar. Das Anpassen der Inhalte der AssemblyInfo ist jedoch auch einfach über ein PowerShell-Skript möglich.

# Regular expression pattern to find the version in the build number 
# and then apply it to the assemblies 
$VersionRegex = "\d+\.\d+\.\d+\.\d+"

# Get and validate the version data 
$VersionData = [regex]::matches($Env:BUILD_BUILDNUMBER,$VersionRegex) 
$NewVersion = $VersionData[0]

# Apply the version to the assembly property files 
$files = gci $Env:BUILD_SOURCESDIRECTORY -recurse | 
    ?{ $_.PSIsContainer } | 
    foreach { gci -Path $_.FullName -Recurse -include GlobalAssemblyInfo.* }

foreach ($file in $files) { 
    $filecontent = Get-Content($file) 
    attrib $file -r 
    $filecontent -replace $VersionRegex, $NewVersion | Out-File $file 
    Write-Warning "$file.FullName - version applied" 
}

Das komplette Skript steht hier zum Download zur Verfügung. Je nach Anwendungsfall ist der Regex-Ausdruck und der Filter für die AssemblyInfo-Datei anzupassen. Das Skript muss anschließend nur noch in der Versionsverwaltung abgelegt, und in der Builddefinition aufgerufen werden.

image

Somit wird jede Assembly im Buildprozess mit einer eindeutigen Versionsnummer versehen und kann jederzeit zum Build und zum Quellcode zurückverfolgt werden.

image

Sven Hubert: HoloLens: Erstkontakt mit der Hardware

Wie Sie beim Lesen unserer letzten Blogbeiträge mitbekommen haben, sind wir stolze Besitzer zweier Microsoft HoloLenses. Mit und ohne die Brillen sind wir bereits eifrig dabei, erste Erfahrungen zu sammeln und unseren Kunden diese Eindrücke vorzustellen (so wie z.B. auf der DWX 2016). Im vorherigen Blogartikel ging es um die Software-Plattform und die Entwicklungswerkzeuge für dieses neuartige Gerät. Dieser Teil der Blog-Serie gibt Ihnen einen Eindruck über die technischen Details und die Hardware, also die 3D-Brille selbst.

01_HoloLense

Die HoloLens (Bildquelle)

 

Was ist in der HoloLens-Box?

Die HoloLens kommt in einem edlen runden Soft-Case mit Reißverschluss, in dem sich die Augmented-Reality-Brille selbst und weiteres hilfreiches Zubehör befinden. Zum Lieferumfang gehören noch ein kleines Handbuch, der HoloLens-Klicker (eine Art Fernbedienung), ein Micro-USB-Kabel mit Netzstecker, eine weitere Nasenauflage und ein Überkopfband. Schon beim ersten Anfassen/Herausholen spürt man das relativ hohe Gewicht der Brille von ca. 600g, die später zum Teil auf der eigenen Nase liegen werden.

 

02_HoloLensBox

HoloLens-Box mit Inhalt

 

Das erste Mal die HoloLens auf dem Haupt

Als Erstes folgen wir dem Handbuch und befestigen das Überkopfband, stellen uns die Größe des Bands für unseren Kopf entsprechend ein. Befestigt wird dann die HoloLens über ein Rädchen am beweglichen Kopfband, welches direkt mit der Brille verbunden ist. Spüren wir beim Aufziehen das Gewicht der HoloLens auf unserer Nase zu stark, so sollte man das Überkopfband nochmals nachjustieren. Es empfiehlt sich auch die zweite Nasenauflage auszuprobieren. Gemäß Handbuch sollte das Kopfband hinten etwas nach unten verschoben werden für einen besseren Halt. Meine persönlichen Versuche zeigten jedoch, dass der Tragekomfort mit einem eher geraden Kopfband wesentlich angenehmer ist (auch zeigen einige Microsoft-Videos/Fotos die gleiche Tragehaltung). Ist alles richtig justiert, so spürt man die HoloLens kaum noch auf der Nase. Das Gewicht wird komplett vom Kopf getragen. Die Brille selbst sitzt fest direkt vor den Augen und integriert sich zum größten Teil in das Sichtfeld (auch als Brillenträger war dies gut möglich).

 

03_HandbuchBild

Tragehaltung gemäß Handbuch

04HoloLensOnHead

Angenehmere Tragehaltung (Bildquelle)

 

Das erste Mal die erweiterte Realität auf der Nase

Einmal die HoloLens aufgezogen und auf den Träger justiert, drücken wir den Start-Knopf, der einfach erreichbar am hinteren Ende der Brille liegt. Beim Starten der HoloLens erscheint ein begrüßendes „Hello“ und das Microsoft-Windows-Symbol zusammen mit dem typischen Windows Start-Ton. Das HoloLens-eigene Betriebssystem „Windows Holographic“ wird gestartet und nach dem erfolgreichen Anmelden auf dem Gerät sehen wir das entsprechende Startmenü. Dieses kennen wir in ähnlicher Form von mobilen Geräten mit Windows 10 oder beispielsweise von Windows Phone. Falls der Ton zu laut ist, befinden sich auf der rechten oberen Seite der Brille zwei Knöpfe zur Regelung der Lautstärke. Befinden wir uns in einer sehr hellen oder dunklen Umgebung, so können wir auf der linken Seite der Brille die Helligkeit justieren.

Wie bediene ich die HoloLens?

Je nach Situation und Ziel gibt es verschiedene Möglichkeiten, die in Frage kommen, um die HoloLens zu steuern. Die Eingabemöglichkeiten sind die Blickrichtung, Gestik und Sprache sowie der zur HoloLens mitgelieferte Klicker. In der Mitte des Sichtfelds befindet sich ein weißer Punkt. Dieser weiße Punkt dient quasi als Mauszeiger. Entweder durch eine bestimmte Gestik (Tippbewegung mit dem Zeigefinger), ein bestimmtes Sprachkommando („Select“) oder mit dem Klicker können wir, ähnlich wie ein Mausklick, Elemente selektieren und auswählen. Je nach gestarteter App existieren auch noch andere Sprachbefehle (z.B. „Remove“ zum Schließen oder für Menüpunkte der Name des Menüeintrags) oder Gestik (z.B. ein Verschieben oder Vergrößern von Elementen).

 

 05_HoloLensMenu

Das Hauptmenü zum Starten von Apps und

Steuern des Systems (Bildquelle)

 

Was steckt in der HoloLens?

Die HoloLens ist ein Gerät, dass gerade so vor technischen Details/Ausstattungen strotzt, wenn man bedenkt, dass sie komplett kabellos ist, ein eigenständigen kleinen Rechner darstellt und auf unserem Kopf sitzt (Andere Virtual-Reality-Brillen verwenden hier ein Kabel zu einem Rechner). Besonders bemerkenswert sind die durchsichtigen holografischen Linsen, in welche die holografischen Elemente hineinprojiziert werden und sich so in das Sichtfeld des Trägers integrieren. Die weitere Sensorik dient zur Interaktion mit denen Projektionen in unserem Sichtfeld und somit der erweiterten Realität (oder auch vermischten Realität). Die notwendigen Sensoren und Komponenten für eine solche Interaktion zwischen virtueller und echter Realität sehen wie folgt aus:

Optik:
  • Durchsichtige holographische Linsen
  • Zwei HD 16:9 Lichtprojektoren
  • Automatische Distanzerkennung der Pupillen
  • Holographische Auflösung von 2.3M Lichtpunkten
Sensoren:
  • Eine IMU (inertiale Messeinheit zur Messung der Trägheitsnavigation)
  • 4 umgebungsverstehende Kameras
  • 1 Tiefenkamera
  • 1 2MP Foto-/Video-Kamera
  • 4 Mikrofone
  • 1 Umgebungslichtsensor
Menschliche Steuerung:
  • Tracking der Blickrichtung
  • Eingabe über Gestik
  • Sprachsteuerung
  • Klicker
Weiteres Erwähnenswertes:
  • Eingebaute Lautsprecher
  • 3,5mm Klinkenstecker
  • WLAN
  • Gewicht: 579g
  • Festplatte: 64GB Flash
  • Arbeitsspeicher: 2GB
  • CPU: Speziell angefertigte holografische Recheneinheit
  • […]

 

06HolographicLens

Die Holografischen Linsen (Bildquelle)

07SenorenAnsicht

Die HoloLens ohne Abdeckung und mit sichtbaren Sensoren (Bildquelle)

Was kann die HoloLens jetzt schon?

Auf der HoloLens mitinstalliert befinden sich bereits einige wenige Anwendungen. Andere Anwendungen können aus dem Windows Store heruntergeladen werden. Alle Anwendungen, die als Universal Windows Plattform App entwickelt wurden, können auf der HoloLens problemlos betrieben werden. Diese bezeichnet man auch als 2D-Anwendungen, da sie auf eine zweidimensionale Oberfläche projiziert werden. Somit können wir wie gewohnt  auf einem Desktop mit Fenstern arbeiten. Der Unterschied hier ist: Die Fenster können wir uns in die vermischte Realität pinnen. Beispielsweise kann man surfen und gleichzeitig ein Video schauen.

08_KitchenTableWith2DApps

Der Frühstückstisch wird zum interaktiven Arbeitsplatz
durch die im Raum verteilten 2-D-Anwendungen (Bildquelle)

Besonders herausragend sind hier aber die für HoloLens spezialisierten Apps, die auch eine dreidimensionale Interaktion erlauben. Es gibt hier von Microsoft schon einige Beispiel-Apps, die zeigen, welche Möglichkeiten für eine Interaktion zwischen der virtuellen und echten Welt möglich sind. Während man in diesen Anwendungen ist, scheinen wirklich beide Welten zu verschmelzen. Der Begriff „vermischte Realität“ trifft es hier voll und ganz. Beispielsweise kann man mit HoloTour verschiedene Städte auf der Welt besuchen und sich dort die besten Sehenswürdigkeiten ansehen (wie z.B. Rom). Ist mehr Action gewünscht, so kann man mit RoboRaid gegen Aliens in seinen eigenen Räumen kämpfen. Ein richtig gutes Beispiel, was jetzt schon möglich ist, zeigt die Anwendung Fragments. Hier wird nach erfolgreicher Raum-Analyse ein Krimi gestartet, in dem man selbst die Rolle eines Detektives übernimmt. Die Auftragsgeber und Tatortszenen integrieren sich meisterhaft in das Wohnzimmer bzw. den aktuell verwendeten Raum. Beispielsweise sitzt der Auftragsgeber auf dem Sofa gegenüber beim Mission-Briefing und spricht einen direkt an. Achtung: Es ist wichtig, dass der Raum entsprechend groß ist. Am Anfang der Raum-Analyse wird dies auch mitangezeigt. Microsoft bietet auch für Noch-Nicht-HoloLens-Besitzer zahlreiche Informationen zur Übersicht (inkl. Videos), was es bereits gibt und wo die Richtung hingehen soll. Reinschauen lohnt sich!

09_Example3DApp_Fragments

In Fragments sitzt man zusammen mit dem Auftragsgeber beim Mission-Briefing und erhält die Auftragsdetails (Bildquelle)

Wollen Sie mehr über HoloLens erfahren, dann sprechen Sie uns an oder melden Sie sich an beim AIT Holodeck.

Jürgen Gutsch: Setup Angular2 & TypeScript in a ASP.​NET Core project using Visual Studio

In this post I try to explain, how to setup a ASP.NET Core project with Angular2 and typescript in Visual Studio 2015.

There are two ways to setup an Angular2 Application: The most preferred way is to use angular-cli, which is pretty simple. Unfortunately the Angular CLI doesn't use the latest version . The other way is to follow the tutorial on angular.io, which sets-up a basic starting point, but this needs a lot of manually steps. There are also two ways to setup the way you want to develop your app with ASP.NET Core: One way is to separate the client app completely from the server part. It is pretty useful to decouple the server and the client, to create almost independent applications and to host it on different machines. The other way is to host the client app inside the server app. This is useful for small applications, to have all that stuff in one place and it is easy to deploy on a single server.

In this post I'm going to show you, how you can setup Angular2 app, which will be hosted inside an ASP.NET Core application using Visual Studio 2015. Using this way, the Angular-CLI is not the right choice, because it already sets up a development environment for you and all that stuff is configured a little bit different. The effort to move this to Visual Studio would be to much. I will almost follow the tutorial on http://angular.io/. But we need to change some small things to get that stuff working in Visual Studio 2015.

Configure the ASP.NET Core project

Let's start with a new ASP.NET Core project based on .NET Core. (The name doesn't matter, so "WebApplication391" is fine). We need to choose a Web API project, because the client side Angular2 App will probably communicate with that API and we don't need all the predefined MVC stuff.

A Web API project can't serve static files like JavaScripts, CSS styles, images, or even HTML files. Therefore we need to add a reference to Microsoft.AspNetCore.StaticFiles in the project.json:

"Microsoft.AspNetCore.StaticFiles": "1.0.0 ",

And in the startup.cs, we need to add the following line, just before the call of `UseMvc()

app.UseStaticFiles();

Another important thing we need to do in the startup.cs, is to support the Routing of Angular2. If the Browser calls a URL which doesn't exists on the server, it could be a Angular route. Especially if the URL doesn't contain a file extension.

This means we need to handle the 404 error, which will occur in such cases. We need to serve the index.html to the client, if there was an 404 error, on requests without extensions. To do this we just need a simple lambda based MiddleWare, just before we call UseStaticFiles():

app.Use(async (context, next) =>
{
    await next();

    if (context.Response.StatusCode == 404
        && !Path.HasExtension(context.Request.Path.Value))
    {
        context.Request.Path = "/index.html";
        await next();
    }
});

Inside the properties folder we'll find a file called launchSettings.json. This file is used to configure the behavior of visual Studio 2015, when we press F5 to run the application. Remove all strings "api/values" from this file. Because Visual Studio will always call that specific Web API, every time you press F5.

Now we prepared the ASP.NET Core application to start to follow the angular.io tutorial.:

Let's start with the NodeJS packages. Using Visual Studio we can create a new "npm Configuration file" called package.json. Just copy the stuff from the tutorial:

{
  "name": "dotnetpro-ecollector",
  "version": "1.0.0",
  "scripts": {
    "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "lite": "lite-server",
    "postinstall": "typings install && gulp restore",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/common": "2.0.0-rc.4",
    "@angular/compiler": "2.0.0-rc.4",
    "@angular/core": "2.0.0-rc.4",
    "@angular/forms": "0.2.0",
    "@angular/http": "2.0.0-rc.4",
    "@angular/platform-browser": "2.0.0-rc.4",
    "@angular/platform-browser-dynamic": "2.0.0-rc.4",
    "@angular/router": "3.0.0-beta.1",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0-rc.4",
    "systemjs": "0.19.27",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12",
    "angular2-in-memory-web-api": "0.0.14",
    "es6-promise": "^3.1.2",
    "es6-shim": "^0.35.0",
    "jquery": "^2.2.4",
    "bootstrap": "^3.3.6"
  },
  "devDependencies": {
    "gulp": "^3.9.1",
    "concurrently": "^2.0.0",
    "lite-server": "^2.2.0",
    "typescript": "^1.8.10",
    "typings": "^1.0.4"
  }
}

In this listing, I changed a few things:

  • I added "&& gulp restore" to the postinstall script
  • I also added Gulp to the devDependency to typings

After the file is saved, Visual Studio tryies to load all the packages. This works, but VS shows a yellow exclemation mark because of any arror. Until yet, I didn't figure out what is going wrong here. To be sure all packages are propery installed, use the console, change directory to the current project and type npm install

The post install will possibly faile because gulp is not yet configured. We need gulp to copy the dependencies to the right location inside the wwwroot folder, because static files will only be loaded from that location. This is not part of the tutorial on angular.io, but is needed to fit the client stuff into Visual Studio. Using Visual Studio we need to create a new "gulp Configuration file" with the name gulpfile.js:

var gulp = require('gulp');

gulp.task('default', function () {
    // place code for your default task here
});

gulp.task('restore', function() {
    gulp.src([
        'node_modules/@angular/**/*.js',
        'node_modules/angular2-in-memory-web-api/*.js',
        'node_modules/rxjs/**/*.js',
        'node_modules/systemjs/dist/*.js',
        'node_modules/zone.js/dist/*.js',
        'node_modules/core-js/client/*.js',
        'node_modules/reflect-metadata/reflect.js',
        'node_modules/jquery/dist/*.js',
        'node_modules/bootstrap/dist/**/*.*'
    ]).pipe(gulp.dest('./wwwroot/libs'));
});

The task restore, copies all the needed files to the Folder ./wwwroot/libs

TypeScript needs some type definitions to get the types and API definitions of the libraries, which are not written in TypeScript or not available in TypeScript. To load this, we use another tool, called "typings". This is already installed with NPM. This tool is a package manager for type definition files. We need to configure this tool with a typings.config

{
  "globalDependencies": {
    "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
    "jquery": "registry:dt/jquery#1.10.0+20160417213236"
  }
}

No we have to configure typescript itself. We can also add a new item, using Visual Studio to create a TyoeScript configuration file. I would suggest not to use the default content, but the contents from the angular.io tutorial.

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}

The only things I did with this file, is to add the "compileOnSave" flag and to exclude the "node_modules" folder from the TypeScript build, because we don't need to build containing the TypeScript files and because we moved the needed JavaScripts to ./wwwroot/libs.

If you use Git or any other source code repository, you should ignore the files generated out of our TypeScript files. In case of Git, I simply add another .gitignore to the ./wwwroot/app folder

#remove generated files
*.js
*.map

We do this becasue the JavaScript files are only relevant to run the applicaiton and should be created automatically in the development environment or on a build server, befor deploying the app.

The first app

That is all to prepare a ASP.NET Core project in Visual Studio 2015. Let's start to create the Angular app. The first step is to create a index.html in the folder wwwroot:

<html>
<head>
    <title>dotnetpro eCollector</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/styles.css">
    <!-- 1. Load libraries -->
    <!-- Polyfill(s) for older browsers -->
    <script src="libs/shim.min.js"></script>
    <script src="libs/zone.js"></script>
    <script src="libs/Reflect.js"></script>
    <script src="libs/system.src.js"></script>
    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
        System.import('app')
            .catch(function (err) { console.error(err); });
    </script>
</head>
<!-- 3. Display the application -->
<body>
    <my-app>Loading...</my-app>
</body>
</html>

As you can see, we load almost all JavaScript files from the libs folder. Except a systemjs.config.js. This file is needed to configure Angular2, to define which module is needed, where to find dependencies an so on. Create a new JavaScript file, call it systemjs.config.js and paste the following content into it:

(function (global) {

    // map tells the System loader where to look for things
    var map = {
        'app': 'app', 
        'rxjs': 'lib/rxjs',
        '@angular': 'lib/@angular'
    };

    // packages tells the System loader how to load when no filename and/or no extension
    var packages = {
        'app': { main: 'main.js', defaultExtension: 'js' },
        'rxjs': { defaultExtension: 'js' },
        'angular2-in-memory-web-api': { defaultExtension: 'js' },
    };

    var packageNames = [
      '@angular/common',
      '@angular/compiler',
      '@angular/core',
      '@angular/http',
      '@angular/platform-browser',
      '@angular/platform-browser-dynamic',
      '@angular/router',
      '@angular/router-deprecated',
      '@angular/upgrade'
    ];

    packageNames.forEach(function (pkgName) {
        packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
    });

    var config = {
        map: map,
        packages: packages
    }

    // filterSystemConfig - index.html's chance to modify config before we register it.
    if (global.filterSystemConfig) { global.filterSystemConfig(config); }

    System.config(config);

})(this);

This file also defines a main entry point which is a main.js. This file is the transpiled TypeScript file main.ts we need to create in the next step. The main.ts bootstraps our Angular2 app:

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';

bootstrap(AppComponent);

We also need to create our first Angular2 component. Create a TypeScript file with the name app.component.ts inside the app folder:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: '<h1>My first Angular App in Visual Studio</h1>'
})
export class AppComponent { }

If all works fine, Visual Studio should have created a JavaScript file for each TypeScript file. Also the build should run. Pressing F5 should start the Application and a Browser should open.

A short moment the Loading... is visible in the browser. After the app is initialized and all the Angular2 magic happened, you'll see the contents of the template defined in the app.component.ts.

Conclusion

I propose to use VisualStudio just for small single page applications, because it gets slower the more dynamic files need to be handled. ASP.NET Core is pretty cool to handle dynamically generated files, but Visual Studio still is not. VS tries to track and manage all the files inside the project, which slows down a lot. One solution is to disable source control in Visual Studio and use an external tool to manage the sources.

Another - even better - solution is not to use Visual Studio for front-end development. In a new project, I propose to separate front-end and back-end development and to use Visual Studio Code for the front-end development or even both. You need to learn a few things about NPM, Gulp and you need to use a console in this case, but web development will be a lot faster and a lot more lightweight with this approach. In one of the next posts, I'll show how I currently work with Angular2.

Martin Hey: GZip für WebAPI 2 aktivieren

Mit GZip-Komprimierung kann man einiges an Netzwerklast minimieren - insbesondere, wenn größere Datenmengen übertragen werden sollen, in denen häufig ähnliche Worte vorkommen. Auch wenn das meist genutzte JSON-Format nicht ganz so geschwätzig ist wie beispielsweise SOAP, so kommen doch auch hier beispielsweise die Eigenschaftsnamen in jedem Objekt wieder vor. Wenn man dann eine Liste von Objekten überträgt, so ergibt sich hier ein Einsparungspotenzial.


Im  Gegensatz zu Content-Negotiation, die die Web-API selbst übernimmt, gibt es offenbar keinen Automatismus für die Gzip-Komprimierung. Eine Suche ergab, verschiedene Lösungsansätze - z.B. den von Ben Foster oder den von Radenko Zec. Letzterer ist Vorlage für meine jetzige Lösung geworden.

Schritt 1 - Erzeugen eines ActionFilters, der die Response ändert
public class CompressionAttribute : ActionFilterAttribute
{
    public override async Task OnActionExecutedAsync(HttpActionExecutedContext context, CancellationToken cancellationToken)
    {
        var acceptEncoding = context.Request.Headers.AcceptEncoding;
        var acceptsGzip = acceptEncoding.Contains(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip"));

        if (!acceptsGzip)
        {
            return;
        }

        var content = context.Response.Content;
        if (content == null)
        {
            return;
        }

        var headers = context.Response.Content.Headers;
        var bytes = await content.ReadAsByteArrayAsync();

        var zlibbedContent = (await Compress(bytes)) ?? new byte[0];
        context.Response.Content = new ByteArrayContent(zlibbedContent);

        foreach (var header in headers)
        {
            if (header.Key.Equals("Content-Length", StringComparison.OrdinalIgnoreCase))
            {
                continue;
            }
            context.Response.Content.Headers.Add(header.Key, header.Value);
        }
        context.Response.Content.Headers.Add("Content-Encoding", "gzip");
    }

    private static async Task Compress(byte[] value)
    {
        if (value == null)
        {
            return null;
        }

        using (var output = new MemoryStream())
        {
            using (var gzipStream = new GZipStream(output, CompressionMode.Compress, CompressionLevel.BestSpeed))
            {
                gzipStream.FlushMode = FlushType.Finish;
                await gzipStream.WriteAsync(value, 0, value.Length);
                   
            }
            return output.ToArray();
        }
    }
}
Um die Komprimierung selbst kümmert sich Ionic.Zlib

Die Implementierung ist an sich recht einfach. Zunächst wird geprüft, ob der Client Gzip-Encoding akzeptiert. Ist das nicht der Fall, dann verändert das Attribut die Ausgabe nicht. Anderenfalls wird die Ausgabe komprimiert und die Response neu aufgebaut. Durch die Neuzuweisung der Response werden auch alle bisherigen Content-Type-Header verworfen, weswegen diese im Nachgang wieder gesetzt werden müssen.

Im Anschluss wird dann dem Client noch mitgeteilt, dass es sich um komprimierten Inhalt handelt.

Schritt 2 - ActionFilter anwenden
Der ActionFilter kann nun verwendet werden, indem eine Web-API-Methode damit annotiert wird oder man aktiviert ihn global für alle Anfragen.
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ...

        config.Filters.Add(new CompressionAttribute());

        ...
    }
}
Das passiert in der WebApiConfig.

Jürgen Gutsch: Add HTTP headers to static files in ASP.​NET Core

Usually, static files like JavaScript, CSS, images and so on, are cached on the client after the first request. But sometimes, you need to disable the cache or to add a special cache handling.

To provide static files in a ASP.NET Core application, you use the StaticFileMiddleware:

app.UseStaticFiles();

This extension method has two overloads. One of them needs a StaticFileOptions instance, which is our friend in this case. This options has a property called OnPrepareResponse of type Action<StaticFileResponseContext>. Inside this Action, you have access to the HttpContext and many more. Let's see how it looks like to set the cache life time to 12 hours:

app.UseStaticFiles(new StaticFileOptions()
{
    OnPrepareResponse = context =>
    {
        context.Context.Response.Headers["Cache-Control"] = 
                "private, max-age=43200";

        context.Context.Response.Headers["Expires"] = 
                DateTime.UtcNow.AddHours(12).ToString("R");
    }
});

With the StaticFileResponseContext, you also have access to the file of the currently handled file. With this info, it is possible to manipulate the HTTP headers just for a specific file or file type.

This approach ensures, that the client doesn't use pretty much outdated files, but use cached versions while working with it. We use this in a ASP.NET Core single page application, which uses many JavaScript, and HTML template files. In combination with continuous deployment, we need to ensure the Application uses the latest files.

Norbert Eder: XWiki: List of child-documents

I wrote about XWiki some time ago. It is a pretty cool wiki with a lot of features and a modern look. As I write articles about XWiki, my decision pro or against XWiki/Confluence shouldn’t be hard to guess. Exactly, I gave XWiki a chance.

Some of my wiki pages should just list and link all child pages automatically, so I haven’t to add them manually. Usually this is done by a tree in the sidebar which I disabled in my installation (for several reason, but they doesn’t matter so far). There is macro for this: Document Tree Macro.

In order to create a dynamic list/tree use this piece of “code”:

{{velocity}}
  {{documentTree root="document:$doc.fullName"/}}
{{/velocity}}

This should do the trick.

Please see the documentation for a description of all possible parameters.

The post XWiki: List of child-documents appeared first on Norbert Eder.

Holger Schwichtenberg: Anstehende Windows Updates auf mehreren Computern ermitteln

Ein PowerShell-Skript liefert Informationen darüber, wie viele Updates für die Windows-Computer im Netzwerk vorliegen.

Sven Hubert: HoloLens: Softwareplattform und Entwicklungswerkzeuge

Sie halten die HoloLens noch nicht in eigenen Händen, wollen aber schon anfangen, Apps dafür zu entwickeln? Dank Visual Studio, Unity und dem HoloLens Emulator von Microsoft ist dies bereits heute möglich. In diesem Teil der Blog-Serie HoloLens zeigen wir Ihnen, wie Sie auch ohne Hardware mit der Entwicklung für die HoloLens starten können.

Die nötigen Tools, die vorher installiert werden müssen, und Systemvoraussetzungen befinden sich auf der Microsoft-Seite und können hier nachgelesen werden. Die Tools beinhalten unter anderem das Visual Studio 2015 Update 3, den HoloLens Emulator und Unity.
Bei Visual Studio sollte beachtet werden, dass es sich bei HoloLens-Apps um UWP-Apps handelt. Deshalb müssen die entsprechenden UWP-Features in Visual Studio auch mit installiert werden.
Die Systemvoraussetzungen an den Entwicklungsrechner sind hoch: 64-bit Windows 10, 4-Kern CPU, 8 GB RAM und eine GPU mit DirectX Version 11 oder höher. Zusätzlich muss für den HoloLens-Emulator Hyper-V aktiviert sein.

Wer dies liefern kann und die entsprechenden Tools installiert hat, der kann direkt mit der Entwicklung für die HoloLens beginnen.

Apps

Für die Entwicklung von Anwendungen muss zuerst einmal unterschieden werden, ob eine 2D-App oder eine 3D-App entwickelt werden soll.

HoloLens: 2D-App
HoloLens: 2D-App (Bildquelle)
HoloLens: 3D-App
HoloLens: 3D-App (Bildquelle)

 

2D-Apps können als ganz normale UWP-Apps entwickelt und auch im HoloLens Simulator getestet werden. Diese werden innerhalb der 3D-Welt als rechteckiges Fenster dargestellt (siehe Bild).
3D-Apps wiederum stellen normalerweise 3D-Objekte dar oder agieren direkt mit dem drei dimensionalen Raum.
Wer also nicht mit der 3D-Welt direkt interagieren möchte, dem reicht die Entwicklung einer normalen UWP-App vollkommen aus.

Unity

Unity ist eine 3D-Engine, die zusätzlich noch eine Entwicklungsplattform liefert, mit der nicht nur Spiele sondern auch Augmented Reality (kurz AR) und Virtual Reality (kurz VR) Anwendung erstellt werden können. Dabei fällt die HoloLens in die Kategorie von Augmented Reality, also der erweiterten Realität, da hiermit eine Vermischung der echten Welt mit 3D-Objekten stattfindet.
Da Unity für die Entwicklung von 3D-Welten und auch im Umgang mit AR bereits viel bietet, setzt Microsoft auf diese Technologie in der Entwicklung von Anwendungen für die HoloLens. Wem Unity nicht gefällt, der hat noch die Alternative direkt mit DirectX und C++ oder SharpDX und C# zu arbeiten.
Unity: Der Asset-Manager von Unity

Unity: Der Asset-Manager von Unity

Jedes Projekt in Unity besteht hauptsächlich aus Assets. Diese können z.B. 3D-Models, Skripte, Shader oder Scenes sein.

Die Programmierung der Logik in Unity erfolgt über C#-Skripte. Dabei stellt Unity ein Framework bereit, auf welchem aufgebaut und über welches mit der 3D-Welt interagiert werden kann. Hierzu sollten die Kenntnisse in 3D-Programmierung und auch der Matrizen- und Vektorrechnung aufgefrischt werden, denn an diesen kommen Sie im Normalfall nicht vorbei.
Als Einstieg eignet sich die Galaxy Explorer App, die im Zuge der Share Your Idea Kampagne von Microsoft entwickelt wurde und als Beispiel-App für die HoloLens dient. Diese bietet alle wichtigen Konzepte einer HoloLens-App in Unity wie 3D-Modelle, Sounds, GUI, C#-Skripte, Shader und einer flüssigen Kameraführung.

Zum Abbilden von 3D-Objekten können in Unity verschiedene 3D-Model-Formate importiert werden. Dabei gibt es Unterstützung für 3D-Modelling-Anwendungen wie Maya, 3ds Max oder Blender. Wer nicht selber 3D-Objekte modellieren möchte, wird im Internet fündig. Hier gibt es unterschiedliche Seiten wie z.B. den Unity Asset Store über den man entweder kostenpflichtige aber auch kostenlose 3D-Modelle erwerben kann.

Zu sehr soll in diesem Blogbeitrag zum Thema Unity nicht in die Tiefe gegangen werden. Hier nur ein paar Features zusammengefasst:
Für grafische Effekte können in Unity Shader angelegt werden. Wer innerhalb seiner Anwendung Partikeleffekte oder ein Physik benötigt, für den hat Unity ebenfalls etwas an Bord.
Wer unterschiedliche Darstellungen hat, kann auf Scenes zurückgreifen. Durch Scenes wird definiert, was dargestellt wird. Somit können z.B. unterschiedliche Räume auch unterschiedliche Objekte enthalten. Jeder Raum wird dann durch eine Scene repräsentiert.

Visual Studio

Visual Studio wird hauptsächlich für das Debugging und Deployment der HoloLens-Apps verwendet. Zusätzlich können C#-Skripte aus Unity in Visual Studio bearbeitet werden, wodurch Features wie IntelliSense zur Verfügung stehen.

Visual Studio: HoloLens-Solution nachdem diese aus Unity exportiert wurde

Visual Studio: HoloLens-Solution (nachdem diese aus Unity exportiert wurde)

Das Debugging von Apps funktioniert über den HoloLens Emulator. Dabei wird die App einfach aus Visual Studio gestartet und die C#-Skripte aus Unity können mit Breakpoints versehen werden.

Das Deployment von Apps funktioniert entweder über den Windows Store, wie eine gewöhnliche UWP-App, oder es kann direkt auf die HoloLens installiert werden.

HoloLens Emulator

Der HoloLens Emulator bietet die Möglichkeit das Heads-Up-Display der HoloLens zu emulieren. Dabei wird alles, was der Benutzer später sieht, auch im Emulator dargestellt. Alle schwarzen Bereiche im Emulator sind später in der HoloLens durchsichtig.

HoloLens Emulator: Galaxy Explorer

HoloLens Emulator: Galaxy Explorer

Die Steuerung des Emulators funktioniert mit Maus und Tastatur. Dadurch können alle Aktionen und Bewegungen der HoloLens im Emulator nachgespielt werden. Der Emulator bietet ebenfalls die Möglichkeit, verschiedene Räume zu laden. Dadurch kann die HoloLens in einer vorher aufgenommenen reellen Umgebung getestet werden. Dabei ist es auch möglich, eigene Räume mit der HoloLens aufzunehmen und diese im Emulator abzuspielen.

HoloLens Device Portal

Das HoloLens Device Portal kann sowohl für die richtige HoloLens als auch für den Emulator verwendet werden. Dieses bietet aktuelle Informationen zum Zustand der HoloLens wie z.B. die Auslastung, die installierten Apps und sogar einen direkten Einblick in die 3D-Welt, welche die HoloLens gerade sieht. Das HoloLens Device Portal bietet somit eine weitere Debugging-Schnittstelle, mit der wichtige Information während dem Entwickeln angezeigt werden können. Hier enthält der Entwickler Einblick in die Systemperformance, die Systemauslastung oder kann Aufnahmen der Umgebung oder dessen, was die HoloLens sieht, aufzeichnen.

 

HoloLens Device Portal: Das Webportal der HoloLens inklusive Einsicht in die 3D-Welt

HoloLens Device Portal: Das Webportal der HoloLens inklusive Einsicht in die 3D-Welt

 

Die wichtigsten Funktionen im Überblick:

  • 3D View: Bietet die Möglichkeit die Position und Blickrichtung der HoloLens im 3D-Raum zu verfolgen. Gleichzeitig kann der geladene Raum im Emulator angezeigt werden.
  • Mixed Reality Capture: Bietet die Möglichkeit eine Aufnahme zu machen, aus dem was die HoloLens im Moment in der reellen Welt sieht und was in der 3D-Welt abgebildet wird.
  • Performance Tracing: Startet ein Performanceprofiler der z.B. die CPU-Auslastung oder die Speicherbelastung mit aufnimmt.
  • System Performance: Zeigt die Auslastung des Systems, z.B. für die Auslastung der CPU, GPU oder des Arbeitsspeichers.
  • Apps: Bietet eine Liste der installierten Apps und der aktuell laufenden Apps. Diese können entweder gestartet oder gestoppt werden. Zusätzlich können Apps installiert und wieder deinstalliert werden.
  • App Crash Dumps: Für Apps können Crash Dumps aktiviert werden, die sich später auch hier abrufen lassen, um ein App Crash zu analysieren.
  • Simulation: Über die Simulation können Räume und Bewegungen des Benutzers aufgenommen, die später im Emulator wieder angezeigt und abgespielt werden können. Dadurch kann das Benutzerverhalten zu einem späteren Zeitpunkt noch einmal nachgespielt werden.

Wollen Sie mehr über HoloLens erfahren, dann sprechen Sie uns an oder kommen Sie am 14.09.2016 zu uns nach Stuttgart auf’s Holodeck.

Christian Giesswein: .NET User Group Vortrag in Nürnberg vom 28.07.2016

Am 28.07.2016 war ich zur .NET User Group in Nürnberg eingeladen (http://www.dodnedder.de/).

Dabei stand das Thema "Datenbindung Deluxe – Deep Dive in das Binding von WPF" am abendlichen Programm.

Das schöne an dem Meeting war, dass ein Grillabend dem Vortrag vorangegangen war, und wir dabei von dem Team der User Group und ebenso dem Hauptsponsor des Abends (http://cmo.clear-group.de/) verköstigt wurden.

Es war mir dabei wiedermal ein Spaß mit der Community zusammen einen Abend zu verbringen und viele, bekannte aber auch neue Gesichter zu sehen.

Die Unterlagen und Beispiele gibt es wieder auf GitHub zum downloaden: https://github.com/softwaretirol/conferences.

Die Folien können auch hier direkt heruntergeladen werden:

Holger Schwichtenberg: Microsoft verkündet Pläne für Entity Framework Version 1.1

Bis der Nachfolger der erst kürzlich erschienenen Version 1.0 verfügbar ist, dauert es zwar noch eine Weile, einen Blick auf zu erwartende Neuerungen gewährte Microsoft allerdings schon jetzt.

codefest.at [MS]: Monaco Editor in eigene Apps integrieren

Visual Studio Code verwendet ihn. Und man kann ihn auch selbst in eigenen Projekten verwenden: Den unglaublich coolen Monaco-Editor! Dieser Editor ist ein browser-basierter Code Editor, mit IntelliSense für JavaScript, JSON, HTML, CSS, Less, Sass, C# und TypeScript Support und vielem mehr. Und er kann in eigenen Web-Apps verwendet werden.

Eine detaillierte Beschreibung des Monaco-Editors ist unter (Visual Studio Code) Editing Evolved vorhanden. Hier werden die coolen Features des Editors und Tipps und Tastenkombinationen beschrieben.

image

Wer den Editor einmal selbst rasch ausprobieren will, kann dies online im Monaco Editor Playground tun.

image

Der Editor funktioniert unter IE 9/10/11, Edge, Chrome, Firefox, Safari und Opera. Die Monaco-Editor Website liefert weitere Hintergrundinformationen.

image

Mehr Detailsinfos gibt es unter https://www.npmjs.com/package/monaco-editor.

Beispiele für den Einsatz in eigenen Apps sind auf GitHub unter Microsoft/monaco-editor-samples zu finden.

Als Lizenzform ist MIT License der Open Source Initiative angegeben. Der Editor kann also beliebig verwendet und angepasst werden.

Das Testen ist mit Node.js recht einfach (die Anleitung ist ebenso unter Microsoft/monaco-editor-samples vorhanden).

npm install monaco-editor-samples
cd node_modules/monaco-editor-samples
npm run simpleserver

Auf meiner Maschine (wo bereits einige Pakete installiert sind) sieht das Ganze so aus:

image

Nun kann der Browser mit der lokalen Webadresse der Editor-Page geöffnet werden. Der Simple Editor präsentiert sich wie folgt.

SNAGHTMLefa7de

Der Monaco-Editor kann auch in einem iframe laufen.

Eine sehr coole Sache. Neben Themes und den verschiedensten Sprachunterstützungen bietet der Editor eine beeindruckende Funktionalität.

Wer also solch einen leistungsfähigen Editor in eigene Webprojekten benötigt, findet in dem Monaco-Editor einen unglaublich tollen Editor mit wirklich coolen Features – wie in VSC!

Danke Christoph Wille für den Tipp zum Monaco-Editor!

codefest.at [MS]: Azure Logic Apps sind da

In Microsoft Azure kommen fast täglich Neuigkeiten hinzu, die Cloud machts möglich. Ein relativ neues Service darin sind die Azure Logic Apps. Diese wurden im Mai 2016 bei der Integrate 2016 conference in London vorgestellt. Nun sind die Azure Logic Apps allgemein verfügbar (GA).

Azure Logic Apps stellen eine Infrastruktur bereit, die einen Dataflow aus nahezu beliebigen Datenquellen in andere Systemen ermöglichen und zwar für Power Users und Developer, in Cloud und in Hybrid-Szenarien. Einerseits unterstützt ein Designer bei der Definition des Dataflows und andrerseits können Logic Apps customized und erweitert werden. Nicht umsonst basieren Logic Apps auf BizTalk Server Logik. Azure Logic Apps könnte man als eine Art Biztalk kombiniert mit IfThisThanThat verstehen, schön verpackt als Cloud-Service.

Der Startpunkt für Azure Logic Apps ist unter Azure.com – oder in der eigenen Azure Subscription.

image

Seit Ende Juli sind die Azure Logic Apps nun allgemein verfügbar (general availability), schreibt Frank Weigel, Principal Director Program Management, im Azure Blog:

Announcing Azure Logic Apps general availability

Der Dataflow kann im Designer modelliert werden, wie etwa in diesem Beispiel aus der Ankündigung.

image

Wichtig hierbei sind natürlich die “Connectors”, welche für verschiedenste Systeme fertig bereitstehen. Das können öffentliche Interfaces zu Diensten wie CRM Online, Dropbox, Facebook, Twitter, GitHub, Google Drive, FTP und viele mehr sein.

Für Entwickler sind die Logic Apps besonders interessant, da sie auch Daten aus eigenen Web-API Schnittstellen oder etwa direkt von Azure Blob Storage verwenden können. Umgekehrt muss keine eigene Logik für eine Transformation oder Notifications entwickelt werden, sondern dies kann in den Logic Apps erfolgen. Ich sehe das als sehr großen Vorteil gerade in Szenarien, wo Daten aus eigenen Applikationen in andere Systeme fließen sollen – oder umgekehrt.

Für alle jene, die sich mit Logic Apps befassen wollen, empfehle ich die Tutorial: Connect Logic App to your Azure IoT Suite Remote Monitoring preconfigured solution Seite. Hier wird eine Demoapp angelegt, welche Daten aus einer vorkonfigurierten IoT Demosuite verwendet und ein simples Monitoring per SendGrid Dienst bereitstellt. Der Dataflow sieht im Designer etwa wie folgt aus.

image

Dieses IoT-Beispiel demonstriert visuell recht schön, was in diesem Demo passiert: Daten werden aus einer HTTP Schnittstelle geliefert und an eine EMail Adresse per SendGrid versendet. Easy going, oder?

Last but not least, jetzt , wo Azure Logic Apps verfügbar sind, gibt es auch finale Preise dafür. Das Pricing ist sehr überschaubar und abhängig von der Menge der verarbeiteten Daten, siehe hier.

In diesem Sinne: Es gibt sicherlich viele Szenarien, wo Azure Logic Apps eigene Apps und Lösungen unterstützen können und einen stabilen, skalierbaren Cloud-Service anbieten, der sich durch Interfaces leicht konsumieren läßt. Viel Spaß mit Logic Apps!

Sven Hubert: Rückblick auf Microsofts Worldwide Partner Conference 2016

Vom 11.07.2016 bis 14.07.2016 lud Microsoft zu seiner alljährlichen Partnerkonferenz (WPC) ein, eine Konferenz, auf der Microsoft seinen Partnern einen Blick in die Zukunft und Stoßrichtung des Unternehmens gibt und auf der Partner die Möglichkeit haben, sich mit Microsoft und anderen Partnern über aktuelle und zukünftige Themen und Zusammenarbeiten zu unterhalten.

Auch auf der WPC 2016 war das über allem schwebende Thema die digitale Transformation. In jeder der drei Key Notes verwiesen die Microsoft-Verantwortlichen auf die seit 2015 formulierte Vision, jede Person und jedes Unternehmen auf dem Planeten zu stärken um mehr zu erreichen.

Microsoft_Mission

Ermöglicht werden soll dies insbesondere durch Microsofts Cloud-Plattform und den darin zur Verfügung stehenden Diensten. Microsoft stellt dabei in besonderem Maße heraus, dass Sicherheit, Compliance, Transparenz und Vertrauen die Basis und das Alleinstellungsmerkmal der Microsoft Cloud sind. Dabei wurde erneut auf die German Cloud verwiesen, ein Konstrukt, bei dem Microsoft nur Technologielieferant ist, die Daten aber von einem deutschen Datentreuhänder verwaltet werden, und somit der Zugriff auf diese Daten durch Dritte vollständig dem deutschen Recht unterliegt. Diese Rechtssicherheit kann heute keiner der Wettbewerber von Microsoft bieten.

Darüber hinaus sieht Microsoft einen Zwang zur Digitalisierung, denn Digitalisierung sei ein Merkmal erfolgreicher Unternehmen. Um dies zu erreichen, sollen drei Bestrebungen verfolgt werden:

  1. Produktivität und Geschäftsprozesse neu definieren
  2. Die intelligente Cloud Plattform liefern
  3. Ein persönlicheres Computer-Erlebnis schaffen

In der Keynote unterhielt sich Satya Nadella mit Jeff Immelt, dem CEO von G.E. darüber, wie dieses 140 Jahre alte Unternehmen die Herausforderung der Digitalisierung angenommen hat. Jeff Immelts Kernaussage in dem Gespräch war: „Wir stehen an einer Grenzlinie für Industrieunternehmen. Es gibt eine Vergangenheit und es wird eine Zukunft geben. Und die Zukunft ist abhängig davon, wer am schnellsten digitalisiert!“ Das ganze Gespräch können sie hier ansehen:



Microsoft stellt auf der WPC auch nochmals ganz klar heraus, dass es ein durch Partner getriebenes Unternehmen ist. Durch Partner werden Technologien und Plattformen zu Lösungen.

Als langjähriger Microsoft-Partner ist für uns bei AIT die WPC ein Gradmesser, inwiefern unser Wissen um Technologien und Methoden dem aus Microsofts Sicht zukünftigen Markt gerecht werden kann. Wir nutzen die Gespräche mit Vertretern von Microsoft und anderen Microsoft-Partnern, um unseren Blick für Lösungen aber auch Engpässe zu schärfen. Darüber hinaus gehen wir noch vor unseren Kunden durch das Tal der Tränen, in dem wir Neuerungen und Empfehlungen selbst ausprobieren und dabei des notwendige Wissen aufbauen, um unseren Kunden die entscheiden Hinweise bei der eigenen Adaption von Technologien und Prozessen zu geben.

Im Kontext der Neudefinition von Geschäftsprozessen und Produktivität baut die Aussage von Microsoft auf dem Einsatz von Office 365, Visual Studio Team Services sowie weiteren Diensten aus der Microsoft Cloud sowie einem mobilen Zugang zu all diesen Informationen. Durch unsere eigene Migration von einer On-Premise Softwarelandschaft hin zu einer hybriden Landschaft, bei der alle führenden Plattformen in der Cloud laufen, können wir aus eigener Erfahrung von sowohl Vorteilen als auch Hindernissen und Nachteilen berichten. Das eine Digitalisierung von Prozessen auch mit fundamentalen Verbesserungen einher geht, zeigt unser Einsatz von PowerBI zur Auswertung unserer Dienstleistungen und Projekte. VSTS nutzen wir seit Preview-Verfügbarkeit des Dienstes und unsere Erweiterungen zur agilen Schätzung und Backlog-Priorisierung zeigen, wie bestehende Dienste um vermisste Funktionen ergänzt werden können. Als Xamarin Premier Consulting Partner können wir zudem unseren Kunden den Weg zur mobilen Anwendung aufzeigen und Sie dabei mit Beratung und Entwicklung erfolgreich begleiten.

Unter dem Begriff der intelligenten Cloud Plattform sieht Microsoft eine Vielzahl an Diensten, die heute bereits in Azure verfügbar sind. Die wichtigsten für unsere Kunden aus dem Maschinen- und Anlagenbau sind sicherlich die als Azure IoT Suite orchestrierte Sammlung von Cloud-Diensten zur Bereitstellung von Szenarien wie Predictive Maintainance oder Remote Monitoring. Microsoft verankert hierzu wie kein anderer Anbieter offene Standards wir OPC UA in seinen Diensten. Darüber hinaus steht, und das war sicher für viele eine überraschende Ankündigung, mit Windows 10 IoT Core ein kostenfreies Betriebssystem für Devices zur Verfügung, welches den gleichen Softwareentwicklungsparadigmen wie die restliche Windows-Plattform folgt und dabei die gleichen Werkzeuge nutzt.



Das persönlichere Computer-Erlebnis heißt bei Microsoft momentan HoloLens. Mit HoloLens realisiert Microsoft eine Vision der Interaktion zwischen Mensch und Computer, die bereits in Science Fiction Filmen des vergangenen Jahrtausends erdacht wurde. Auch wir bei AIT sehen großes Potential insbesondere im industriellen Umfeld für derartige Devices. Gespräche mit unseren Kunden zeigen bereits heute, dass das Interesse und Potential an derartigen Lösungen sehr hoch sind. Wir sind gespannt, welche Ideen wir in diesem Umfeld in Zukunft gemeinsam mit unseren Kunden zum Leben erwecken dürfen. Kontaktieren Sie uns, wenn Sie mehr zu HoloLens, den Möglichkeiten, Bedingungen und Entwicklungen erfahren möchten. Wenn Sie Sich die Microsoft HoloLens live anschauen wollen, dann haben Sie bei unserer Veranstaltung in Stuttgart am 14.9.2016 die Möglichkeit dazu. Melden Sie Sich einfach hier an: AIT HoloLens Roadshow

Als Fazit der WPC nehmen wir mit, dass innovative Softwarelösungen der Schlüssel zur Digitalisierung sein werden und das Softwareentwicklung zur Kompetenz eines jeden Unternehmens gehören wird. Die Beherrschung von Technologien, Prozessen und Werkzeugen werden zum Hygienefaktor einer erfolgreichen Digitalisierungsstrategie und wir freuen uns darauf, unsere Kunden auf diesem Weg führen zu dürfen.

Sven Hubert: ALM kompakt: TFS entfernt doppelte Work Items beim E-Mail-Versand

Szenario: Man führt eine Work Item Query aus, in der Work Items mehrfach vorkommen. Dies kann beispielsweise der Fall sein, wenn man Backlog Items mit ihren Test Cases ausgeben lässt. Ein Test Case kann sich durchaus auf mehrere Backlog Items beziehen. Nachfolgend ist ein kleiner Ausschnitt eines Backlogs mit zwei User Stories zu sehen. Der Test Case mit der ID 419 kommt in der Liste zweimal vor.

image

Wenn man nun über den im Screenshot hervorgehobenen Mail-Button das Ergebnis der Work Item Query versenden möchte, werden die mehrfach vorkommenden Work Items jeweils nur bei ihrem ersten Vorkommen dargestellt. Die Liste wird also normalisiert. Im konkreten Beispiel sieht dies dann wie folgt aus:

image

Es ist gut zu erkennen, dass unterhalb der User Story 318 der Test Case 419 nicht mehr zu sehen ist. Wenn es darum geht, eine Liste von Work Items zu versenden, die beispielsweise noch durch eine andere Person überarbeitet werden muss, ist dies eine sinnvolle Veränderung der Liste. Möchte man hingegen einem Kollegen oder Kunden die Struktur der Work Items aufzeigen, so möchte man ggf. die vorhandenen, redundanzbehafteten Strukturen unverändert weitergeben. Um dies zu erreichen, gibt es einen kleinen Trick.

Anstatt die Liste wie im ersten Screenshot gezeigt mit dem Button über der Ergebnisliste zu versenden, kann man auch alle Einträge in der Liste markieren. Dies geht am schnellsten über die Tastatur mit <STRG> und A.

image

Über das Kontextmenü (rechte Maustaste) erreicht man dann den Befehl „Copy as HTML“. ACHTUNG: Sehr verlockend ist hier auch der Befehl “Email selected work item(s)…”, dieser führt jedoch auch nicht zu dem gewünschten Ergebnis (siehe weiter unten).

2016-07-25_08-56-21

Es öffnet sich ein Dialog, der eine kopierfreundliche Ansicht zeigt, in der der gewünschte Inhalt bereits ausgewählt ist. Man muss nun nur noch den eigentlichen Kopierbefehl, z.B. mittels <STRG>+C, ausführen. Der Dialog schließt sich danach automatisch wieder.

2016-07-25_09-45-57

Nun kann man den Inhalt direkt in eine E-Mail einbetten, in der dann auch wie gewünscht manche Work Items redundant vorkommen.

2016-07-25_09-46-38

Dieser Weg hat zwar einige manuelle Schritte, geht aber letztlich doch recht flüssig von der Hand. Mit den out-of-the-box Möglichkeiten lässt sich die redundante Abbildung nicht automatisiert per E-Mail versenden.

Für die besonders interessierten Leser nachfolgend noch die Darstellung, wenn man die markierten Elemente mit dem Befehl “Email selected work item(s)…” versendet:

image

Nun wird die komplette Liste in die E-Mail eingefügt, ohne dabei Dubletten zu entfernen. Dies sieht noch so aus, wie man es im eingangs geschilderten Szenario haben möchte.

image

Jedoch kommt beim Empfang die redundanzfreie Form an:

2016-07-25_09-48-10

Wenn man sich in dem anfangs beschriebenen Szenario befindet kann man sich mit ein paar wenigen manuellen Schritten helfen. In vielen anderen Fällen ist die redundanzfreie Darstellung sicherlich hilfreich.

codefest.at [MS]: Visual Studio Code den Run-Button für Websites beibringen

Visual Studio Code ist eine feine Sache. Das kostenlose Entwicklungssystem für Windows, OS X und Linux ist unter https://code.visualstudio.com downloadbar und stellt neben einem sehr leistungsfähigen Editor mit IntelliSense und Debugging, Git-Support und Extensions auch Runtimes für Node.js, .NET Core, Unity und Office bereit. Apropos Runtime: Wie sieht es mit Webprojekten aus? Das müssen wir Visual Studio Code erst beibringen…

Visual Studio Code for all

Für alle jene, die neu in Visual Studio Code (VSC) sind, informiert die Startseite The Basics of Visual Studio Code über den Editor und seine Leistungsfähigkeit.

image

Damit gleich zur Realität…

Wo ist der Run Button?

Gerade, wenn man von Visual Studio kommt, erwartet man einen “Run”-Button und einen gewohnten, ähnlichen Komfort für Webprojekte. Nun, im Gegensatz zu Visual Studio stellt VSC eine “lightweight” Developing-Environment bereit. Es gibt keinen “Run” Button (F5)…

Ein Webprojekt starten

In meinem Beispiel wollte ich ein Office-AddIn für Word bauen und mit VSC bearbeiten. Das Framework habe ich übrigens in Node.js mit npm install -g bower yo generator-office gulp tsd und yo Office erstellt, aber das ist eine andere Geschichte.

Man bearbeitet also ein Webprojekt mit VSC – am besten mit File / Open Folder

image

Nun kann die Bearbeitung erfolgen. Nur, wie sieht man nun den Output? Wie kann man dieses Webprojekt starten…?

image

Klar, man benötigt einen lokalen Webserver. Nur, wie integriert man diesen in VSC?

Command Palette

Zuvor noch einen kleinen Exkurs in VSC: Ein sehr wichtiges Feature in VSC ist die “Command Palette”. Diese ist mit Ctrl+Shift+P (oder am PC schneller mit der F1-Taste) jederzeit erreichbar und bietet Zugriff zur ganzen Funktionalitäten von VSC. In der Anzeige wird nach der Eingabe gefiltert. Wenn verfügbar, wird gleich neben der Funktion die entsprechende Tastenkombination angezeigt. Praktisch und schnell!

image

Gut, Kommandos können also ganz rasch abgesetzt werden. Diese können Formatierungsbefehle oder auch umfangreiche Befehle sein. Das führt uns zu den Erweiterungen…

Extensions

Wer, so wie ich von Visual Studio kommt, sucht hier mal einige Zeit nach einer Methode, das Projekt zu “starten”. Zum Glück gibt es eine einfache Lösung für mein Thema mit dem Webprojekt: Die gute Botschaft ist, dass Visual Studio Code mit sog. “Extensions” erweitert werden kann.

Und es gibt eine ganze Reihe von coolen Extensions für VSC!

image

Die Lösung: IIS Express Extension

Die Integration wird am einfachsten durch eine weitere Extension zu VSC hinzugefügt. Im Visual Studio Marketplace hat Warren Buckley eine Extension für die Integration von IIS Express bereitgestellt. Danke Warren!

IIS Express (Run websites straight from VS Code using IIS Express)

image

Der Code ist übrigens unter https://github.com/warrenbuckley/IIS-Express-Code verfügbar.
(IIS Express – und somit diese Extension - ist nur unter Windows Systemen lauffähig.)

image

Nach der Installation muss die Extension aktiviert werden und VS Code einmal neu gestartet werden.

image

IIS Express Extension verwenden

Nach dem VSC Restart wird der IIS Express (für die Website) gestartet: IIS Express: Run Website. Die Suche nach “run” liefert sogleich die Extension.

image

Nun wird die Website mit dem Start Website Command gestartet.

image

Das Output Window zeigt den Erfolg und die localhost Adresse an (in meinem Beispiel Port 3498).

image

Zusätzlich wird auch sogleich der Default Browser geöffnet. Je nach Projekt-Struktur wird das Default Dokument im Root Folder geöffnet – oder auch nicht…

image

In meinem Beispiel habe ich eine tiefere Ordnerstruktur und ein home.html Startdokument. Somit lautet mein Pfad natürlich http://localhost:3498/app/home/home.html. Damit klappts auch im Browser.

SNAGHTML461a4fd

Der Webserver läuft. Code-Änderungen werden wie erwartet durch Speichern des Files und Refresh im Browser aktualisiert.

Wer den IIS Express Webserver wieder beenden möchte, führt in der Command Palette IIS Express: Run Website und hier den Stop Webserver Befehl aus.

image

Das wars. Die IIS Express Extension bietet eine rasche Methode, Webprojekte mit Visual Studio Code zu entwickeln und zu starten!

Hier noch rasch ein paar Links zu den wichtigsten Themen in VSC:

  • Setup - Install VS Code for your platform and configure the tool set for your development needs.
  • The Basics - Introduction to the basic UI, commands, and features of the VS Code editor.
  • Settings - Customize VS Code for how you like to work.
  • Languages - Learn about VS Code's support for your favorite programming languages.
  • Node.js - This tutorial gets you quickly running and debugging a Node.js web app.
  • Why VS Code? - Read about the design philosophy and architecture of VS Code.
  • Download VS Code - Quickly find the appropriate install for your platform (Windows, OS X and Linux).

Visual Studio Code ist cool! Viel Spaß beim Entwickeln mit VSC!

codefest.at [MS]: Was ist das neue SharePoint Framework?

Passend zu meinem letzten Blogpost mit dem Hinweis zum Office 365 Developer Podcast möchte ich Software-Entwicklern das neue SharePoint Framework vorstellen. Doch schön der Reihe nach…

Mit der Vorstellung von SharePoint 2016 Anfang Mai (siehe Future of SharePoint) hat Microsoft ein neues Entwicklungsmodell für SharePoint vorgestellt: Das SharePoint Framework. Anstelle von Server-seitigem Development (so, wie es von der ersten SharePoint Version mit ASP und ab 2003 ASP.NET – mit Ausnahme des neuen App Modells - bis heute der Fall war…) tritt nun Client-seitiges Development. Für Entwickler bedeutet das in einem Wort gesagt: Javascript!

Um es auch in Folge sehr kurz zu machen: Mit dem SharePoint Framework ermöglicht Microsoft modernes End-to-End App Development mit Webtechnologien, die nicht von .NET Implementierungen abhängig sind. Das SharePoint Framework wird es für SharePoint Online und SharePoint on premises geben. Es steht derzeit nur als Preview bereit und kann also erst in naher Zukunft eingesetzt werden. Dieser Artikel mit den Ressourcen ist sozusagen als Vorbereitung für Developer zu sehen.

In The SharePoint Framework—an open and connected platform stellt Microsoft das neue Framework kurz vor. Das SharePoint Framework basiert auf Open Source Software und wird auf existierenden SharePoint Sites verfügbar sein. Damit wird Zugriff auf den SP-Presentation Layer, das DOM, Data, Events und den SP-Host möglich sein.

image

Als Startpunkt möchte ich sogleich das Youtube-Video Open and Connected Platform: The SharePoint Framework von Daniel Kogan/Microsoft Mechanics aus dem Artikel mitgeben. In kurzen 15 Minuten erhält man einen Einblick in das neue Framework und das Tooling. Damit sind u.a. moderne und responsive Designs out of the Box möglich.

image

Das Design, die “Page Structure”, besteht aus mehreren Teilen. Footer und Header (der SPO “Seitenrahmen) werden als “Chrome” bezeichnet. Hier fließen Daten, bzw. die Navigation, von der SharePoint-Site ein.

image

Der “Page Body” enthält dann die eigentlichen Daten, den “Canvas” (also die “Leinwand”). Enduser können Inhalte in diesen Canvas (wie zuvor in die WebPart Zones) platzieren. WebParts wiederum können Daten aus SharePoint oder anderen Services wie etwa Office 365 (Exchange, Delve) oder aus eigenen Datenquellen (einer Provider Hosted App) anzeigen.

image

Mit der neuen “Publishing App” können Enduser sehr einfach und intuitiv neue Seiten in SharePoint erstellen.

Für Developer gibt es eine Reihe von Open Source Tools, die zum Einsatz kommen. Die folgende Grafik von http://yeoman.io/ liefert einen Überblick:

image

Der Entwicklungsprozess sieht dann wie folgt aus: Ein Developer erstellt mit Yeoman Scaffolding ein SP-Projekt und entwickelt eine Lösung mit dem SharePoint Framework, etwa mit Visual Studio Code oder mit Visual Studio. Diese wird dann mit eine Build System wie Gulp deployed (siehe u.a. The streaming build system http://gulpjs.com und https://github.com/gulpjs/gulp)

Die folgende Grafik zeigt den Workflow.

image

In dem Beispiel wird die Lösung mit Typescript und den Tools auf Basis von Node.js erstellt. Sobald die Solution gebaut ist, geht es um das Testen und das Deployment.

In dem Prozess gibt es eine für SP-Developer neue Komponente, die SharePoint Workbench. Damit ist ein lokales Testen auch ohne Verbindung zum SharePoint Server möglich – das ist wirklich cool! Der folgende Screenshot zeigt einen Teil der Lösung in Typescript in Visual Studio Code und Node.js mit gulp für das Testen und Deployment.

image

gulp serve erstellt das Deployment-Paket und startet SharePoint Workbench auf dem localhost. Das Webpart verhält sich dabei genauso wie im SharePoint Server. Damit kann das Development losgelöst erfolgen, sogar im Flugzeug… ;). Das Beispiel zeigt ein WebPart mit zwei Image-Größen-Optionen, welches in der SharePoint Workbench läuft.

image

Updates sind integriert: gulp serve läuft im Hintergrund und überwacht Code-Änderungen und re-deployt diese sofort in die SharePoint Workbench. gulp upload-cdn hilft dann beim Packing und Deployment über CDN (eine Vorab-Konfiguration wird hier natürlich vorausgesetzt).

Solche WebParts können nicht nur in Publishing Apps eingefügt werden…

image

…sondern auch via WebPart Editor genauso in existierende Seiten integriert werden. Die WebPart-Eigenschaften können wie gewohnt bearbeitet werden.

image

Ein Hinweis für existierende SharePoint (und Office) Devs und Lösungen…

Keine Sorge, das SharePoint Framework wird das bestehende Modell nicht ersetzen oder ablösen, sondern nur erweitern. Das gesamte Wissen über SharePoint und die APIs kann weiterverwendet werden. Dazu gibt es einen exzellenten Webcast von Vesa Juvonen (Mr. PnP) und Waldek Mastykarz (MVP) in Waldeks’ Artikel SharePoint Framework - powered by open source bzw. direkt auf Channel9.

image

Apropos Office 365 Developer Podcasts: Mehr über das SharePoint Framework gibt es unter anderem in der Episode 093 on PnP and the SharePoint Framework—Office 365 Developer Podcast zu erfahren.

image

Hier sind auch weitere coole Podcasts von Microsoft und Community Kollegen verlinkt.

Für alle Fortgeschrittenen SP-Developer ist auch der Webcast PnP Web Cast - Converting existing JS apps to SharePoint Framework von Vesa Juvonen sehr empfehlenswert sowie die http://dev.office.com/PnP Website.

In diesem Sinne freuen wir uns auf das neue SharePoint Framework und die neuen Funktionen!

codefest.at [MS]: Neues im Office 365 Developer Podcast

Office 365 ist eine Developer Plattform. Als Einstieg in die Entwicklung stellt Microsoft die http://dev.office.com/ Website bereit. Neben den umfangreichen Informationen für den optimalen Start und vielen Demos gibt es auch eine weitere aktuelle Bezugsquelle, die wenig Developern bekannt ist: den Office 365 Developer Podcast. Davon gibt es nun die 100.te Ausgabe!

image

Software-Entwickler finden im Office Dev Center den Einstieg in das Office Development.

Das Office 365 Dev Team bei Microsoft feiert nun den 100.ten Podcast – und zwar mit prominenten Gästen!

Episode 100 with Corporate Vice President Jeff Teper on Future of SharePoint—Office 365 Developer Podcast

image

Hier sprechen Coding-Guru Richard diZerega und Andrew Coates, die Jeff Teper, Corporate Vice President of SharePoint and OneDrive, als Gast begrüßen dürfen. Unter anderem ist auch Jeremy Thake mit dabei, der vorige Produzent des Office 365 Developer Podcasts.

Viel Spaß mit den Podcasts und der Jubiläumsausgabe des Office 365 Developer Podcasts!

Sven Hubert: New release of TFS ASAP for TFS 2015 Update 3

We are proud to present the new release of our TFS Automated Servicing and Administration Platform (TFS ASAP). Besides some minor bug fixes, this version supports update 3 of Microsoft Team Foundation Server 2015. In addition, we improved the usability of the Global Lists Editor.

Administering global lists in TFS is not straight forward. Out of the box, this can only be achieved by using command line or the TFS Power Tools. Both ways require the user to be member of the Project Collection Administrators group. Thus, the number of users who can maintain global lists and their entries are very limited. To remove this limitation TFS ASAP provides the Global Lists Editor, a web based administration platform.

Global List

Within this web page, global lists can be created, updated and deleted. By sorting the global lists and its entries alphabeticaly it should now be easier to find the items you are looking for. New entries are always added on top of the list until the next page load. There is also the option to enable users who are not in the Project Collection Administrators group to maintain global lists by creating a dedicated TFS group. For detailed information about this feature please refer to our user manual (chapter 6).

The installer (Build 14.30.16216.2) can be downloaded here and for further information please visit www.tfsasap.com. If you don’t have a licence key, you can request a trial at support@tfsasap.com.

codefest.at [MS]: Willkommen bei Microsoft AppSource

Die Art und Weise, wie wir heute Software und Services verwenden hat sich geändert. Heutzutage sind wir gewohnt, Apps rasch und einfach zu finden, zu installieren, anzusehen und zu verwenden. Um dieses Konzept auch im Business-Bereich umsetzen zu können, sind moderne Apps und eine entsprechende Infrastruktur erforderlich. Der neue AppSource Store macht dies möglich.

Der AppSource Store läuft ganz unter dem Motto “Find the right app for your business needs - Get solutions tailored to your industry that work with the products you already use”. Hier werden Lösungen für die Bereiche Microsoft Dynamics, Power BI, Office 365 und Azure gelistet.

Der AppSource Store steht unter https://appsource.microsoft.com bereit.

image

Der AppSource Store wird im Artikel Turning business process into business advantage for organizations everywhere unter blogs.microsoft.com vorgestellt.

AppSource kann nach Lösungen nach Kategorien, Branchen und Produkten gefiltert werden, wie etwa hier in diesem Beispiel.

image

 

Für Software-Entwickler ist diese Plattform interessant, um eigene Lösungen hier anzubieten.

image

Es sind nur wenige Felder auszufüllen, nämlich das Unternehmen, Kontaktinfos und eine kurze App-Beschreibung. Relevant ist natürlich auch die Art der App/Lösung:

image

Das wars auch schon. Nach dem Submit folgt eine kurze Info, dass sich Microsoft melden wird, um Details über die Lösung zu erfragen: “Thanks for telling us about your app! We’ll reach out to you with next steps soon”.

Wir sehen uns im AppSource Store…

Uli Armbruster: Should I stay or should I go: Wechselmotive analyisieren

In unserem Video, welches sich an Bewerber für die co-IT.eu GmbH richtet, sprechen wir das Thema Wechselgründe an. Die folgende Linksammlung soll euch bei eurer Entscheidung helfen.

 

 

Wir werden die Liste kontinuierlich erweitern, sofern wir gut Artikel finden. Der geneigte Leser kann gerne weitere Vorschläge einreichen oder von seinen Erfahrungen berichten.


Einsortiert unter:German, Links, Misc Tagged: Gehalt, Retrospektive, Stellenausschreibung

Sven Hubert: WiX Toolset Teil 5: Access denied! – Permissions setzen leicht gemacht

Herzlich willkommen zum fünften Teil der WiX-Blog-Serie. Jeder, der im Alltag mit Computern arbeitet, kommt irgendwann an einen Punkt, an dem Administratoren-Rechte auf dem System sehr hilfreich wären, um ein Problem schnell und unkompliziert zu lösen. Aus Sicht des IT-Supports wäre das gleichzusetzen mit absoluter Anarchie. Jeder macht was er will, keiner macht was er soll, aber alle machen mit. Beschränkungen stellen in der Regel sicher, dass nur diejenigen, die ganz genau wissen, was sie tun, tiefere Eingriffe in ein bestehendes System durchführen können. Dies gewährleistet einen konsistenten Zustand des Gesamt-Systems.

Trotzdem müssen auch Anwendern in bestimmten Bereichen weitreichende Rechte eingeräumt werden. Eine installierte Anwendung, die vom angemeldeten Nutzer zwar gesehen, aber nicht ausgeführt werden darf, kann auch nicht die Arbeitsleistung verbessern. Eine Anwendung, die eine Datei-basierte Datenbank benutzt, auf welcher der Anwender aber keine Schreib-Rechte hat, wird keine Daten persistieren können. Berechtigungen müssen also schon vor der ersten Ausführung einer Anwendung gesetzt werden. Am besten schon während der Installation. Dazu sind während der Installation zwar temporäre Administrations-Rechte nötig, diese werden bei vielen Firmen im Verteilungskonzept einer Software aber berücksichtigt. Wie sieht die Rechte-Vergabe mit Hilfe von WiX also aus?

Um das zu beantworten muss unterschieden werden zwischen drei zur Verfügung stehenden Elementen. Die Elemente Permission, PermissionEx und util:PermissionEx haben alle das gleiche Ziel: Berechtigungen setzen. Sie verfolgen jedoch verschiedene Wege um ans Ziel zu kommen.

Das Element PermissionEx ist ein mit WiX mitgeliefertes Element zum Schreiben von Berechtigungen. Es besitzt zwei Attribute: eine ID und einen SDDL-String (Security Descriptor Definition Language). Dieses Element ist nur für Installationsprojekte, die auf MSI 5.0 aufbauen verfügbar. Über den SDDL-String werden die genauen Berechtigungen des übergeordneten Elementes bestimmt. Denn eines haben alle Permission Elemente geminsam: Sie müssen stets einem anderen Element zugeordnet werden. Dies kann ein CreateFolder, ein File oder ein RegistryKey/Value Element sein. Somit werden die Berechtigungen auf einem Element gesetzt, das einem Component, und damit einem DirectoryRef-Element zugeordnet ist. Die Arbeit mit SDDL-Strings ist jedoch etwas gewöhnungsbedürftig und benötigt Einarbeitung, daher ist das PermissionEx-Element nicht für den Einstieg geeignet und soll hier nicht weiter betrachtet werden. Mehr Informationen über die Handhabung der SDDL-Strings findet man bei MSDN oder in verschiedenen Tutorials.

Das ebenfalls im Standard-WiX-Paket enthaltene Permission-Element kann mehrere Attribute beinhalten. Hier werden einzelne Berechtigungen über einzelne Attribute erteilt oder verweigert. Anders als das PermissionEx-Element, muss auch der User und die Domain des Users über ein Attribut definiert werden. Hierbei wird deutlich, dass ein Element auch mehrere Permission, beziehungsweise PermissionEx Elemente beinhalten kann, um unterschiedlichen Benutzern verschiedene Rechte-Sets zuzuweisen. Hierbei ist jedoch zu beachten, dass durch das Permission-Element, alle ACLs (Access Control List) überschrieben werden und somit nur noch die definierten Rechte-Sets gelten. Dies birgt bei unbedachtem Einsatz die Gefahr, sich selbst auszusperren. Im folgenden Beispiel gelten nach der Installation ausschließlich die definierten Rechte-Sets:

18-07-2016 15-54-24

Das letzte Element, das util:PermissionEx Element, ist kein Bestandteil des eigentlichen WiX-Pakets. Es ist in der Util-Extension enthalten und kann durch xmlns:util=“http://schemas.microsoft.com/wix/UtilExtension“ in den Installer eingebunden werden. Im Großen und Ganzen ähnelt das util:PermissionEx-Element dem mitgelieferten Permission-Element des WiX-Pakets. Der größte Unterschied ist jedoch, dass durch das util:PermissionEx-Element die ACLs nicht überschrieben, sondern modifiziert werden. Somit bleiben bestehende Berechtigungen, wie etwa der volle Zugriff für Administratoren, unberührt. Ein weiterer Vorteil des util:PermissionEx Elementes ist, dass ohne weiteres Zutun alle Unterordner die gleichen Berechtigungen wie der definierte Ordner erhalten.

Im Falle von Permission und util:PermissionEx werden Permissions einzeln als Attribut vergeben. Das Attribut Read setzt beispielsweise die Lese-Rechte des angegebenen Nutzers. Darüber hinaus existieren noch allgemeinere Rechte-Sammlungen. Neben GenericAll, was alle Rechte beinhaltet, gibt es noch GenericRead oder GenericWrite. Diese beinhalten verschiedene Rechte, die zum Lesen beziehungsweise Schreiben benötigt werden. Diese können nicht einzeln verboten werden, da sie implizit auch das Recht Synchronize beinhalten. Somit würde eine Anfrage für GenericRead fehlschlagen wenn GenericWrite verboten ist. Es wird daher empfohlen, explizit nur mit dem Erlauben von Rechten zu arbeiten, um solche impliziten Verkettungen auszuschließen.

Ein weiteres Pflicht-Attribut ist der User. Damit wird der Nutzer, für den die Berechtigung gesetzt werden soll, bestimmt. Dabei sind bestimmte Schlüsselwörter bereits vorhanden. Everyone, Administrators und Users werden auf jedem System erkannt. Darüber hinaus können weitere Benutzer beziehungsweise Gruppen angegeben werden. Dazu kann über das Domain-Attribut auch die entsprechende Domain  angegeben werden. Dies führt jedoch dazu, dass Installer an ein bestimmtes System angepasst werden müssen. Für interne Software einer Firma ist dies irrelevant, da nur das eigene System unterstützt werden muss. Falls das Zielsystem aber unbekannt ist, sollten nur die obigen allgemein erkannten Schlüsselwörter genutzt werden. Wesentlich einfacher kann dabei die Verwendung von Properties sein, die in Custom Actions mit den entsprechenden Werten gefüllt werden. Im folgenden Beispiel bleiben die bestehenden Rechte des Systems erhalten und werden entsprechend angepasst:

18-07-2016 15-50-29

Ausblick

Zu guter Letzt besteht natürlich immer die Möglichkeit, spezielle Wünsche über Custom Actions umzusetzen. Mit den Custom Actions sind dem Entwickler kaum noch Grenzen gesetzt, welche Vorgänge und Anpassungen während einer Installation durchgeführt werden sollen. Wie das aussieht, wird im nächsten Teil der WiX-Blog-Serie beleuchtet.

Uli Armbruster: Tools for Developers Session vom NET Open Space 2016

Zur Session „Tools & Practices for Developers“ habe ich mir Notizen gemacht. Wie versprochen findet ihr hier aufgelistet die genannten Tools. Ich habe nicht alle aufgeschrieben, also postet gerne weitere, wenn euch eines fehlt.

Mein Antrieb hinter der Session war der, dass ich meine tägliche Arbeit versuche so weit es geht zu optimieren und automatisieren. Wenn ich pro Tag 10 Minuten einsparen kann,was z.B. alleine durch TotalCommander möglich ist, so ergibt sich pro Jahr eine freigewordene Zeit von 43,5h.

 

Keepass Plugins

meine Keepass Plugins

Wenn ihr noch wichtige Tools aus eurer täglichen Arbeit nicht aufgelistet findet, dann schreibt mir und ich füge sie hinzu.

 

 

 


Einsortiert unter:German, Links, Misc Tagged: Community, Open Space

codefest.at [MS]: Microsoft Cognitive Services Emotion API Teil 4

Neben der Face-API habe ich kürzlich die Emotion API der Microsoft Cognitive Services ausprobiert. Beide Services basieren auf Machine Learning und interpretieren Gesichter aus Fotos (bzw. auch aus Videos). Während die Face API Basisinformationen über ein Gesicht liefern, versucht die Emotion API den Gesichtsausdruck von erkannten Gesichtern in Zahlen zu fassen. Die Emotion API beurteilt einen Ausdruck in verschiedenen Kategorien und liefert Wahrscheinlichkeiten retour. Das Ganze sieht dann so aus…

Der Startpunkt für die Emotion API ist https://www.microsoft.com/cognitive-services/en-us/emotion-api und die Documentation.

Auch hierfür gibt es ein Tutorial Get Started with Emotion API in C#, auf GitHub steht das Microsoft/Cognitive-Emotion-Windows Projekt zum Download bereit. Die Repo enthält die Windows Client Library und ein Beispiel mit einer Windows-App.

Build…

Allerdings ist für Windows SDK for the Microsoft Emotion API etwas Handarbeit nötig, um das Projekt zum Laufen zu bekommen. Das Projekt SampleUserControlLibrary muss extra geladen und in die Solution eingebunden werden. Dann lädt man noch in der NuGet Console das Paket Install-Package Microsoft.ProjectOxford.Emotion und fügt die Reference zum SampleUserControlLibrary in das EmotionAPI-WPF_Samples Project hinzu. Dann klappts auch mit dem Compile.

Ausprobieren

Nachdem diese technischen Voraussetzungen erfüllt sind, und die Solution ge-build-et werden kann, kann der Start der WPF App erfolgen. Das Demo startet mit der erforderlichen Key-Aufforderung.

image

Hier wird also zunächst der eigene “Emotion-Preview” Key benötigt. Diesen erhält man von https://www.microsoft.com/cognitive-services/en-us/subscriptions. Der kostenfrei Key kann für 30,000 transactions per month und 20-mal pro Minute verwendet werden. Diesen kopiert man und trägt in hier in das Subscription Key Feld ein und klickt auf Save Key. Damit wird der eigene Key auf die eigene Festplatte gespeichert und steht für die Zukunft in dieser App bereit.

Detect emotion using a stream

Beim Fortsetzen kann nun ein Bild oder ein Video ausgewählt werden. Ich habe diesmal ein Bild von mir verwendet, das nicht so neutral wie jenes von der Face API ist, sondern wo ich mir ein Lächeln abgerungen habe. Hinweis: In den Nutzungsbedingungen steht auch klar, dass Personen im Bild damit einverstanden sein müssen, dass das Bild hier verwendet wird… Gut, ich bin einverstanden.

Das Ergebnis sieht hier, mit der Emotion API, wie folgt aus:

image

Die Ergebnisse im Detail:

[17:17:44.959642]: EmotionServiceClient is created
[17:17:44.985143]: Calling EmotionServiceClient.RecognizeAsync()...
[17:17:46.279940]: Detection Result:
[17:17:46.282933]: Emotion[0]
[17:17:46.285444]:   .FaceRectangle = left: 122, top: 49, width: 53, height: 53
[17:17:46.287934]:   Anger    : 0.0003246186
[17:17:46.289450]:   Contempt : 0.002541366
[17:17:46.290972]:   Disgust  : 0.003764645
[17:17:46.297973]:   Fear     : 8.104636E-07
[17:17:46.299971]:   Happiness: 0.7857869
[17:17:46.302971]:   Neutral  : 0.2070151
[17:17:46.304972]:   Sadness  : 7.317301E-05
[17:17:46.307971]:   Surprise  : 0.0004933038

Man sieht hier also die erkannte Wahrscheinlichkeiten in verschiedenen Kategorien (Anger, Contempt, Disgust, Fear, Happiness, Neutral, Sadness, Surprise). Die Kategorien mit der höchsten Wahrscheinlichkeit werden neben dem Foto zusammengefasst. In meinem Beispiel sind das Happiness mit 78%, gefolgt von Neutral mit 20% und Disgust mit 0,3%. Witzig, 0,3% “Abscheu” hätte ich nicht interpretiert, allerdings ist das in diesem Beispiel auch völlig vernachlässigbar. Alle anderen Faktoren (wie Geringschätzung, Angst, Traurigkeit) werden von der Emotion API mit einer noch geringeren Wahrscheinlichkeit bewertet.

Technisch gesehen erfolgt das Ermitteln der Emotionen wie folgt.

image

…hier folgt dann die UploadAndDetectEmotions Methode mit dem Client (SDK) in DetectEmotionUsingStreamPage.xaml.cs. Diese erzeugt den Client mit dem Subscription Key und lädt das Bild in das Service.

image

…und die Ausgabe dieses Szenarios aus dem Beispiel durch Durchlaufen der emotionResult-Collection.

image

Weitere Szenarien funktionieren nach demselben Prinzip.

Detect emotion using a URL

Die zweite Option “Detect emotion using a URL” macht dasselbe, nur dass eben ein Bild-URL verwendet werden kann.

image

Wenn das Bild nicht entspricht (wie in meinem Fall), zeigt die API mögliche Ursachen an:

No emotion is detected. This might be due to:

  • image is too small to detect faces
  • no faces are in the images
  • faces poses make it difficult to detect emotions
  • or other factors

Mein Versuchsbild von der URL ist nur 150 Pixel breit und viel zu pixelig, um für brauchbare Ergebnisse verwendet zu werden. Verständlich, wenn sich die API dann beschwert.

Detect emotion using a video

Hierbei muss das Videofile als .mp4, .mov oder .wmv File auf der Festplatte vorliegen. Dieses wird nach der Auswahl zur Analyse an die Emotion API upgeloadet. Das Ergebnis wird in EmotionDetectionUsingVideoPage.xaml.cs von der async-Methode emotionServiceClient.GetOperationResultAsync(videoOperation) geliefert.

image

Ein Video wird in verschiedene Sequenzen zerlegt und analysiert. Das dauert natürlich je nach Video einige Zeit… mein Beispielvideo war zwar nur etwa 14 Sekunden lang, der Upload und die Analyse dauerte rund 3 Minuten.

image

Das Ergebnis der Videoanalyse zeigt die “Top 3 Emotions”. In diesem Video habe ich viele unterschiedliche Gesichtsausdrücke ausprobiert, von happy, über erstaunt bis neutral. Mein Ergebnis sah dann so aus:

image

Die Top 3 Kategorien meines Kurzvideos waren Neutral (51%), Erfreut (46%) und Verärgert (0,5%).
Mein Ausdruck für “überrascht” scheint wohl in Happiness aufgegangen zu sein. Winking smile

Hier der JSON-Output des ersten Gesichtsausdrucks (offensichtlich der Ausdruck “Happy”, visualisiert mit jsonvisualizer.com):

SNAGHTML11bc727

Aus dem Array werden dann die Top 3 Ausdrücke ausgegeben. So kann dann durch die Ergebnisse gelaufen werden und diese weiterverwendet werden.

Fazit

Die Emotion API stellt neben der Face API ein weiteres, cooles Cloud Service aus den Microsoft Cognitive Services dar. Bei Bildern funktionierte die Erkennung in meinem Beispielen ziemlich gut. Bei Videos ist das schwerer zu beurteilen und nachzuvollziehen. Auf jeden Fall sind beide Services für mich sehr beeindruckend. In zukünftiger Software (auch abseits von Spaß-Apps) wird es bestimmt Anwendungsfälle geben - mir fallen hier neben Überwachungsaspekten vor allem Beispiele in Bezug auf Menschen mit Behinderungen ein -, wo der Einsatz und die Bewertung der Gesichtserkennung Sinn macht.

Somit meine Empfehlung: Eine coole Sache. Am besten einmal die Beispiele selbst ausprobieren und damit experimentieren!

 

Quicklinks zu den vorigen Teilen dieser Serie über Cognitive Services:

codefest.at [MS]: Microsoft Cognitive Services Teil 3

In den ersten beiden Teilen über die Microsoft Cognitive Services ging es um die Face-API.Die Cognitive Services sind jedoch sehr umfangreich und bieten eine ganze Reihe von interessanten Beispielen, welche die Verwendung demonstrieren.

Viele Beispiele für die Microsoft Cognitive Services sind auf der SDKs & Samples SDKs & Samples Website aufgelistet.

image

Viele Samples liegen auf GitHub oder können direkt von dort bezogen werden. Bitte nicht vergessen, dass für die einzelnen Services ein eigener API-Key erforderlich ist, der von https://www.microsoft.com/cognitive-services/en-us/subscriptions bezogen und verwaltet werden kann. Die Liste kann nach Plattform und API gefiltert werden.

Ein Service, das wahrscheinlich oft in eigenen Apps/Webapps genutzt werden kann, ist das Microsoft Bot Framework: “Your bots — wherever your users are talking.”. In diesem Sinne ist ein “Bot” etwas Gutes. Er soll Benutzern Hilfestellung durch natürliche Fragen und Antworten geben. Der Startpunkt für Bots ist https://dev.botframework.com/.

image

Zum Entwickeln eigener Bots steht das Bot Framework Developer Portal bereit. Hier können eigene Bots registriert und konfiguriert werden, gewünschte Channels gewählt werden und der Bot im Bot Directory veröffentlicht werden. Alle so registrierten Bots sind auto-configured umd mit Skype und dem Web zu funktionieren.

Hinweis: Das Microsoft Bot Framework wurde bei der BUILD Conference vorgestellt. Mittlerweile, rund 3 Monate später, gibt es hier bereits Neuerungen und es liegt bereits die API V3 vor: Upgrade your bot to V3.

Viel Spaß beim Ausprobieren der Services!

Martin Richter: Samsung S4 (I9500 und I9295) mit Android 5.01 stürzen ab, wenn man die Google Kontoeinstellungen bearbeiten will

Vor über 2 Monaten fing es an. Nach irgend einem Update konnte ich auf einmal die Kontoeinstellungen meines Google Accounts auf meinem Samsung S4 Active mit Android 5.01 nicht mehr erreichen. Einstellungen -> Konten -> Google und Crash, Anwendung wird angehalten.

Relativ schnell fand ich Leidensgenossen im Netz, denen es genauso geht. Der häufigste Kommentar der Experten war: „Warten auf ein neues Google-Play-Store Update“. Andere setzten tatsächlich ihr Handy zurück und machten die wildesten Klimmzüge. Resultat war: Nach dem nächsten Update lief es wieder nicht.

Bis dato war es mir erstmal egal, aber jetzt wollte ich doch eine Einstellung ändern. Also noch mal gegoogelt und gleich in mehreren Threads einen simplen Workaround gefunden, wie man doch an sein Konto kommt und den Tipp möchte ich Euch auch gerne zukommen lassen:

  • Einfach Gallerie App öffnen
  • Einstellungen auswählen
  • Und da findet man auch das verwendete Google Konto.

Hier stürzt nichts ab und man kann die entsprechenden Einstellungen vornehmen.

Siehe unter anderem hier und auch hier.


Copyright © 2010 Martin Richter
Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.
(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)

codefest.at [MS]: Microsoft Cognitive Services Face API Teil 2

In Teil 1 ging es um das Erstellen einer einfachen App, um Gesichter auf Fotos mit der Face-API zu erkennen. Nun geht es darum, mehr über die Gesichter zu erfahren…

Ich habe das Beispiel aus dem Tutorial Get Started with Face API in C# etwas erweitert. Hier sehen wir das bisherige Ergebnis mit einer Person (mir) und dem erkannten Gesichtsfeld auf dem Foto. Sehen wir uns an, was die Face-API noch alles kann und welche Daten sie uns für eigene Apps liefern kann…

image_thumb[10]

Dazu habe ich das Sample (Code siehe hier) mit den Infos von der Face-API - How to Detect Faces in Image erweitert und mit demselben Bild (und weiteren, s.u.) experimentiert.

Somit habe ich einfach das verwendete Bild erneut mit FaceAttributes an das Service gesendet:

faceServiceClient.DetectAsync(s, returnFaceLandmarks: true, returnFaceAttributes: requiredFaceAttributes)

Der Screenshot zeigt die möglichen Attribute (Age, Gender, Smile, FacialHair, HeadPose, Glasses).

image_thumb[18]

Das Ergebnis und die erkannten Merkmale sind beeindruckend… von Alter, Geschlecht, Brillenträger-Info bis zum Smile-Faktor mit einer Wahrscheinlichkeit (0 bis 1 = 100%). Cool, oder?

image_thumb[22]

Schöner wird das Ganze, wenn man die Ergebnisse serialisiert und so ausgeben lässt:

var json = JsonConvert.SerializeObject(face);

image

Beim Erforschen entdeckt man weitere interessante Details… etwa in FacialHair, ob ein Bart, Schnurrbart oder Kotletten erkannt wurden.

Geliefert werden auch die X und Y-Position der wichtigsten Gesichtsmerkmale im Bild (FaceLandmarks). Das kann hilfreich für das Erkennen von Gesichtsausdrücken und für die Steuerung der eigenen App sein.

image

Diese Eigenschaften sind hier visualisiert.

image

…sowie die Haltung des Kopfes. In meinem Beispiel ist Pitch 0 Grad, Roll –1.8 Grad und Yaw +1 Grad. Die Person im Bild oben hat den Kopf ganz leicht nach links geneigt.

image

Die folgende Grafik aus dem Glossar und Infos aus Face API - V1.0 helfen, die Werte zu verstehen.

image

Natürlich habe ich auch mit weiteren Beispielbildern experimentiert. Bei einem Bild eines (grinsenden = 93% Wahrscheinlichkeit) Brillenträges (ReadingGlasses) hat das auch brav funktioniert…

image

Ebenso hat mein Versuch mit einem Bild von Martina gut geklappt… Winking smile

image_thumb[43]

image

Natürlich musste ich auch ein (spätes) Foto von Elvis Presley ausprobieren… es wäre wegen den Kotletten. Viel mehr Sideburns geht bei dem Foto (das ich aus Copryright Gründen hier nicht poste) eigentlich nicht, aber – you get the idea - die Sideburns werden erkannt: 0.2 und Beard 0.3. Das Alter…hm auch Elvis war mal jung…

image

Zugegeben, ich bin von diesem Service recht beeindruckt. Wie in Teil 1 erwähnt, muss die Qualität der Bilder, die Auflösung, die Lichtverhältnisse und die Konstellation der Personen für eine korrekte Erkennung natürlich ausreichen. Bei meinen Versuchen erkannte die Face-API – bei guter Bildqualität - recht zuverlässig Daten aus den Fotos. Umgekehrt gab es auch Fotos, wo gar keine Gesichter erkannt wurden.

Die Face-API liegt derzeit (siehe Endpoint https://api.projectoxford.ai/face/v1.0/detect) als Version 1.0 vor. Offensichtlich wird für die Public-Demo http://how-old.net/ eine ältere Version verwendet, diese liefert teilweise unterschiedliche Ergebnisse. Zum Herumspielen ist die Website aber allemal gut. Aus meiner Sicht liefert das eigene V1 Demo jedoch bessere Ergebnisse. Wichtig ist auch der Gesichtsausdruck. Je neutraler (Stichwort Passfoto), desto genauer ist auch die Altersermittlung.

Manche Cognitive Services können in eigenen Applikationen durchaus Sinn machen. Die Verwendung (der Face-API) ist denkbar einfach. Alleine die Möglichkeit solche Funktionen einfach zu benutzen (und nicht selbst entwickeln oder zukaufen zu müssen), beflügeln Gedanken zur Integration in eigene Software-Lösungen.

Die Spielwiese ist eröffnet! Viel Spaß beim Erforschen der Microsoft Cognitive Services!

In Teil 3 gibts dann noch Hinweise für weitere Beispiele.

Kay Giza [MS]: Visual Studio Code 1.3 - Tabs, Extensions View und mehr Neuigkeiten

Visual Studio Code (VSCode) hat mir Version 1.3 einige entscheidende Verbesserungen und Highlights erhalten. In diesem Blogeintrag möchte ich einige der Neuigkeiten vorstellen. Eine... [... mehr in diesem Blogeintrag auf Giza-Blog.de]


This post is powered by www.Giza-Blog.de | Giza-Blog.de: RSS Feed
© Copyright 2006-2016 Kay Giza. All rights reserved. Legal

codefest.at [MS]: Microsoft Cognitive Services Face API Teil 1

Die Art und Weise, wie wir in Zukunft Computer bedienen werden, wird sich ändern. Neben den gewohnten Mechanismen mit Tastatur, Maus, Touch und Spracheingabe wird Software zunehmend intelligenter und besser auf den User eingehen und die Kommunikation mit der Maschine vereinfachen.

Zu diesem Zweck forschen Software-Entwickler daran, Machine Learning zu verbessern und Services bereitzustellen, welche APIs zur Konsumentation von Logik in eigene Apps erlauben.

Microsoft hat kürzlich die Cognitive Services vorgestellt, die mehr als zwanzig (!) verschiedene Cloud-Services zur Integration in eigene Apps anbieten. Der Projektname lautete übrigens “Project Oxford”. Die Cognitive Services sind derzeit noch in Preview und die Endpoints und Libraries heißen auch noch “Project Oxford”.

Die Website https://www.microsoft.com/cognitive-services zeigt alle verfügbaren Services.

image

Ich habe mir ein einfaches Service herausgepickt, um dieses selbst einmal auszuprobieren, nämlich die Face-API aus der Vision-Kategorie.

image

Der Startpunkt ist Face-API Webseite.
Die Face-API Dokumentation liefert den Überblick und weitere Links zu Beispielen.

Das Tutorial Get Started with Face API in C# zeigt die ersten Schritte zum Ausprobieren. Los gehts!

Als Voraussetzung ist für jedes Service ein (derzeit kostenfreier) API Key erforderlich. Dieser kann unter https://www.microsoft.com/cognitive-services/en-us/sign-up mit einem Microsoft Account (MSA) angefordert werden.

Die Verwaltung der Keys erfolgt unter https://www.microsoft.com/cognitive-services/en-us/subscriptions.

image

In meinem Fall benötige ich das “Face-Preview” Service. Hier muss der Key für die Face-API angezeigt werden (ein Key ist ausreichend) und hier können die Keys verwaltet werden.

Noch ein Wort zu den Preisen: Diese richten sich nach dem Service und der Nutzung. Soweit ich gesehen habe, sind alle Services bis zu einem Volumen von 5,000 transactions per month kostenfrei! Die aktuellen Preise sind unter Preview pricing ersichtlich.

image

Damit können wir das Demoprojekt starten. Zunächst wird in Schritt 1 mit Visual Studio ein neues WPF Projekt angelegt und in Schritt 2 mit dem NuGet Package Manager das Paket Newtonsoft.Json installiert.

Die Cognitive Services sind per HTTPS Request gegen den entsprechenden Cloud-Endpoint aufrufbar. Dieser lautet (siehe Face API - V1.0):

https://api.projectoxford.ai/face/v1.0/detect[?returnFaceId][&returnFaceLandmarks][&returnFaceAttributes]

Für die .NET Plattform gibt es zur einfacheren Nutzung Client Libraries, um die Web-Requests einzukapseln und um das Service bequemer zu verwenden. In Schritt 3 wird nun die Client-Library “Microsoft.Project Oxford.Face” über NuGet wie folgt bezogen.

image

Danach werden die Libraries zu MainWindow.xaml.cs hinzugefügt:

using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;

…und ein Interface mit dem eigenen Subscription Key (aus der eigenen Subscription von oben) in der MainWindow class erstellt:

private readonly IFaceServiceClient faceServiceClient = new FaceServiceClient("Your subscription key");

Das wars schon mit den ersten Vorbereitungen für das App-Framework. Nun geht es um den eigentlichen Code zur Verwendung der Face-API.

Wir verwenden die Face-Detect API um ein Bild direkt upzuloaden. Der Link führt direkt zur Dokumentation des Endpoints. Für asynchrone Methoden kann die DetectAsync methode des FaceServiceClient verwendet werden. Jedes retournierte Gesicht enthält ein Rechteck um die Position im Foto zu markieren, das mit Face Attributes ergänzt ist. In Schritt 4 wird der FaceServiceClient verwendet.

In Schritt 5 des Tutorials wird die ButtonClick Methode async und das Ergebnis ausgewertet. Dabei wird pro erkanntem Gesicht ein rotes Rechteck über die Position gezeichnet. Dazu habe ich ein Schwarz/Weiß-Foto von mir verwendet, das Beispiel zeigt den Output.

image

Sehr schön. Das Beispiel klappt und markiert das erkannte Gesicht auf dem Foto. In meinem Beispiel besteht das Array faceRects aus nur einem Face.

Die Qualität der Bilder muss natürlich ausreichend sein. Auch Gruppenfotos (hier ein Schnappschuss der Audience vom letzten Microsoft Community Open Day in München) liefern beeindruckende Ergebnisse.

image

In Teil 2 interessieren mich jedoch noch weitere Details und was die Face-API so alles erkennen und liefern kann…

Manfred Steyer: Slides and Sample from my talk about the newest new Router in Angular 2 at @angular_berlin in July 2017

Please find below the slides and the sample from my talk about the newest new Router in Angular 2 that I did at @angular_berlin in July 2017.

The samples show:

  • How to configure the router
  • How to create hierarchical routes
  • How to use Aux-Routes
  • How to use Guards, e. g. for Authentication 
  • How to use modern Auth with OAuth2 und OIDC using my npm-package angular2-ouath2

The slides give an outlook to the upcomming lazy-loading features.


Downloads

Christian Giesswein: Developer Week 2016 - Ein Rückblick

Schön war sie, die #dwx16.. und auch schon ein paar Wochen her.
Leider kam ich noch nicht dazu ein paar Worte über diese Konferenz zu verlieren.

Die Developer Week 2016 fand wieder in Nürnberg im Konferenzzentrum statt und ist im .NET Umfeld, im deutschsprachigen Bereich eine der größten Konferenzen mit fast 2000 Teilnehmern. Als Entwickler hat man auf dieser Konferenz glaub ich die Qual der Wahl welchen Vortrag man denn nun besuchen möchte.
Für mich war es als Sprecher eine recht stressige aber sehr schöne Zeit, schließlich war ich mit 4,5 Vorträgen auf der Konferenz vertreten.

Am Montag gleich das erste, spannende Thema "Datenbindung Deluxe – Deep Dive in das Binding von WPF" wo der Saal platzend voll war, sogar vor der Bühne noch Leute im Schneidersitz saßen - als Sprecher immer ein gutes Gefühl und auch die Gespräche im Anschluss zeigten ein hohes Interesse an dem Thema.

Weiter ging es am Montagnachmittag gleich mit "Modulares UI - MVVM mit Prism 6" wo in rasanten 60 Minuten die Grundprinzipien von PRISM erläutert wurde und eine Kleine Basisanwendung mit PRISM entwickelt wurde. Wie üblich bei all meinen Vorträgen, zu 99% mit Visual Studio statt mit Powerpoint - Praxis pur!

Am Dienstag begann der Tag dann etwas ruhiger, da war am Nachmittag dann eine zweistündige "DevSession" zum Thema "Entity Framework und WPF" statt, wo es um die Best Practices im Umgang von Entity Framework MIT WPF ging. Also Erfahrungen womit zwei Technologien zusammengefasst wurden.

Der letzte Tag, am Mittwoch, fing dann bereits in der Früh mit "Visual Studio 2015 Extensions leichtgemacht" an, wo es um das Entwickeln von eigenen Erweiterungen für Visual Studio 2015 ging. Obwohl das Thema sicherlich nicht das gängigste ist, haben sich auch hier sehr viele Teilnehmer eingefunden um in der Früh sich mal über das Thema zu informieren. Dabei kam am Ende eine kleine Erweiterung raus, die "mal eben schnell" von mehreren Projekten in der Solution die .NET Version verändert.

Ging ich aus diesem Vortrag noch raus mit dem Gefühl *puh,.. das war’s* sprangen mein geschätzter Kollege David Tielke und ich für eine Ersatzsession am Nachmittag ein.
Dabei haben wir uns das Thema "Back to the Future - Eine Zeitreise - von C# 1.0 bis 7.0" eine knackige aber sehr unterhaltsame Session zum Thema C# überlegt.
Ich glaube nach dieser Session ist wohl jeder mit sehr guter Laune und einem Lächeln zur Abschlusskeynote von Scott Hanselman gegangen.

Persönlich bleibt mir die Developer Week 2016 in Nürnberg sehr gut in Erinnerung, viele Sprecher als auch Teilnehmer kennt man mittlerweile von den .NET Konferenzen die das ganze Jahr über so vergehen und man geht mit sehr viel neuen Input nach Hause.

Alle Codebeispiele sind auf GitHub veröffentlich und können dort heruntergeladen werden: https://github.com/softwaretirol/conferences
Ich freue mich auf jeden Fall auf eine Developer Week 2017 und hoffe, dass auch die Konferenz wieder so gelungen wird wie die vergangene.

 

Die Unterlagen:

Jürgen Gutsch: Working with user secrets in ASP.​NET Core applications.

In the past there was a study about critical data in GitHub projects. They wrote a crawler to find passwords, user names and other secret stuff in projects on GitHub. And they found a lot of such data in public projects, even in projects of huge companies, which should pretty much care about security.

The most of this credentials are stored in .config files. For sure, you need to configure the access to a database somewhere, you also need to configure the credentials to storages, mail servers, ftp, what ever. In many cases this credentials are used for development, with lot more rights than the production credentials.

Fact is: Secret information shouldn't be pushed to any public source code repository. Even better: not pushed to any source code repository.

But what is the solution? How should we tell our app where to get this secret information?

On Azure, you are able to configure your settings directly in the application settings of your web app. This overrides the settings of your config file. It doesn't matter if it's a web.config or an appsettings.json.

But we can't do the same on the local development machine. There is no configuration like this. How and where do we save secret credentials?

With .Core, there is something similar now. There is a SecretManager tool, provided by the .NET Core SDK (Microsoft.Extensions.SecretManager.Tools), which you can access with the dotnet CLI.

This tool stores your secrets locally on your machine. This is not a high secure password manager like keypass. It is not really high secure, but on your development machine, it provides the possibility NOT to store your secrets in a config file inside your project. And this is the important thing here.

To use the SecretManager tool, you need to add that tool in the "Tools" section of your project.json, like this:

"Microsoft.Extensions.SecretManager.Tools": {
  "version": "1.0.0-preview2-final",
  "imports": "portable-net45+win8+dnxcore50"
},

Be sure you have a userSecretsId in your project.json. With this ID the SecretManager tool assigns the user secrets to your app:

"userSecretsId": "aspnet-UserSecretDemo-79c563d8-751d-48e5-a5b1-d0ec19e5d2b0",

If you create a new ASP.NET Core project with Visual Studio, the SecretManager tool is already added.

Now you just need to access your secrets inside your app. In a new Visual Studio project, this should also already done and look like this:

public Startup(IHostingEnvironment env)
{
    _hostingEnvironment = env;

    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    if (env.IsDevelopment())
    {
        // For more details on using the user secret store see 
        // http://go.microsoft.com/fwlink/?LinkID=532709
        builder.AddUserSecrets();

        // This will push telemetry data through Application 
        // Insights pipeline faster, allowing you to view results 
        // immediately.
        builder.AddApplicationInsightsSettings(developerMode: true);
    }

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

If not arr a NuGet reference to Microsoft.Extensions.Configuration.UserSecrets 1.0.0 in your project.json and add builder.AddUserSecrets(); as shown here.

The Extension Method AddUserSecrets() loads the secret information of that project into the ConfigurationBuilder. If the keys of the secrets are equal to the keys in the previously defined appsettings.json, the app settings will be overwritten.

If this all is done you are able to use the tool to store new secrets:

dotnet user-secrets set key value

If you create a separate section in your appsettings.config as equal to the existing settings, you need to combine the user secret key with the sections name and the settings name, separated by a colon.

I created settings like this:

"AppSettings": {
    "MySecretKey": "Hallo from AppSettings",
    "MyTopSecretKey": "Hallo from AppSettings"
},

To overwrite the keys with the values from the SecretManager tool, I need to create entries like this:

dotnet user-secrets set AppSettings:MySecretKey "Hello from UserSecretStore"
dotnet user-secrets set AppSettings:MyTopSecretKey "Hello from UserSecretStore"

BTW: to override existing keys with new values, just call set the secret again with the same key and the new value.

This way to handle secret data works pretty fine for me.

The SecretManager tool knows three more commands:

  • dotnet user-secrets clear: removes all secrets from the store
  • dotnet user-secrets list: shows you all existing keys
  • dotnet user-secrets remove <key>: removes the specific key

Just type dotnet user-secrets --help to see more information about the existing commands.

If you need to handle some more secrets in your project, it possibly makes sense to create a small batch file to add the keys, or to share the settings with build and test environments. But never ever push this file to the source code repository ;)

Code-Inside Blog: CAKE: Building solutions with C# & Roslyn

x

CAKE - C# Make

  • A DSL for build tasks (e.g. build following projects, copy stuff, deploy stuff etc.)
  • It’s just C# code that gets compiled via Roslyn
  • Active community, OSS & written in C#
  • You can get CAKE via NuGet
  • Before we begin you might want to check out the actual website of CAKE
  • Cross Platform support

Our goal: Building, running tests, package NuGet Packages etc.

I already did a couple of MSBuild and FAKE related blogposts, so if you are interested on these topics as well go ahead (some are quite old, there is a high chance that some pieces might not apply anymore):

Ok… now back to CAKE.

Let’s start with the basics: Building

I created a pretty simple WPF app and followed these instructions.

The build.cake script

My script is a simplified version of this build script:

// ARGUMENTS
var target = Argument("target", "Default");

// TASKS
Task("Restore-NuGet-Packages")
    .Does(() =>
{
    NuGetRestore("CakeExampleWithWpf.sln");
});

Task("Build")
    .IsDependentOn("Restore-NuGet-Packages")
    .Does(() =>
{
      MSBuild("CakeExampleWithWpf.sln", settings =>
        settings.SetConfiguration("Release"));

});

// TASK TARGETS
Task("Default").IsDependentOn("Build");

// EXECUTION
RunTarget(target);

If you know FAKE or MSBuild, this is more or less the same structure. You define tasks, which may depend on other tasks. At the end you invoke one task and the dependency chain will do its work.

Invoke build.cake

The “build.ps1” will invoke “tools/cake.exe” with the input file “build.cake”.

“build.ps1” is just a helper. This Powershell script will download nuget.exe and download the CAKE NuGet-Package and extract it under a /tools folder. If you don’t have problems with binary files in your source control, you don’t need this Powershell script.

Our first CAKE script!

The output is very well formatted and should explain the mechanics behind it good enough:

Time Elapsed 00:00:02.86
Finished executing task: Build

========================================
Default
========================================
Executing task: Default
Finished executing task: Default

Task                          Duration
--------------------------------------------------
Restore-NuGet-Packages        00:00:00.5192250
Build                         00:00:03.1315658
Default                       00:00:00.0113019
--------------------------------------------------
Total:                        00:00:03.6620927

The first steps are pretty easy and it’s much easier than MSBuild and feels good if you know C#.

The super simple intro code can be found on GitHub.

Jürgen Gutsch: How web development changed for me over the last 20 years

The web changed pretty fast within the last 20 years. More and more logic moves from the server side to the client side. More complex JavaScript needs to be written on the client side. And something freaky things happened the last years: JavaScript was moving to the server and Web technology was moving to the desktop. That is nothing new, but who was thinking about that 20 years ago?

The web changed, but also my technology stack. It seems my stack changed back to the roots. 20 years ago, I started with HTML and JavaScript, moving forward to classic ASP using VBScript. In 2001 I started playing around with ASP.NET and VB.NET and used it in in production until the end of 2006. In 2007 I started writing ASP.NET using C#. HTML and JavaScript was still involved, but more or less wrapped in third party controls and jQuery was an alias for JavaScript that time. All about JavaScript was just jQuery. ASP.NET WebForms felled pretty huge and not really flexible, but it worked. Later - in 2010 - I also did many stuff with SilverLight, WinForms, WPF.

ASP.NET MVC came up and the web stuff starts to feel little more naturally again, than ASP.NET WebForms. From an ASP.NET developer perspective, the web changed back to get better, more clean, more flexible, more lightweight and even more naturally.

But there was something new coming up. Things from outside the ASP.NET world. Strong JavaScript libraries, like KnockOut, Backbone and later on Angular and React. The First Single Page Application frameworks (sorry, I don't wanted to mention the crappy ASP.NET Ajax thing...) came up, and the UI logic moves from the server to the client. (Well, we did a pretty cool SPA back in 2005, but we didn't thought about to create a framework out of it.)

NodeJS change the world again, by using JavaScript on the server. You just need two different languages (HTML and JavaScript) to create cool web applications. I didn't really care about NodeJS, except using it in the back, because some tools are based on it. Maybe that was a mistake, who knows... ;)

Now we got ASP.NET Core, which feels a lot more naturally than the classic ASP.NET MVC.

Naturally in this case means, it feels almost the same as writing classic ASP. It means using the stateless web and working with the stateless web, instead of trying to fix it. Working with the Request and Response more directly, than with the classic ASP.NET MVC and even more than in ASP.NET WebForms. It doesn't mean to write the same unstructured, crappy shit than with classic ASP. ;)

Since we got the pretty cool client side JavaScript frameworks and simplified, minimalistic server side frameworks, the server part was reduced to just serve static files and to serve data over RESTish services.

This is the time where it makes sense to have a deeper look into TypeScript. Until now it didn't makes sense to me. I was writing JavaScript for around 20 years, more and less complex scripts, but I never wrote so much JavaScript within a single project, than as I started using AngularJS last years. Angular2 also was the reason to have a deep look into TypeScript, 'cause now it is completely written in Typescript. And it makes absolutely sense to use it.

A few weeks ago I started the first real NodeJS project. A desktop application which uses NodeJS to provide a high flexible scripting run-time for the users. NodeJS provides the functionality and the UI to the users. All written in TypeScript, instead of plain JavaScript. Why? Because TypeScript has a lot of unexpected benefits:

  • You are still able to write JavaScript ;)
  • It helps you to write small modules and structured code
  • it helps you to write NodeJS compatible modules
  • In general you don't need to write all the JavaScript overhead code for every module
  • You will just focus on the features you need to write

This is why TypeScript got a great benefit to me. Sure a typed language is also useful in many cases, but - working with JS for 20 years - I also like the flexibility of the implicit typed JavaScript and I'm pretty familiar with it. that means, from my perspective the Good thing about TypeScript is, I am still able to write implicit typed code in TypeScript and to use the flexibility of JavaScript. This is why I wrote "You are still able to write JavaScript"

The web technology changed, my technology stack changed and the tooling changed. All the stuff goes more lightweight, even the tools. The console comes back and the IDEs changed back to the roots: Just being text editors with some benefits like syntax highlighting and IntelliSense. Currently I prefer to use the "Swiss army knife" Visual Studio Code or Adobe Brackets, depending on the type of project. Both are starting pretty fast and include nice features.

Using that light weight IDEs is pure fun. Everything is fast, because the machines resource could be used by the apps I need to develop, instead by the IDE I need to use to develop the apps. This makes development a lot faster.

Starting the IDE today means, starting cmder (my favorite console on windows). changing to the project folder, starting a console command to watch the typescript files, to compile after save. Starting another console to use the tools like NPM, gulp, typings, dotnet CLI, NodeJS, and so on. Starting my favorite light weight editor to write some code. :)

Jürgen Gutsch: Writing blog posts using Pretzel

Until yet I wrote more than 30 blog posts with Pretzel and it works pretty well. From my current perspective it was a good decision, to do this huge change, to move to that pretty cool and lightweight system.

I'm using MarkdownPad 2 to write the posts. Writing goes much easier. The process is now simplified and publishing is almost automated. I also added my blog CSS to that editor to have a nice preview.

The process of writing and publishing new posts goes like this:

  1. Creating a new draft article and save it in the _drafts folder
  2. Working on that draft
  3. Move the finished article to the _posts folder
  4. Commit and push that post to GitHub
  5. Around 30 seconds later the post is published on Azure

This process allows me to write offline in the train, while traveling to the Office in Basel. This is the most important thing to me.

The other big change, was switching to English. I now get more readers and feedback from around the world. Now the most readers are from the US, UK, India and Russia. But also from the other European countries, Australia, Middle East (and Cluj in Romania).

Maybe I lost some readers from the German speaking Area (Germany, Switzerland and Austria) who liked to read my posts in German (I need to find a good translation service to integrate) and I got some more from around the world.

Writing feels good in both, English and in the MarkdownPad :) From my perspective it was a good decision to change the blog system and even the language.

to learn more about Pretzel, have look into my previous post about using pretzel.

Sven Hubert: WiX Toolset Teil 4: Manuell starten war gestern – Autostart und Conditions

In diesem Teil der WiX-Blog-Serie steht das Thema Autostart im Fokus. Die zwei größten Anwendungsfälle für diese Funktion sind das Starten eines benötigten Services im Hintergrund, sowie eine Komfortfunktion um Programme, die man während der Arbeit benötigt, nicht mehr manuell starten zu müssen. Dazu wird im Laufe einer Installation oft gefragt, ob das installierte Programm beim Systemstart direkt mit ausgeführt werden soll. Wie diese Funktion über einen WiX Installer umgesetzt werden kann, soll im Folgenden beschrieben werden.

Um die Auswahl zu ermöglichen, wird zwischen dem aus Teil zwei der WiX Toolset Blogserie bekannten EULA-Dialog und dem Verifizierungs-Dialog ein weiterer Installationsschritt eingebaut, in dem ausgewählt werden kann, ob bestimmte Funktionen aktiviert werden sollen. In diesem Fall betrifft es das Erstellen des Desktop-Icons sowie das Ausführen der Anwendung beim Systemstart. Der Dialog enthält außer zwei Checkboxen und den bekannten Buttons Back, Next und Cancel keine weitere Logik:

clip_image002[4]

clip_image004[4]

 

Besonders wichtig sind die beiden Controls AutomaticStartup und DesktopCreation. Sie referenzieren jeweils ein Property, welches zusätzlich angelegt werden muss. Um die Übersicht zu behalten, wird empfohlen alle anfallenden Properties in ein eigenes Fragment auszulagern. Im Beispiel wird das Property in dem Fragment angelegt, in dem es von einer Komponente benutzt wird. Innerhalb des DesktopShortcut-Component-Elements wird daraufhin ein zusätzliches Element Condition gelegt, das den Wert der entsprechenden Property überprüft. Das Ergebnis wird im folgenden Screenshot dargestellt:

clip_image006[4]

Dass eine Anwendung beim Systemstart ausgeführt wird, lässt sich auf zwei Arten erreichen: Man kann eine Verknüpfung im StartupFolder von Windows anlegen, oder einen Eintrag in der Registry vornehmen. Der einfachste Weg ist dabei das Hinzufügen einer Verknüpfung in den StartupFolder. Dazu wird der Directory-Struktur der Knoten StartupFolder hinzugefügt, unter dem anschließend ein weiterer Shortcut angelegt wird. Diese Variante bietet zum einen den Charme, sehr simpel zu sein. Des Weiteren kann der Nutzer jederzeit selbstständig ohne größere Komplikationen die Verknüpfung aus dem StartupFolder löschen und somit das Ausführen beim Systemstart verhindern. Ein weiterer Punkt ist die Tatsache, dass der Verknüpfung im StartupFolder Parameter übergeben werden können, die den Programmstart beeinflussen.

clip_image008[4]

Eine weitere Variante, um die Anwendung beim Systemstart auszuführen, ist ein Eintrag in der Registry unter Software \Microsoft\Windows\CurrentVersion\Run. Besonderes Augenmerk sollte darauf auf das Root-Attribut des RegistryValue-Elementes gelegt werden. Dieses Attribut gibt an, ob die Anwendung für die Maschine, also unabhängig vom Nutzer, oder ob sie erst nach der Anmeldung eines bestimmten Nutzers gestartet werden soll. Der Registry-Eintrag zeigt dabei auf die ausführbare Datei im Installationsverzeichnis. Da sich ein Condition-Element stets auf das gesamte Component-Element bezieht, werden für das Setzen des Autostarts über die Registry zwei Component-Elemente benötigt. Dabei enthält die erste Komponente die ausführbare Datei und die zweite das RegistryValue, sowie das Condition-Element zur Überprüfung, ob der Nutzer einen Autostart möchte. Die zweite Komponente wird somit nur installiert, wenn die Condition zutrifft.

clip_image010[4]

Stefan Henneken: IEC 61131-3: Arrays mit variabler Länge

Bei der Deklaration von Arrays musste bisher immer eine konstante Größe angegeben werden. Ab der 3rd Edition der IEC 61131-3 können Arrays mit einer variablen Länge deklariert werden. Funktionen lassen sich dadurch deutlich generischer anlegen als bisher.

Zwar können für die Arraygrenzen auch Variablen benutzt werden, diese Variablen müssen aber als Konstanten deklariert werden. Eine Anpassung der Arraygrenzen zur Laufzeit ist somit nicht möglich.

PROGRAM MAIN
VAR
  arrData             : ARRAY[1..ARRAY_UPPER_BOUND] OF INT;
END_VAR
VAR CONSTANT
  ARRAY_UPPER_BOUND   : INT := 10;	
END_VAR

Gerade wenn Arrays als Parameter an Funktionen oder Funktionsblöcken übergeben werden, stellen feste Arraygrenzen eine unangenehme Limitierung dar. Ist diese nicht hinnehmbar, musste bisher auf Pointerarithmetik gewechselt werden, mit allem Nachteilen. Hier ein einfaches Beispiel, welches die Summe eines eindimensionalen Arrays von LREAL-Variablen berechnet.

FUNCTION F_CalcSum1DimArrayOldSchool : LREAL
VAR_INPUT
  pData           : POINTER TO LREAL;
  nSize           : UDINT;
END_VAR
VAR
  pDataIndex      : POINTER TO LREAL;
  nUpperIndex     : UDINT;
  nIndex          : UDINT;
END_VAR

F_CalcSum1DimArrayOldSchool := 0;
nUpperIndex := nSize / SIZEOF(pDataIndex^);
IF (nUpperIndex > 0) THEN
  FOR nIndex := 0 TO (nUpperIndex - 1) DO
    pDataIndex := pData + (nIndex * SIZEOF(pDataIndex^));
    F_CalcSum1DimArrayOldSchool := F_CalcSum1DimArrayOldSchool + pDataIndex^;	
  END_FOR
END_IF

Die Funktion kann für die Addition beliebiger LREAL-Arrays genutzt werden. Sie ist unabhängig von der Anzahl der Elemente und von der oberen und unteren Arraygrenze.

PROGRAM MAIN
VAR
  array01    : ARRAY[2..8] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1];
  lrSum01    : LREAL;
	
  array02    : ARRAY[-1..2] OF LREAL := [16.1, 34.1, 9.1, 13.1];
  lrSum02    : LREAL;
	
  array03    : ARRAY[-3..-1] OF LREAL := [16.1, 34.1, 8.1];
  lrSum03    : LREAL;
END_VAR
lrSum01 := F_CalcSum1DimArrayOldSchool(ADR(array01), SIZEOF(array01));
lrSum02 := F_CalcSum1DimArrayOldSchool(ADR(array02), SIZEOF(array02));
lrSum03 := F_CalcSum1DimArrayOldSchool(ADR(array03), SIZEOF(array03));

Beispiel 1 (TwinCAT 3.1.4020)

Allerdings hat diese Lösung einige Nachteile. Zum einen eben die Tatsache das Pointerarithmetik benutzt werden muss. Der Quellcode der Funktion wird schon bei relativ einfachen Aufgaben recht komplex. Zum anderen muss an die Funktion auch eine Größen- bzw. Längenangabe übergeben werden. Bei dem Aufruf muss also sichergestellt werden, das der Pointer auf das Array und die Längenangabe übereinstimmen.

Seit der 3rd Edition der IEC 61131-3 können Arrays auch mit variabler Arraygrenze definiert werden. Statt der Arraygrenze, wird ein ’*’ angegeben:

arrData   : ARRAY[*] OF LREAL;

Wird die Funktion aufgerufen, so muss das übergebene Array konstante Arraygrenzen besitzen. In der Funktion kann über die Funktionen LOWER_BOUND und UPPER_BOUND die jeweilige obere- und untere Arraygrenze abgefragt werden.

Derzeit können Arrays mit variabler Länge nur an VAR_IN_OUT Variablen von Funktionen, Funktionsblöcken und Methoden übergeben werden (bleibt zu hoffen, dass in Zukunft auch VAR_INPUT und VAR_OUTPUT Variablen unterstützt werden).

Hier das angepasste Beispiele:

FUNCTION F_CalcSum1DimArray : LREAL
VAR_IN_OUT
  arrData    : ARRAY[*] OF LREAL;
END_VAR
VAR
  nIndex     : DINT;
END_VAR
F_CalcSum1DimArray := 0;
FOR nIndex := LOWER_BOUND(arrData, 1) TO UPPER_BOUND(arrData, 1) DO
  F_CalcSum1DimArray := F_CalcSum1DimArray + arrData[nIndex];
END_FOR

Die Funktion erwartet als Eingangsparameter nur noch ein Array von LREAL-Werten. Die Anzahl der Array-Elemente ist variabel. Mit LOWER_BOUND und UPPER_BOUND kann eine Iteration über das gesamte Array durchgeführt werden. Der Quellcode ist deutlich lesbarer als im ersten Beispiel.

PROGRAM MAIN
VAR
  array01    : ARRAY[2..8] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1];
  lrSum01    : LREAL;
	
  array02    : ARRAY[-1..2] OF LREAL := [16.1, 34.1, 9.1, 13.1];
  lrSum02    : LREAL;
	
  array03    : ARRAY[-3..-1] OF LREAL := [16.1, 34.1, 8.1];
  lrSum03    : LREAL;
END_VAR
lrSum01 := F_CalcSum1DimArray(array01);
lrSum02 := F_CalcSum1DimArray(array02);
lrSum03 := F_CalcSum1DimArray(array03);

Beispiel 2 (TwinCAT 3.1.4020)

Auch werden mehrdimensionale Arrays unterstützt. Bei der Deklaration müssen alle Dimensionen als variabel angelegt werden:

arrData    : ARRAY[*, *, *] OF LREAL;

Der zweite Parameter von UPPER_BOUND und LOWER_BOUND gibt die Dimension an, von der die jeweilige Arraygrenze ermittelt werden soll.

FUNCTION F_CalcSum3DimArray : LREAL
VAR_IN_OUT
   arrData      : ARRAY[*, *, *] OF LREAL;
END_VAR
VAR
   nIndex1, nIndex2, nIndex3  : DINT;
END_VAR
F_CalcSum3DimArray := 0;
FOR nIndex1 := LOWER_BOUND(arrData, 1) TO UPPER_BOUND(arrData, 1) DO
  FOR nIndex2 := LOWER_BOUND(arrData, 2) TO UPPER_BOUND(arrData, 2) DO
    FOR nIndex3 := LOWER_BOUND(arrData, 3) TO UPPER_BOUND(arrData, 3) DO
      F_CalcSum3DimArray := F_CalcSum3DimArray + arrData[nIndex1, nIndex2, nIndex3];
    END_FOR
  END_FOR
END_FOR

Bei dem Aufruf kann ein beliebiges dreidimensionales Array von LREAL-Werten an die Funktion übergeben werden.

PROGRAM MAIN
VAR
  array01    : ARRAY[1..2, 3..4, 5..6] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1, 16.1];
  lrSum01    : LREAL;
END_VAR
lrSum01 := F_CalcSum3DimArray(array01);

Beispiel 3 (TwinCAT 3.1.4020)

Somit lassen sich auch komplexere Aufgaben flexibel umsetzen ohne das auf Pointerarithmetik zurückgegriffen werden muss.

Dieses soll zum Schluss an einem Funktionsblock gezeigt werden, der zwei Matrizen miteinander multipliziert. Die Größen der Matrizen sind variabel:

METHOD PUBLIC Multiplication : BOOL
VAR_IN_OUT
  arrayA     : ARRAY[*, *] OF DINT;
  arrayB     : ARRAY[*, *] OF DINT;
  arrayX     : ARRAY[*, *] OF DINT;	
END_VAR
VAR
  nIndex1, nIndex2, nIndex3, nIndex4   : DINT;
END_VAR;
FOR nIndex1 := LOWER_BOUND(arrayA, 1) TO UPPER_BOUND(arrayA, 1) DO
  FOR nIndex2 := LOWER_BOUND(arrayB, 2) TO UPPER_BOUND(arrayB, 2) DO
    nIndex4 := 0;
    FOR nIndex3 := LOWER_BOUND(arrayA, 2) TO UPPER_BOUND(arrayA, 2) DO
      nIndex4 := nIndex4 + arrayA[nIndex1, nIndex3] * arrayB[nIndex3, nIndex2];
    END_FOR;
    arrayX[nIndex1, nIndex2] := nIndex4;
  END_FOR;
END_FOR;

Die Methode kann mit unterschiedlich großen Arrays aufgerufen werden.

PROGRAM MAIN
VAR
  fbMatrix     : FB_Matrix;
  arrayA1      : ARRAY[1..2, 1..2] OF DINT := [1, 2, 3, 4];
  arrayB1      : ARRAY[1..2, 1..2] OF DINT := [5, 6, 7, 8];
  arrayX1      : ARRAY[1..2, 1..2] OF DINT;
	
  arrayA2      : ARRAY[1..3, 1..3] OF DINT := [1, 2, 3, 4, 5, 6, 7, 8, 9];
  arrayB2      : ARRAY[1..3, 1..3] OF DINT := [5, 6, 7, 8, 10, 11, 12, 13, 14];
  arrayX2      : ARRAY[1..3, 1..3] OF DINT;				
END_VAR
fbMatrix.Multiplication(arrayA1, arrayB1, arrayX1);
fbMatrix.Multiplication(arrayA2, arrayB2, arrayX2);

Beispiel 4 (TwinCAT 3.1.4020)


friends header

bloggers headline

links header

 
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.