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

codefest.at [MS]: Neues in PowerApps

PowerApps ermöglichen Power-Usern rasch und einfach Formulare aus verschiedenen Datenquellen innerhalb des Unternehmens bereitszustellen. Hier gibt es nun eine Neuerungen, mehr dazu hier.

Wie in “Turn data into apps” mit PowerApps beschrieben, können mit der PowerApp und den installierten PowerApp Clients (für Windows, iOS und Android) kleine Lösungen ohne Programmieraufwand erzeugt werden. Es gib eine ganze Reihe von möglichen Datenquellen, und natürlich kann man auch selbst eigene OData-Schnittstellen erstellen und verwenden.

image

Im PowerApps-Blog gibt es nun einige Neuerungen, siehe

Introducing support for lookups and a new sample app.

Die aktuellste PowerApps Build 2.0.440 bringt drei neue Features, die ich der Einfachheit halber mal 1:1 hier übernehme:

  1. Options and tools rights side panels are now merged into one experience. In the new right side panel, you always see the relevant set of options for the object you select on the canvas. When you select an app screen, for example, you can use the options panel to add data sources to the app. When you select a form, you can use the panel to select the fields to use from the data source.  Panels like Share, Advanced and Flows open on top. You can dismiss them anytime and automatically get back to the options panel.
  2. A new Lookups Control is now available to use on your forms, and it comes all wired in when you create an app from data. You can further configure the field to display from the lookup list.
  3. Our newest sample app called Showcase is ready to try out! The functionality is focused on presenting assets, products or events. Take a look on the great design language and layouting ideas.

Besonders erwähnenswert finde ich die neuen “Lookup Controls”. Damit sind nun Lookups in Formularen möglich. Das ist besonders für SharePoint Online Datenquellen relevant, wo CustomLists mit Lookups zu anderen Listen definiert sind (bislang wurden diese Felder einfach ignoriert).

Der folgende Screenshot aus dem Blogartikel zeigt diese Funktionalität.

image

Somit: Viel Spaß beim Basteln von unternehmenseigenen (Power)Apps!

Norbert Eder: Visual Studio 2015: Sprache ändern

Ich habe heute Visual Studio 2015 versehentlich in Deutsch installiert. Da ich allerdings Englisch bevorzuge, stellte sich die Frage, ob ich die Sprache ohne Neuinstallation ändern kann (denn von Haus aus unterstützt das Visual Studio nicht). Kann man:

Dazu gibt es ein Visual Studio 2015 Language Pack.

Nach der Installation findet sich ein neuer Eintrag in den Optionen: Internationale Einstellungen:

Visual Studio 2015 - Sprache wechseln

Visual Studio 2015 – Sprache wechseln

Damit die Änderungen wirksam werden ist Visual Studio neu zu starten.

Danke Dariusz für den Tipp.

The post Visual Studio 2015: Sprache ändern appeared first on Norbert Eder.

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

Wolfgang Kinkeldei: FAKE und Sass

Gerne wird CSS nicht mehr direkt selbst geschrieben, sondern mit Präprozessoren wie z.B. SASS erzeugt. Schnell werden dann Projekte mit meist node.js basierenden Hilfsprogrammen ausgestattet, die lokal natürlich immer prima funktionieren, aber auf CI-Servern durchaus Probleme bereiten können. Genau das ist uns kürzlich passiert.

Kurzerhand haben wir beschlossen, die wesentlichen Schritte auf unserem CI Server durch entsprechende Funktionalitäten von FAKE zu ersetzen, was neben durchgängiger Versionskontrolle nur noch Abhängigkeiten von NuGet Paketen hatte.

Und eine Bibliothek für die Compilierung von SASS in das FAKE Script einzubauen war selbst für mich als F# Neuling nicht das große Problem.

Die relevanten Teile des Build Scripts sehen so aus – vermutlich lässt sich noch einiges daran verbessern aber die Abhängigkeit zu "Fremdkörpern" ist hiermit verschwunden:

#r @"packages/FAKE/tools/FakeLib.dll"
#r @"packages/libsassnet/lib/net40/LibSass.x86.dll"
#r @"packages/libsassnet/lib/net40/libsassnet.dll"

open Fake
open System.IO
open LibSassNet

let compileScss files =
    let compile file =
        let filename ext = Path.ChangeExtension(file, ext)

        let compiler = new LibSassNet.SassCompiler()

        tracefn "Compiling %s..." file

        let generateOutput outputStyle cssFile =
            let mapFile = cssFile + ".map"
            let result = compiler.CompileFile(file, outputStyle, mapFile)
            File.WriteAllText(cssFile, result.CSS)
            File.WriteAllText(mapFile, result.SourceMap)

        generateOutput LibSassNet.OutputStyle.Compact (filename ".css")
        generateOutput LibSassNet.OutputStyle.Compressed (filename ".min.css")

    files

        |> Seq.iter compile

// Targets (Auszug)
Target "Css" (fun _ ->
    !! "**/Content/*.scss"
        |> compileScss


)
...

codefest.at [MS]: Spielen mit dem SQL Server 2016 in Azure

Seit 1. Juni ist Microsoft SQL Server 2016 RTM zum Download verfügbar, siehe SQL Server 2016 RTM ist hier. Für Developer ist es natürlich interessant, mit den neuesten Bits zu spielen und eigene Apps dafür zu optimieren. Das geht nun ganz einfach, ohne eigene, zeitintensives Setup!

Seit kurzem ist ein SQL Server 2016 Developer Image in der Azure Marketplace verfügbar, siehe Announcing SQL Server 2016 Developer image in the Azure Gallery.

image

Die SQL Server Developer Edition ist die voll ausgestattete, “free licensed version of SQL Server”, die zum Entwickeln und Testen von Apps mit SQL Server dient. Sie ist funktionsmäßig ident mit der SQL Server 2016 Enterprise Version und bietet Features wie In-Memory OLTP und DW, Advanced Analytics, Availability Groups, Row-Level Security, etc.)

Das VM-Image besitzt keinerlei Limitierungen (memory, storage, etc.), darf aber nicht für die Produktion verwendet werden. Die VM Größe kann von A0 bis GS5 beliebig gewählt werden. Microsoft empfiehlt, die VM bei Nicht-Gebrauch zu pausieren.

Hier gehts los mit dem Provisionieren des SQL Server 2016 Developer Images.

PS: Wer eine freie Bürowand hat: Hier gibt es übrigens ein fesches Microsoft SQL Server 2016 Poster zum Download…

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

Alexander Schmidt: ReSharper verhindert SmartTag-Shortcut

SmartTag-Shortcut mit ReSharper-Installation beheben.

Kay Giza [MS]: PDF-Download: Microsoft Azure verstehen - ein Leitfaden fuer Entwickler

Das PDF-Dokument ist kostenfrei und ohne Registrierung frei erhältlich. Unter dem Titel 'Azure verstehen - ein Leitfaden für Entwickler' hat Microsoft ein rund 40 Seiten langes deutschsprachiges PDF veröffentlicht. Der Leitfaden beschreibt das Warum und Wie von Microsoft Azure Szenarien... [... 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

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

Johannes Renatus: Angular 1.5 Component Template in TypeScript

Seit Angular 1.5 gibt es noch eine neue Möglichkeit um Direktiven zu erstellen. Der neue Typ nennt sich “component” und bietet einige Vorteile gegenüber der klassischen Direktive. Dazu gehören z.B. die einfachere Konfiguration, da viele Werte bereits vorkonfiguriert sind mit den am häufigsten verwendeten Werten. Dann ist bereits die ControllerAs Syntax eingebaut, in dem man […]

Sven Hubert: WiX Toolset Teil 3: Wo war das noch gleich? – Shortcuts und Uninstall

Wer kein ausgefeiltes Ordnungssystem auf seiner Festplatte einhält, kennt mit Sicherheit das folgende Szenario: Nur mal schnell zum Testen eine kleine Anwendung installieren, sich schnellstmöglich durch den Installationsassistenten klicken, der Ladebalken läuft auch schnell durch und dann muss man verwirrt innehalten. Wo genau wurde die Anwendung jetzt nochmal installiert? Auf dem Desktop ist keine Verknüpfung, im Startmenü gibt es keinen neuen Eintrag, erst die Windows-Suche liefert den Installationspfad und aus dem „nur mal schnell“ wurden ein paar Minuten.

Um von Entwicklerseite solche Szenarien beim Anwender zu vermeiden, helfen Desktopverknüpfungen und Startmenüeinträge. Der dritte Teil der WiX Toolset Blogserie zeigt auf, wie die entsprechenden Verknüpfungen während der Installation angelegt werden können. Darüber hinaus müssen alle Komponenten auch wieder sauber entfernt werden, sobald die Anwendung deinstalliert wird.

Wie bereits im ersten Teil der WiX Toolset Blogserie dargestellt, folgen auch Desktop Shortcuts und Startmenüeinträge dem bekannten Muster aus Components, die einem Pfad zugeordnet werden und die eigentliche Datei enthalten. Bevor das Components-Element deklariert wird, muss jedoch zuerst wieder die Ordnerhierarchie aufgebaut werden. Dazu bedienen wir uns der mitgelieferten Standardwerte um zum ProgramMenuFolder und dem DesktopFolder zu navigieren. Im Folgenden wird eine Struktur dargestellt, die den Ordner „AIT“ unterhalb von „Program Files“ und einen zweiten Ordner „AIT“ im Startmenü anlegt. Zusätzlich wird mit dem <Directory Id=“DesktopFolder“ /> die Möglichkeit geschaffen, Dateien auf dem Desktop anzulegen.

clip_image001

Dies erfolgt, wie schon bekannt, über ein Component, das im entsprechenden DirectoryRef-Element erstellt wird. Dieses Component-Element erhält in diesem Fall drei Kindelemente. Dabei handelt es sich um ein Shortcut-Element, das den eigentlichen Shortcut enthält, ein RegistryValue-Element, das den KeyPath der Komponente enthält und ein RemoveFolder/File-Element, um die Deinstallation zu ermöglichen. Das RegistryValue-Element ist notwendig, da ein Shortcut-Element, im Gegensatz zu einem File-Element, nicht selbst als KeyPath fungieren kann. Der Windows-Installer überprüft vor der Installation, ob der entsprechende KeyPath bereits vorhanden ist und führt die Installation der Komponente nur durch, wenn dies nicht der Fall ist. Der Folgende Screenshot zeigt, wie das Component-Element für den Startmenüeintrag aufgebaut wird.

clip_image003

Das Shortcut-Element enthält den Namen des Shortcuts sowie die Zieldatei und das WorkingDirectory. Der Shortcut wird in diesem Fall auf die Datei Demo.exe im zuvor definierten Verzeichnis unterhalb des Ordners „Program Files“ zeigen und diese ausführen.

Uninstall

Das RemoveFolder-Element enthält mindestens zwei Attribute. Eine eindeutige ID sowie das Attribut „On“, das den Vorgang bezeichnet, während welchem der Ordner entfernt werden soll. Hier sind die Werte Uninstall, Install und Both möglich. Welcher Ordner entfernt wird, wird dadurch bestimmt, in welchem DirectoryRef-Element sich die Komponente befindet. Der Folgende Screenshot zeigt ein Component-Element, das den Anwendungsordner in den „Program Files“ entfernt. Dabei werden alle Files des Ordners über RemoveFile-Elemente entfernt. Um hier mehrere Dateien auf einmal zu löschen, können für den Dateinamen Wildcards vergeben werden. Abschließend wird noch der Ordner über das bekannte RemoveFolder-Element gelöscht. Ist ein Registry-Eintrag als KeyPath einer Komponente hinterlegt, wie im Beispiel der Shortcuts oben, so erfolgt das Entfernen des Eintrags automatisch mit dem Entfernen der Komponente.

clip_image005

Eventuell möchte ein Nutzer aber gar keinen Desktop-Shortcut anlegen? Oder er möchte die Anwendung lieber direkt mit dem Systemstart ausführen? Wie diese beiden Anwendungsfälle mit dem WiX Toolset abgebildet werden können, lesen sie im vierten Teil der WiX Toolset Blogserie.

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

codefest.at [MS]: #techsrus - Techs"R"Us Live Streaming Event

Am Dienstag, dem 21. Juni 2016, ab 9 Uhr werden unsere deutschen Microsoft-Kollegen mit der Fachkonferenz Techs"R"Us der Technologie eine Bühne geben – der Technologie, mit der wir tagtäglich arbeiten, die uns begeistert, vor ungeahnte Herausforderungen stellt, zur Verzweiflung bringt, aber auch sensationelle Lösungen ermöglicht. Mit einer bunt gemischten Agenda werden wir das Thema von all diesen genannten Perspektiven beleuchten und so unsere Lust und Freude an Technik mit dem Publikum teilen, um vor allem eines zu zeigen: Wir sind Techies aus Leidenschaft!

Die Agenda (siehe unten) der virtuellen Konferenz umfasst einen weiten thematischen Bogen und beinhaltet insgesamt acht Vorträge. Inhaltlich wird es u.a. um agile Teambuilding-Methoden, das Leben und Sterben von Side-Projekten, Einhorn-Entwickler oder, wie man innerhalb von sieben Wochen zum Spieleentwickler wird, gehen. Technischer wird es bei den Sessions rund um den richtigen Einsatz von Docker, ob Mixed Reality unser Leben verändern wird, wie die Blockchain wirklich funktioniert und welche Kniffs in Xcode noch versteckt sind.

Die Kollegen freuen sich auf euer virtuelles Kommen und auf reges Tweeten unter dem Hashtag #techsrus während der Veranstaltung. Du kannst auch gerne während der Talks Fragen stellen – ganz einfach via Twitter mit dem Hashtag #techsrus. So können wir am Ende jeder Session noch eine kurze Q&A-Runde einlegen, bei der unsere Experten die Fragen beantworten.    

     
Agenda
 

09:00 - 09:45

Introduction to Blockchain with Ethereum hands-on 

10:00 - 10:45

From Zero to Launch In Seven Weeks 

11:00 - 11:45

Funktioniert bei mir? Nein: Funktioniert überall. Mit Docker! 

12:00 - 12:45

The Past, Present and Future of Augmented Reality 

13:00 - 13:45

Xcode Trickkiste 

14:00 - 14:45

Developer's Journey, Wie Einhorn-Entwickler am besten gezüchtet werden 

15:00 - 15:45

Außen agil, innen fragil?

16:00 - 16:45

Tales from the trenches: Navigating the maze of ideas, technology, and marketing 

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

codefest.at [MS]: #Ch9weekly - JSON in Hadoop and Hive

 

Jede Woche stellen wir ein interessantes Channel 9 Video für Euch hier zur Verfügung, damit Ihr stets einen Wissensvorsprung haben könnt.

In diesem Video wird erläutert, wie man JSON in einem Big Data Umfeld von Hadoop/ Hive effizient nutzen kann.

 

codefest.at [MS]: Build 2016 Redelivery Event

Letzten Donnerstag, den 16. Juni, fand bei Microsoft in Wien das Build 2016 Redelivery Event statt. Microsoft hatte eingeladen, sich persönlich über “Das neueste zu Windows 10 und anderen coolen Dingen – Zusammenfassung von der //build” zu informieren.

Im TechNet Blog findet ihr einige visuelle Eindrücke vom Event:
Snapshots vom Build 2016 Redelivery Event bei Microsoft Wien

image

Wir sammeln noch alle Session-Slides. Die ersten gibt es bereits hier zum Download (wir befüllen diese nach und nach, bitte in den nächsten Tagen nachsehen…): Session Slides of Build 2016 Redelivery Event Vienna

Es war ein cooles Community Event! Vielen Dank an alle Teilnehmer, an alle Sprecher und an die Organisatoren und Microsoft Österreich als Event-Sponsor!

Manfred Steyer: Influencing Routing with Guards using the new Angular-2-Router

The German version of this article can be found here.
Version: This article uses Angular 2 RC2 with @angular/router 3.0.0-alpha6, which was the current version in June 2016.

Using Guards, Angular-2-Applications can get informed about changes to the current route by the new Angular-2-Router that is available since June 2016. These Guards are just services and replace the lifecycle-hooks of the BETA-router. Their methods that are defined by interfaces are called by the router when it activates or deactivates a component. The returned value defines whether the router is allowed to perform the requested route-change. Valid values are true, false and Observable<boolean>. The latter one allows to postpone the decision so that the application can delegate to a service or talk to the user before making up its decision.

For implementing guards, the router provides two interfaces: CanActivate defines the method canActivate that is executed by the router before activating a component. The interface CanDeactivate in turn comes with a method canDeactivate that is executed before deactivating a component. This article shows how an application can use canDeactivate to ask the user for permission before leaving a component. The sourcecode for this sample can be found here.

sample

Installing the new router

To get the new router, one has to install version 3 of the package @angular/router. When this text was written, the QuickStart-Sample at angular.io still used version 2. In this case the following entry within the file package.json has to be updated. To install this version, one can call npm install after that.

"dependencies": {
    [...]
    "@angular/router":  "3.0.0-alpha.6"
}

Implementing a Guard

The here presented guard is a simple Angular-2-Service that implements the interface CanDeactivate. This interface has to be parametrised with the type of the component it is indented for:

import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import { FlightEditComponent} from './flight-edit.component';

export class FlightEditGuard implements CanDeactivate<FlightEditComponent> {

    canDeactivate(
            component: FlightEditComponent, 
            route: ActivatedRouteSnapshot, 
            state: RouterStateSnapshot) {

                return component.canDeactivate();
    }

}

Implementing the component

The method canDeactivate takes the instance of the component in question as well as parameters that inform about the current and the requested future state of the router. The here described implementation delegates to the component so that it can display a warning for the user.

The method canDeactivate within the component which is called by the guard sets the property exitWarning.show to true to show the warning. This warning asks the user whether they really want to leave the route. As canDeactivate has to wait for their decision it returns an Observable<boolean> and stores the equivalent Observer<boolean> into exitWarning.observer.

The method decide takes the decision from the user and hides the warning by setting exitWarning.show back to false. After that, it sends the received decision to the router by using the Overserver.

import { Component} from '@angular/core';
import { ActivatedRoute} from '@angular/router';
import { Observable, Observer} from 'rxjs';

@Component({
    template: require('./flight-edit.component.html')
})
export class FlightEditComponent {

    [...]    

    exitWarning = {
        observer: null,
        show: false
    }

    decide(d: boolean) {
        this.exitWarning.show = false;
        this.exitWarning.observer.next(d);
        this.exitWarning.observer.complete();
    }

    canDeactivate() {
        this.exitWarning.show = true;
        return new Observable<boolean>((sender: Observer<boolean>) => {
            this.exitWarning.observer = sender;

        });
    }

}

The template for the warning can be found in the next listing. It shows the warning in lieu of exitWarning.show. The descion of the user is delegated to the method decide.

<div *ngIf="exitWarning.show" class="alert alert-warning">
        <div>
        Daten wurden nicht gespeichert! Trotzdem Maske verlassen?
        </div>
        <div>
            <a href="javascript:void(0)" (click)="decide(true)" class="btn btn-danger">Ja</a>
            <a href="javascript:void(0)" (click)="decide(false)" class="btn btn-default">Nein</a>
        </div>
</div>

Registering the guard within the router-configuration

To register the guard for a component, its entry within the router-configuration has to point to it via the array canDeactivate:

const APP_ROUTES: RouterConfig = [
    {
        path: '/home',
        component: HomeComponent,
        index: true
    },
    {
        path: '/flight-booking',
        component: FlightBookingComponent,
        children: [
            {
                path: '/flight-search',
                component: FlightSearchComponent
            },
            {
                path: '/passenger-search',
                component: PassengerSearchComponent
            },
            {
                path: '/flight-edit/:id',
                component: FlightEditComponent,
                canDeactivate: [FlightEditGuard]
            }
        ]
    }
];

Strictly speaking, canDeactivate only points to a token which has to be bound to a service with a provider. The following listing creates a provider-array that contains such a provider using the usual abbreviated form:

export const APP_ROUTER_PROVIDERS = [
    FlightEditGuard,
        // the same as: 
        //     provide(FlightEditGuard, {useClass: FlightEditGuard})
    provideRouter(APP_ROUTES),
];

To make Angular 2 respect this provider-array the sample in question includes it into a further provider-array that is passed to bootstrap:

var providers = [
  APP_ROUTER_PROVIDERS,
  HTTP_PROVIDERS
];

bootstrap(AppComponent, providers);

Marco Scheel: Links for 2016-06-17 [del.icio.us]

Manfred Steyer: Mit Guards ins Routing des Angular-2-Routers eingreifen

Mit Guards können sich Angular-2-Anwendungen über Routenwechsel des neuen, seit Juni 2016 zur Verfügung stehenden Angular-2-Routers (Version 3) informieren lassen. Dabei handelt es sich lediglich um Services, welche die Lifecycle-Hooks des "BETA-Routers" ablösen. Ihre über Interfaces vorgegebenen Methoden ruft der Router beim Deaktivieren einer Komponente bzw. beim Aktivieren einer neuen Komponente auf. Der zurückgelieferte Wert bestimmt, ob der Router den angeforderten Routenwechsel tatsächlich durchführen darf. Hierzu kommen true, false oder ein Observable<boolean> zum Einsatz. Letzteres erlaubt das Hinauszögern der Entscheidung, um zum Beispiel eine Web API zu konsultieren oder Rücksprache mit dem Benutzer zu halten.

Der Router bietet für die Implementierung von Guards zwei Interfaces: CanActivate definiert die Methode canActivate, welche der Router vor dem Aktivieren einer Komponente anstößt. Das Interface CanDeactivate kommt analog dazu mit der Methode canDeactivate, die der Router vor dem Deaktivieren einer Komponente zur Ausführung bringt. Dieser Beitrag zeigt, wie eine Anwendung mit canDeactivate vor dem Verlassen einer Route eine Bestätigung vom Benutzer einholen kann. Der gesamte Quellcode findet sich hier.

Installation des neuen Routers

Um den neuen Router zu beziehen, ist die Version 3 des Paketes @angular/router zu installieren. Als dieser Text geschrieben wurde, verwies das QuickStart-Sample auf angular.io noch auf Version 2. In diesem Fall ist der nachfolgende Eintrag in der Datei package.json zu aktualisieren. Ein Aufruf von npm install installiert Version 3 des Routers anschließend.

"dependencies": {
    [...]
    "@angular/router":  "3.0.0-alpha.6"
}

Implementierung des Guards

Beim hier verwendeten Guard handelt es sich um einen einfachen Angular-2-Service, der das Interface CanDeactivate implementiert. Dieses Interface ist mit dem Typ der Komponente, um welche sich der Guard kümmert, zu parametrisieren:

import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import { FlightEditComponent} from './flight-edit.component';

export class FlightEditGuard implements CanDeactivate<FlightEditComponent> {

    canDeactivate(
            component: FlightEditComponent, 
            route: ActivatedRouteSnapshot, 
            state: RouterStateSnapshot) {

                return component.canDeactivate();
    }

}

Implementierung der Komponente

Die Methode canActivate nimmt die betroffene Instanz dieser Komponente sowie Parameter, welche über den aktuellen Zustand sowie künftigen Zustand des Routers informieren, entgegen. Die hier beschriebene Implementierung delegiert an die Komponente, damit diese für den Benutzer eine Warnmeldung einblendet.

Die Methode canDeactivate der Komponente, welche auf diesem Weg zur Ausführung kommt, setzt die Eigenschaft exitWarning.show auf true. Damit blendet sie die Warnmeldung ein. Diese fragt den Benutzer, ob er tatsächlich die aktuelle Route verlassen möchte. Da canActivate die Antwort des Benutzers abwarten muss, liefert sie ein Observable<boolean> zurück und verstaut den dazu passenden Observer<boolean> in der Eigenschaft exitWarning.observer.

Die Methode decide nimmt diese Entscheidung entgegen und blendet die Warnmeldung wieder aus, indem sie die Eigenschaft exitWarning.show auf false zurücksetzt. Danach gibt sie über den vorhin erhaltenen Observer die Entscheidung an das Observable und somit an den Router weiter.

import { Component} from '@angular/core';
import { ActivatedRoute} from '@angular/router';
import { Observable, Observer} from 'rxjs';

@Component({
    template: require('./flight-edit.component.html')
})
export class FlightEditComponent {

    [...]    

    exitWarning = {
        observer: null,
        show: false
    }

    decide(d: boolean) {
        this.exitWarning.show = false;
        this.exitWarning.observer.next(d);
        this.exitWarning.observer.complete();
    }

    canDeactivate() {
        this.exitWarning.show = true;
        return new Observable<boolean>((sender: Observer<boolean>) => {
            this.exitWarning.observer = sender;

        });
    }

}

Das Template für die Warnmeldung findet sich im nächsten Listing. Es blendet die Warnmeldung in Abhängigkeit von exitWarning.show mittels *ngIf ein. Die Entscheidung des Benutzers, welche die Warnung über einen der beiden Links entgegennimmt, delegiert das Template an die Methode decide weiter.

<div *ngIf="exitWarning.show" class="alert alert-warning">
        <div>
        Daten wurden nicht gespeichert! Trotzdem Maske verlassen?
        </div>
        <div>
            <a href="javascript:void(0)" (click)="decide(true)" class="btn btn-danger">Ja</a>
            <a href="javascript:void(0)" (click)="decide(false)" class="btn btn-default">Nein</a>
        </div>
</div>

Guard in Router-Konfiguration registrieren

Um den Guard für eine Komponente zu registrieren, verweist der betroffene Eintrag der Router-Konfiguration über das Array canDeactivate darauf:

const APP_ROUTES: RouterConfig = [
    {
        path: '/home',
        component: HomeComponent,
        index: true
    },
    {
        path: '/flight-booking',
        component: FlightBookingComponent,
        children: [
            {
                path: '/flight-search',
                component: FlightSearchComponent
            },
            {
                path: '/passenger-search',
                component: PassengerSearchComponent
            },
            {
                path: '/flight-edit/:id',
                component: FlightEditComponent,
                canDeactivate: [FlightEditGuard]
            }
        ]
    }
];

Genaugenommen verweist canDeactivate lediglich auf ein Token, welches im Rahmen eines Provider-Arrays an einen Service zu binden ist. Das nachfolgende Listing nutzt hierzu die übliche Kurzschreibweise, um den Service FlightEditGuard an das gleichnamige Token zu binden:

export const APP_ROUTER_PROVIDERS = [
    FlightEditGuard,
        // entspricht: 
        //     provide(FlightEditGuard, {useClass: FlightEditGuard})
    provideRouter(APP_ROUTES),
];

Damit Angular 2 dieses Provider-Array berücksichtigt, nimmt es das hier beschriebene Beispiel in ein weiteres Provider-Array auf. Anschließend übergibt es dieses Provider-Array an bootstrap. Auf diese Weise nutzt das Beispiel die Tatsache, dass eine Angular-Anwendung Provider-Arrays beliebig verschachteln kann:

var providers = [
  APP_ROUTER_PROVIDERS,
  HTTP_PROVIDERS
];

bootstrap(AppComponent, providers);

Sven Hubert: Gib jedem was er will!?

Um sich Wettbewerbsvorteile zu verschaffen, werden von Kunden individuelle Lösungen benötigt und gefordert. Gleichzeitig soll eine solche Lösung kostengünstig umgesetzt und fortlaufend weiterentwickelt werden. Steht dies nicht im Widerspruch zueinander?

Im Artikel Individualisierung von Standardsoftware – Gib jedem, was er will welcher kürzlich in der Informatik Aktuell erschienen ist, finden Sie die Antwort auf diese Frage. In unserem Download-Bereich steht der Artikel als PDF zur Verfügung.

Sven Hubert: Qualität als Konzept: In 7 einfachen Schritten zu qualitativ hochwertige(re)n Test Cases im TFS!

Ein Testfall beschreibt eine Reihe auszuführender Aktionen sowie die zu erwartenden Ergebnisse dieser Aktionen. Der Sinn eines Testfalles ist es, eine bestimmte Funktionalität eines Testobjektes zu verifizieren. Testfälle sind der erste Schritt im gesamten Testing Lifecycle und bilden somit den Grundstein für eine hohe Qualität im selbigen. Dabei wird die Qualität von Testfällen zunächst durch zwei Faktoren bestimmt:

Zum einen ist es essentiell, das Richtige zu testen. Dafür müssen die relevanten Anwendungsszenarien bekannt sein (“Doing the right thing”). Auf der anderen Seite müssen die Testfälle die Wege durch diese Anwendungsszenarien so beschreiben, dass sie von den Testern eindeutig nachvollzogen werden können (“Doing the things right”). Doch was bedeutet dies konkret und wie sieht ein “guter” Testfall aus?

Leider gibt es kein allgemeingültiges Rezept um diese Fragen zu beantworten. Daher stellen wir in diesem Blogbeitrag 7 Tipps aus der Praxis vor, welche es mit den im TFS zur Verfügung stehenden Mitteln ermöglichen, die Qualität von Testfällen zu verbessern:

  1. Verwendung von Namenskonventionen für Titel von Testfällen: Die Titel von Testfällen sollten einem definierten Schema genügen. Dies dient dem Zweck, allen am Testprozess Beteiligten auf den ersten Blick ersichtlich zu machen, was getestet wird und damit ein einheitliches Verständnis zu fördern. Es sollte vermieden werden, unnötige Bestandteile in die Namenskonvention aufzunehmen. So ist z.B. das verbreitete Präfix TC (für Test Case) redundant, da der Work Item Typ in jeder Ansicht des TFS leicht ersichtlich ist. Ein beispielhaftes Namensschema ist %Zu testendes Modul%_%Zu testende Funktion%. Ein Testfall des Logins einer Web Applikation würde gemäß dieser Konvention einen Titel wie LoginPage_ValidateUserCredentials tragen.
  2. Einbeziehung des Domänenwissens von Testern: Mit Hinblick auf die Granularität der Testschritte ist es essentiell, das Domänenwissen von Testern zu berücksichtigen. Werden die Testfälle von Testern durchgeführt, welche kein fachliches Wissen über das Testobjekt besitzen, so müssen die Testfälle sehr feingranular beschrieben werden. Sind für die Testausführung hingegen Tester mit Expertenwissen verantwortlich, so können gewisse Aspekte vorausgesetzt werden, wodurch eine weniger detaillierte Beschreibung der Testfälle ausreichend ist.
  3. Berücksichtigung der Teststufe: Ein weiterer Aspekt, der sich auf die Granularität der Testschritte auswirkt, ist die Teststufe, auf welcher ein Test angesiedelt ist. Ein Integrationstest z.B. testet das Zusammenspiel mehrerer Komponenten und damit ganze Prozesse innerhalb eines Produktes . Hierbei kann oft aufgrund des Umfangs eines solchen Tests nicht jeder Schritt bis ins kleinste Detail spezifiziert werden. Ein funktionaler Test hingegen testet auf unterster Ebene eine einzige Einheit eines Produktes auf Bases einer funktionalen Spezifikation und sollte sehr detailliert beschrieben werden.
  4. Einheitliches Wording: Bei der Formulierung der Testschritte sollte darauf geachtet werden, keine Synonyme für dieselbe Bedeutung zu verwenden, sondern ein einheitliches Wording über alle Testfälle hinweg zu erreichen. So sollte beispielsweise nicht in einem Schritt die Formulierung “Drücken Sie den Button Login” und in einem anderen die Formulierung “Klicken Sie auf die Schaltfläche Logout” verwendet werden. Beide Formulierungen beschreiben dieselbe Tätigkeit und sollten daher auf dieselbe Weise beschrieben werden. In diesem Kontext kann es sich als nützlich erweisen ein zentralen Glossar (auch über den Bereich des Testings hinaus) einzuführen um die Verwendung eines einheitlichen Wordings zu erleichtern. Dies reduziert Unklarheiten und verbessert das Verständnis des Testers.
  5. Einheitliche Beschreibung von Navigationspfaden: Wie ein einheitliches Wording, so fördert auch die einheitliche Beschreibung von Navigationspfaden die Lesbarkeit und das Verständnis von Testfällen. Dabei ist zu beachten, dass Navigationspfade von außen nach innen beschrieben werden sollten um damit den Tester vom groben zum genauen Ort über die Oberfläche zu führen. Befindet man sich beispielsweise auf der Login/Logout Seite für Downloads von Produkten der AIT (vgl. Abb. 1), so kann man mehrere Bereiche erkennen wie z.B. die Navigationsleiste oder den Bereich Registrieren. Möchte man nun also den Tester zu der Textbox Benutzername im Bereich Benutzeranmeldung führen, so sollte mit dem äußeren Element begonnen werden. Man könnte also schreiben “Benutzernamen im Bereich Benutzeranmeldung in der Textbox Benutzernamen angeben.”. Des weiteren ist es wichtig, ein einheitliches Schema für die Beschreibung von Navigationspfaden zu definieren. Anstatt die Pfade ausformuliert zu beschreiben sollte ein kompaktes Schema durch Nutzung von Trennzeichen wie “|” oder “—>” verwendet werden. Ebenso sollte definiert werden, ob Beschreibungswörter wie Bereich und Textbox miteinbezogen werden sollen oder nicht. Eine kompaktere Schreibweise für den zuvor beschriebenen Testschritt lautet damit “Benutzernamen in Benutzeranmeldung|Benutzername eingeben”.

    LoginPage

    Abb. 1: Login/Logout AIT Downloads

  6. Verwendung von Parametern: Der TFS erlaubt in der Beschreibung der Testschritte die Verwendung von Parametern. Diese ermöglichen es, denselben Testfall mit unterschiedlichen Daten durchzuführen. Die Beschreibung eines Positivtests und eines Negativtests für die Benutzervalidierung beim Login kann beispielsweise mithilfe von Parametern innerhalb eines Testfalls erreicht werden (vgl. Abb. 2). Damit werden Redundanzen vermieden und eine effizientere Testfallerstellung ermöglicht.

    Abb. 2: Verwendung von Parametern

  7. Verwendung von Shared Steps: Shared Steps können im TFS genutzt werden, um Schrittfolgen zentral zu definieren und in unterschiedlichen Testfällen einzubinden. Dieses Vorgehen hat mehrere Vorteile: Zunächst wird durch das Verwenden von Shared Steps die Wartbarkeit der Testfälle wesentlich verbessert. Ändert sich an der in einem Shared Step definierten Schrittfolge etwas, so muss diese Änderung nur einmal vorgenommen werden statt in jedem betroffenen Testfall. Darüber hinaus wird eine erhöhte Einheitlichkeit erzielt, da dieselbe Schrittfolge immer exakt gleich beschrieben ist. Im bereits herangezogenen Beispiel einer Web Applikation mit Login muss in jedem Testfall zunächst der Login durchgeführt werden. Die Schritte dieses Logins können als Shared Steps definiert und diese Shared Steps in allen Testfällen eingebunden werden.

Fazit

Testfälle bilden die Schnittstelle zwischen den Anforderungen und Tests und damit den Grundstein für eine hohe Qualität im gesamten Testprozess. Zwar ist es schwer, zu definieren wie ein qualitativ hochwertiger Testfall im Allgemeinen auszusehen hat, jedoch sollte er effizient, einheitlich und eindeutig definiert werden. Beachtet man also die vorgestellten Tipps kommt man dem Ziel, einer durchgängig hohen Qualität, einen großen Schritt näher. Und wie so oft gilt auch bei der Definition von Testfällen: “Qualität ist das Produkt der Liebe zum Detail.” (Andreas Tenzer).

Christian Giesswein: .NET Day Franken 2016

Letztes Wochenende war es wieder so weit: der .NET Day Franken fand in Nürnberg zum 7. Mal statt.

Auch dieses Jahr durfte ich als Sprecher wieder mich auf den Weg nach Nürnberg machen um über das Thema "C# - Schweinerei und Features die niemand kennt..." zu referieren. Dabei stellte ich einige Sprachfeatures von C# vor, die meiner Meinung jeder Entwickler kennen sollte, und auch ein paar Szenarien was man denn so "falsch" machen kann.

Die Konferenz selber, hat mir persönlich wieder sehr gut gefallen, denn egal ob es sich um die Location, Verpflegung oder Vorträge geht: am .NET Day Franken passt einfach alles.

Die Slides gibt es hier zum Download.

Den Samplecode hier.

Manfred Steyer: Dynamische Formulare mit Angular 2 und DynamicComponentLoader

Dieser Artikel bezieht sich auf den RC 1 von Angular 2, welcher beim Verfassen dieses Textes die aktuelle Version war. Für den RC 2 sind ein paar Namensänderungen geplant. Eine Anpassung wird vermutlich mit Suchen/Ersetzen möglich sein. Siehe dazu die Zusammenfassung am Ende dieses Design-Dokuments.

Um den Umgang mit vielen ähnlichen Formularen zu vereinfachen, bietet sich der Einsatz von Formulargeneratoren an. Dieser Ansatz gibt auch einer serverseitigen Use-Case-Steuerung die Möglichkeit, den Aufbau der Formulare dynamisch zu beeinflussen.

Das imperative Forms-Handling in Angular 2 macht die Implementierung eines solchen Formulargenerators sehr einfach. Infos dazu finden sich in der Dokumentation von Angular. Um diesen Ansatz flexibler zu gestalten, bietet sich das Hinzuziehen des DynamicComponentLoaders an. Dieser erlaubt ein dynamisches Einbinden von Komponenten. Damit kann eine Anwendung zum Beispiel Steuerelemente, die eine Formularbeschreibung lediglich erwähnt, in die Seite laden.

Dieser Artikel beschreibt eine solche Implementierung. Dabei geht er davon aus, dass die zu ladenden Steuerelemente das Interface ControlValueAccessor implementieren und so mit dem Forms-Handling von Angular 2 zusammenspielen. Das gesamte Beispiel findet sich hier.

Metadaten für dynamisches Formular

Um mit dem hier beschriebenen Ansatz ein Formular zu generieren, bietet eine Komponente zunächst Metadaten zum Beschreiben des Formulars an. Zur Vereinfachung bestehen diese Metadaten aus zwei Teilen, nämlich einer vom imperativen Forms-Handling verwendeten ControlerGroup und einem Array elements, welches zusätzliche Daten zu den darzustellenden Steuerelementen beinhaltet. Diese beiden Informationen verpackt es in einem Objekt mit dem Namen formMetaData.

@Component({
    selector: 'flight-search',  
    template: require('./flight-search.component.html'),
    directives: [DynamicFormComponent]
})
export class FlightSearchImpComponent {

    public filter: ControlGroup;
    public formMetaData;

    constructor(
        private flugService: FlugService,
        private fb: FormBuilder) {


            this.filter = fb.group({
               from: [
                    'Graz',
                    Validators.compose([
                        Validators.required, 
                        Validators.minLength(3),
                        Validators.maxLength(50),
                        OrtValidator.validateWithParams(['Graz', 'Wien', 'Hamburg']),
                        Validators.pattern("[a-zA-Z0-9]+")
                    ]),
                    Validators.composeAsync([
                        OrtAsyncValidator.validateAsync
                    ])
               ],
               to: ['Hamburg'],
               date: ['2016-05-01']
            });

            var elements = [
                { fieldName: 'from', label: 'From' },
                { fieldName: 'to', label: 'To' },
                { fieldName: 'date', label: 'Datum', controlName: 'date-control' }
            ];

            this.formMetaData = {
                controlGroup: this.filter,
                elements: elements  
            };
    }

    [...]
}

Um ein Steuerelement für ein Feld vorzugeben, hinterlegt die Komponente dessen Namen in der Eigenschaft controlName. Auf diese Weise gibt das hier betrachtete Beispiel die Komponente date-control vor.

Diese Metadaten reicht die Komponente an die Komponente dynamic-form weiter. Die Implementierung dieser Komponente findet sich im nächsten Abschnitt.

<dynamic-form [formMetaData]="formMetaData">
</dynamic-form>  

Dynamic-Form-Component

Die Komponente dynamic-form nimmt lediglich die Metadaten entgegen und nutzt sie innerhalb des Templates zum Rendern des Formulars:

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

@Component({
    selector: 'dynamic-form',
    template: require('./dynamic-form.component.html')    
})
export class DynamicFormComponent {

    @Input() formMetaData;

}

Das Formular bindet sich an die ControlGroup in den Metadaten und iteriert anschliesend das Array elements. Pro Eintrag rendert es ein Steuerelement und verknüpft dieses über das Attribut ngControl mit dem Control in der ControlGroup. Standardmäßig kommt ein normales input-Element zum Einsatz. Falls der controlName jedoch auf date-control verweist, rendert das Template ein date-control. Dabei handelt es sich um ein einfaches, benutzerdefiniertes Steuerelement, welches hier beschrieben ist.

<form [ngFormModel]="formMetaData.controlGroup">


    <h2>Form Generator with dynamic Components</h2>

    <div *ngFor="let entry of formMetaData.elements" class="form-group">

        <div *ngIf="!entry.controlName && !entry.control">
            <label>{{entry.label}}</label>
            <input [ngControl]="entry.fieldName" class="form-control">
        </div>

        <!-- Issue: Template has to know all Controls here -->
        <div *ngIf="entry.controlName == 'date-control'">
            <label>{{entry.label}}</label>
            <date-control [ngControl]="entry.fieldName"></date-control>
        </div>

    </div>

    <ng-content></ng-content>

</form>

Dieser Ansatz funktioniert ganz gut, hat jedoch den Nachteil, dass die DynamicFormComponent sämtliche Steuerelemente kennen und über einen eigenen Zweig auch einbinden muss. Um diese starke Kopplung aufzuheben, nutzen die nachfolgenden Erweiterungen die Möglichkeit, Steuerelemente dynamisch in die Seite einzubinden.

Steuerelemente dynamisch laden

Um ein dynamisches Laden von Komponenten zu ermöglichen, erhält der betroffene Eintrag im Array elements einen Verweis auf die Komponente. Hierbei handelt es sich um die Klasse, die die Komponente realisiert. Diese könnte das Beispiel auch dynamisch zur Laufzeit, z. B. mittels System.import, vom Server laden.

var elements = [
    { fieldName: 'from', label: 'From' },
    { fieldName: 'to', label: 'To' },
    { fieldName: 'date', label: 'Datum', control: DateControlComponent }
    //                                              ^
    //                                              |
    //                  Component to use -----------+
];

Das dynamische Laden übernimmt in diesem Seznario die nachfolgend präsentierte Komponente ControlWrapperComponent. Wie ihr Name schon vermuten lässt, handelt es sich dabei um einen Wrapper für die dynamisch zu ladende Komponente. Sie implementiert den Lifecycle-Hook OnInit sowie das Interface ControlValueAccessor. Letzteres ist notwendig, damit es mit dem Forms-Handling von Angular zusammenspielt. Die nötigen Metadaten nimmt sie über die Eigenschaft metadata entgegen.

Darüber hinaus weist sie Eigenschaften für die dynamisch geladene Komponente (innerComponent), dem ChangeDetector dieser Komponente (innerComponentChangeDetectorRef) und dem aktuell repräsentierten Wert (value) auf. Wie im Beitrag zu benutzerdefinierten Formular-Komponenten beschrieben, richtet der Konstruktor die Komponente selbst als ihren eigenen ValueAccessor ein.

Die Methode writeValue, welche Angular zum Setzen des Wertes aufruft, hinterlegt den neuen Wert in value. Falls die dynamisch zu ladende Komponente bereits existiert, reicht sie diesen Wert auch an diese weiter und löst anschließend ihren ChangeDetector aus, damit sie ihre View aktualisiert.

Die Methoden registerOnChange und registerOnTouched nehmen von Angular Callbacks entgegen und verstauen diese in den Membern onChange und onTouched. Mit diesen Callbacks informiert die Komponente später Angular, wenn der Benutzer den dargestellten Wert ändert.

Der Lifecycle-Hook ngOnInit lädt mit dem in den Konstruktor injizierten DynamicComponentLoader die gewünschte Komponente das Template des Wrappers. Dazu nimmt dessen Methode loadAsRoot den Verweis auf die Komponenten-Klasse, einen CSS-Selektor und einen Injector entgegen. Der CSS-Selektor bestimmt die Stelle, an der die Komponente im Template zu platzieren ist. Im betrachteten Fall handelt es sich dabei um das span-Element mit der Id control. Der Injector bestimmt, welche Services sich die Komponente per Dependency Injection holen kann. Im betrachteten Fall kommt hierzu der Injector der Wrapper-Komponente zum Einsatz.

Nach dem Laden der Komponente holt sich ngOnInit eine Referenz auf die erzeugte Komponenten-Instanz sowie auf deren ChangeDetector. Danach reicht sie den aktuellen Wert (value) über die Methode writeValue an diese Instanz weiter und stößt anschließend ihren ChangeDetector an.

Danach registriert sich die Wrapper-Komponente bei der dynamisch geladenen Komponente, um über Änderungen am aktuellen Wert am Laufenden zu bleiben. Dazu übergibt sie jeweils einen Lambda-Ausdruck an deren Methode registerOnChanged und registerOnTouched. Diese Lambda-Ausdrücke delegieren an Angular, indem sie die von Angular übergebenen Callbacks onChange und onTouched aufrufen. Den beim Change-Event erhaltenen neuen Wert hinterlegt der Wrapper in der Eigenschaft value.

import { Component, Input, OnInit, DynamicComponentLoader, Injector, ChangeDetectorRef } from '@angular/core';
import {ControlValueAccessor, NgControl } from '@angular/common';


@Component({
    selector: 'control-wrapper',
    template: '<span id="control"></span>'
})
export class ControlWrapperComponent 
                    implements OnInit, ControlValueAccessor {

    @Input() metadata;

    innerComponent: any;
    innerComponentChangeDetectorRef: ChangeDetectorRef;
    value: any;

    constructor(
        private c: NgControl, 
        private dcl: DynamicComponentLoader, 
        private injector: Injector) {

        c.valueAccessor = this;
    }

    writeValue(value: any) {
        this.value = value;
        if (this.innerComponent) {
            this.innerComponent.writeValue(value);
            this.innerComponentChangeDetectorRef.detectChanges();
        }
    }

    onChange = (_) => {};
    onTouched = () => {};
    registerOnChange(fn): void { this.onChange = fn; }
    registerOnTouched(fn): void { this.onTouched = fn; }

    ngOnInit() {

        this.dcl.loadAsRoot(this.metadata.control, '#control', this.injector)

            .then(compRef => {
                this.innerComponent                  = compRef.instance;
                this.innerComponentChangeDetectorRef = compRef.changeDetectorRef;

                this.innerComponent.writeValue(this.value);
                compRef.changeDetectorRef.detectChanges();

                this.innerComponent.registerOnChange((value) => {
                    this.value = value;
                    this.onChange(value); 
                });
                this.innerComponent.registerOnTouched(() => {
                    this.onTouched();
                })

            });
    }

}

Dynamic-Form-Component um dynamische Steuerelemente erweitern

Damit die DynamicFormComponent nun die Wrapper-Komponente nutzen kann, registriert die Anwendung diese im Rahmen ihrer Direktiven:

import { Component, Input } from '@angular/core';
import { ControlWrapperComponent} from '../control-wrapper/control-wrapper.component';

@Component({
    selector: 'dynamic-form',
    template: require('./dynamic-form.component.html'),
    directives: [ControlWrapperComponent]    
})
export class DynamicFormComponent {

    @Input() formMetaData;

}

Zusätzlich nutzt das Template für jedes Feld, das über die Eigenschaft control auf ein Steuerelement verweist, die Wrapper-Komponente. Diese erhält die Metadaten, aus denen das zu nutzende Steuerelement hervor geht.

<form [ngFormModel]="formMetaData.controlGroup">


    <h2>Form Generator with dynamic Components</h2>

    <div *ngFor="let entry of formMetaData.elements" class="form-group">

        <div *ngIf="!entry.controlName && !entry.control">
            <label>{{entry.label}}</label>
            <input [ngControl]="entry.fieldName" class="form-control">
        </div>

        <div *ngIf="entry.control">
            <label>{{entry.label}}</label>
            <control-wrapper [metadata]="entry" [ngControl]="entry.fieldName"></control-wrapper>
        </div>

    </div>

    <ng-content></ng-content>

</form>

Manfred Steyer: Dynamic forms with Angular 2 and DynamicComponentLoader

This post refers to the RC 1 of Angular 2 which was the current version when it was written. For the RC 2 some renamings are planned. An adoption to it seems to be possible via find/replace. See the summary at the end of this design-document for a list of this renamings.

To simplify dealing with many similar forms, you can make use of form generators. This approach gives also a server-side use-case-control the possibility to influence the presented forms.

The imperative forms handling in Angular 2 makes it very easy to implement such a form generator. Information about this can be found in the documentation of angular. To make this approach more flexible, you can put the "DynamicComponentLoaders" into play. This allows a dynamic integration of components. Thus, an application can display controls, which are only mentioned in a form-description.

This article describes such an implementation. It assumes that every dynamically loaded control implements the interface ControlValueAccessor, which allows it to play together with Angular's mechanismns for forms-handling. The entire example can be found here.

Metadata for dynamic form

To generate a form using the approach described here, a component offers metadata for a form. For the sake of simplification, this metadata consists of two parts, namely a ControlGroup used by the imperative forms handling and an array of elements which contains additional data for the form-controls. It then stows these two pieces of information in an object with the name formMetaData:

@Component({
    selector: 'flight-search',  
    template: require('./flight-search.component.html'),
    directives: [DynamicFormComponent]
})
export class FlightSearchImpComponent {

    public filter: ControlGroup;
    public formMetaData;

    constructor(
        private flugService: FlugService,
        private fb: FormBuilder) {


            this.filter = fb.group({
               from: [
                    'Graz',
                    Validators.compose([
                        Validators.required, 
                        Validators.minLength(3),
                        Validators.maxLength(50),
                        OrtValidator.validateWithParams(['Graz', 'Wien', 'Hamburg']),
                        Validators.pattern("[a-zA-Z0-9]+")
                    ]),
                    Validators.composeAsync([
                        OrtAsyncValidator.validateAsync
                    ])
               ],
               to: ['Hamburg'],
               date: ['2016-05-01']
            });

            var elements = [
                { fieldName: 'from', label: 'From' },
                { fieldName: 'to', label: 'To' },
                { fieldName: 'date', label: 'Datum', controlName: 'date-control' }
            ];

            this.formMetaData = {
                controlGroup: this.filter,
                elements: elements  
            };
    }

    [...]
}

To define a control for a field, the component uses the property controlName. On this way, the considered example configures the usage of the component date-control for the property date.

This metadata is passed to the dynamic-form component. The implementation of this component can be found in the next section.

<dynamic-form [formMetaData]="formMetaData">
</dynamic-form>  

DynamicForm-Component

The component dynamic-form takes the passed metadata and uses it within it's template to render the form in question:

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

@Component({
    selector: 'dynamic-form',
    template: require('./dynamic-form.component.html')    
})
export class DynamicFormComponent {

    @Input() formMetaData;

}

The form is bound to the ControlGroup using ngFormModel and the array elements is iterated. For each array-entry the sample renders a control which is bound to a Control within the mentioned ControlGroup. For this, the Attribute ngControl gets the name of the Control in question.

By default, it uses an ordinary input-element, but when there is a property controlName with the value date-control, it renders a date-control. This is a simple control that can be used to edit date-values. The implementation of it is described here.

<form [ngFormModel]="formMetaData.controlGroup">


    <h2>Form Generator with dynamic Components</h2>

    <div *ngFor="let entry of formMetaData.elements" class="form-group">

        <div *ngIf="!entry.controlName && !entry.control">
            <label>{{entry.label}}</label>
            <input [ngControl]="entry.fieldName" class="form-control">
        </div>

        <!-- Issue: Template has to know all Controls here -->
        <div *ngIf="entry.controlName == 'date-control'">
            <label>{{entry.label}}</label>
            <date-control [ngControl]="entry.fieldName"></date-control>
        </div>

    </div>

    <ng-content></ng-content>

</form>

This approach works quite well, but has the disadvantage that the DynamicFormComponent must know all controls and respect them with an own branch. To lower this strong coupling, the following extensions use the possibility to load controls dynamically into the page.

Dynamically load controls

To enable loading components dynamically, the affected entry in the array elements gets a direct reference to the component-controller, which is just a class. An application could also dynamically fetch this control-controller from the server at run time, e. g. by using System.import.

var elements = [
    { fieldName: 'from', label: 'From' },
    { fieldName: 'to', label: 'To' },
    { fieldName: 'date', label: 'Datum', control: DateControlComponent }
    //                                              ^
    //                                              |
    //                  Component to use -----------+
];

The below presented component ControlWrapperComponent takes care of dynamic loading in this scenario. As its name suggests, it is a wrapper for the component which is to be loaded dynamically. It implements the lifecycle-hook OnInit and the ControlValueAccessor interface. The latter is necessary, to make it with work with Angular's forms handling. It takes the necessary metadata from the input-binding metadata.

In addition, it has properties for the dynamically loaded components (innerComponent), the ChangeDetector of this component (innerComponentChangeDetectorRef) and the current value (value). As described in this example, the constructor sets up the component as its own ValueAccessor.

The method writeValue is called by Angular to set the current value. If the dynamically loaded component already exists, it passes this value to it and then it triggers the ChangeDetector to update its view.

The methods registerOnChange and registerOnTouched take callbacks from Angular and stow them within the member-variables onChange and onTouched. With these callbacks the component informs Angular when the user changes the displayed value.

The lifecycle hook ngOnInit uses the injected DynamicComponentLoader to load the desired component. It's method loadAsRoot takes the reference to the component class, a CSS selector and an injector. The CSS selector determines where to place the component within the template. The injector determines what services the component can get via dependency injection. In the considered case the injector of the wrapper-component is used for this purpose.

After loading the component, the generated component-instance as well as it's ChangeDetector is put into variables. Then ngOnInit passes the current value (value) to the newly created component via writeValue. After that, it triggers it's ChangeDetector.

Then, the wrapper component registeres callbacks to keep track of changes. To do this, it passes lambda expressions to registerOnChanged and registerOnTouched. These lambda expressions delegate to Angular by calling onChange and onTouched.

import { Component, Input, OnInit, DynamicComponentLoader, Injector, ChangeDetectorRef } from '@angular/core';
import {ControlValueAccessor, NgControl } from '@angular/common';


@Component({
    selector: 'control-wrapper',
    template: '<span id="control"></span>'
})
export class ControlWrapperComponent 
                    implements OnInit, ControlValueAccessor {

    @Input() metadata;

    innerComponent: any;
    innerComponentChangeDetectorRef: ChangeDetectorRef;
    value: any;

    constructor(
        private c: NgControl, 
        private dcl: DynamicComponentLoader, 
        private injector: Injector) {

        c.valueAccessor = this;
    }

    writeValue(value: any) {
        this.value = value;
        if (this.innerComponent) {
            this.innerComponent.writeValue(value);
            this.innerComponentChangeDetectorRef.detectChanges();
        }
    }

    onChange = (_) => {};
    onTouched = () => {};
    registerOnChange(fn): void { this.onChange = fn; }
    registerOnTouched(fn): void { this.onTouched = fn; }

    ngOnInit() {

        this.dcl.loadAsRoot(this.metadata.control, '#control', this.injector)

            .then(compRef => {
                this.innerComponent                  = compRef.instance;
                this.innerComponentChangeDetectorRef = compRef.changeDetectorRef;

                this.innerComponent.writeValue(this.value);
                compRef.changeDetectorRef.detectChanges();

                this.innerComponent.registerOnChange((value) => {
                    this.value = value;
                    this.onChange(value); 
                });
                this.innerComponent.registerOnTouched(() => {
                    this.onTouched();
                })

            });
    }

}

Dynamic-Form-Component um dynamische Steuerelemente erweitern

The DynamicFormComponent can now use the wrapper-component:

import { Component, Input } from '@angular/core';
import { ControlWrapperComponent} from '../control-wrapper/control-wrapper.component';

@Component({
    selector: 'dynamic-form',
    template: require('./dynamic-form.component.html'),
    directives: [ControlWrapperComponent]    
})
export class DynamicFormComponent {

    @Input() formMetaData;

}

In addition, the template uses the wrapper-component for each field that refers to a component by the means of the property control. This contains the metadata including the control to dynamically load.

<form [ngFormModel]="formMetaData.controlGroup">


    <h2>Form Generator with dynamic Components</h2>

    <div *ngFor="let entry of formMetaData.elements" class="form-group">

        <div *ngIf="!entry.controlName && !entry.control">
            <label>{{entry.label}}</label>
            <input [ngControl]="entry.fieldName" class="form-control">
        </div>

        <div *ngIf="entry.control">
            <label>{{entry.label}}</label>
            <control-wrapper [metadata]="entry" [ngControl]="entry.fieldName"></control-wrapper>
        </div>

    </div>

    <ng-content></ng-content>

</form>

Sven Hubert: AIT unterstützt Team beim Startup Weekend

Das Startup Weekend ist ein weltweites Event bei denen sich Entwickler, Designer, Studenten, Naturwissenschaftler und Ingenieure, Business-Spezialisten und vor allem Gründer in verschiedenen Städten treffen. Innerhalb von 54 Stunden soll ein vollständiges Gründungskonzept entwickelt und auf seine Machbarkeit und Marktgängigkeit geprüft werden. Aufgabe dabei ist ebenfalls eine Demo zu entwickeln, um beim finalen Pitch vor einer meist hochkarätigen Jury zu demonstrieren, dass die Idee umsetzbar ist.

Auch in Paderborn fand dieses Jahr wieder das Startup Weekend statt. Unter anderem trat auch das Team KwiqJobs zum Wettbewerb an, unterstützt vom AIT Senior Consultant und Xamarin Spezialist Martin Kleine. Die Idee hinter KwiqJobs ist einfach. Heutzutage verbringt der Mensch viel Zeit mit Warten, sei es auf den Bus oder in der Schlange vom Supermarkt. Die meisten Menschen nutzen diese Zeit mehr oder weniger sinnvoll um in sozialen Medien mit ihrem Smartphone zu surfen. Mit der KwiqApp sollen diese Leute während sie warten Geld verdienen können, indem sie einfach sogenannte Microjobs erledigen.

clip_image002[5]           clip_image004           clip_image006

Während des Wochenendes mussten drei Bereiche als einfache Demo umgesetzt werden:

1. Eine App fürs Smartphone: Hier wurde Xamarin verwendet.

2. Ein Backend für die Daten: Azure Mobile Apps war hier die Wahl

3. Eine Administrationsseite für die Auftraggeber: ASP.NET Web Application

Mit Hilfe von Xamarin.Forms war es einfach möglich eine App zu entwickeln, die auf den drei Plattformen Android, iOS und Windows Phone läuft. Die Azure Mobile Apps integrierten sich völlig unkompliziert in die Xamarin App und erlaubten eine sehr performante Verarbeitung von Daten in der Cloud per Service. Die Administrationsseite musste ebenfalls diese Daten verarbeiten bzw. auch bereitstellen. Auch hier war eine nahtlose Integration möglich, da die Webseite im gleichen Container gehostet wurde und von dort auf die Daten zugreifen konnte.

clip_image002

Dies war auch der Grund, wieso sich das Team für die Umsetzung mit der Microsoft Plattform entschieden hat. Microsoft bietet für alle drei Bereiche nicht nur einzelne Lösungen an, sondern ermöglicht auch eine unkomplizierte und sehr einfache Form der Integration der verschiedenen Anwendungsteile.

Nebenbei sei noch erwähnt: Sieger des Startups Weekend in Paderborn, bei dem 18 Ideen an den Start gingen, war mit großem Abstand das Team KwiqJobs. Neben der mehr als überzeugenden Idee und einem sehr coolen Auftritt beim finalen Pitch hat auch die technische Umsetzung die Jury schwer beeindruckt.

Code-Inside Blog: FAKE: Build ASP.NET projects with web.config transformation (and without knowing a tiny bit of F#)

This is a follow-up to my other FAKE posts:

What’s the difference between a ASP.NET and other projects?

The most obvious difference is that the output is a bunch of dlls and content files. Additionally you might have a web.debug.config or web.release.config in your source folder.

Both files are important, because they are used during a Visual-Studio build as a Web.Config Transformation.

With a normal build the transformation will not kick in, so we need a way to trigger the transformation “manually”.

Project Overview

The sample project consists of one ASP.NET project and the .fsx file.

x

The FAKE script

We reuse the MSBuild-Helper from FAKE and inject a couple of “Publish”-related stuff, which will trigger the transformation.

Publish a ASP.NET project

...
Target "BuildWebApp" (fun _ ->
trace "Building WebHosted Connect..."
!! "**/*.csproj"
 |> MSBuild artifactsBuildDir "Package"
    ["Configuration", "Release"
     "Platform", "AnyCPU"
     "_PackageTempDir", (@"..\" + artifactsDir + @"Release-Ready-WebApp")
     ]
 |> Log "AppBuild-Output: "
)
...

Result

x

This build will produce two artifacts - the build-folder just contains the normal build output, but without a web.config transformation.

The other folder contains a ready to deploy web application, with the web.release.config applied.

You can find the complete sample & build script on GitHub.

Fabian Deitelhoff: Gelesen + Verlosung: Vorgehensmuster für Softwarearchitektur (2. Auflage)

Im November 2014 durfte ich die erste Auflage des Buchs Vorgehensmuster für Softwarearchitektur (1. Auflage) von Stefan Toth rezensieren und verlosen. Vor einiger Zeit hat mir Stefan freundlicherweise die zweite Auflage zugeschickt, die ich gerne in diesem Beitrag rezensieren und gleichzeitig auch verlosen möchte.

Dieser Beitrag handelt somit von der zweiten Auflage des Buchs Vorgehensmuster für Softwarearchitektur.

Das Buch im Überblick

Vorgehensmuster für Softwarearchitektur

Hanser Fachbuch, 06/2015, 268 Seiten, Deutsch
ISBN: 978-3-446-44395-2, 34,99 Euro

Sprache: Deutsch
Ausstattung: Gebunden
E-Book: Auch als E-Book verfügbar
Probekapitel: Leseprobe ansehen
Gesamtnote: sehr gut – 5,0 von 5 Sternen
Leseempfehlung: Ja

Vorgehensmuster für Softwarearchitektur (Hanser, Stefan Toth)

Der Inhalt

Ich freue mich immer wieder, wenn es aktualisierte Auflagen zu Fachbüchern gibt. Auf der einen Seite bedeutet das ganz schlicht, dass das erste Buch erforderlich genug war, dass sich eine Aktualisierung lohnt. Was nicht selbstverständlich ist. Gerade bei diesem Buch zu Softwarearchitekturen, das schon in der ersten Auflage sehr gut war und eine zwei Auflage mehr als verdient hat.

Damit meine ich nicht, dass in der ersten viele Fehler oder Ungereimtheiten vorhanden waren. Ganz im Gegenteil. Es ist auch nicht verwunderlich, dass die Unterschiede zur ersten Auflage nicht immens umfangreich ausfallen. Was insofern nicht verwunderlich ist, weil schon die erste Auflage das Zeug zu einem neuen Standardwerk in dem Bereich hat.

Das Buch ist in sieben Kapitel aufgeteilt, mit einem klaren Fokus auf die Vorgehensmuster. Darin ist beschrieben, wie Softwarearchitekturen heutzutage entworfen und auch weiterentwickelt werden sollten. Denn Software ist kein statisches Konstrukt. Sie muss sich weiterentwickeln und an neue Anforderungen und Bedürfnisse anpassen. Dabei wird eine bestehende Architektur auf die Probe gestellt, da sie erweiterbar und änderbar sein muss.

Vier der Kapitel handeln deshalb auch direkt von den Vorgehensmustern. Jedes beschrieben mit einer kleinen Einführung und einer Problemstellung, warum dieses Muster auch in der Praxis Sinn ergibt.

Das Kapitel sieben ist meines Erachtens am umfangreichsten angepasst worden bzw. gänzlich neu. Hier sind Tipps und Tricks zur Anwendung der Muster beschrieben, wie zum Beispiel der Einsatz der Muster in Scrum.

Fazit & Bewertung

Mir gefällt auch die zweite Auflage wirklich sehr gut. Ich mag den klaren Schreibstil von Stefan Toth, die gute Struktur und Gliederung der einzelnen Kapitel und Unterkapitel, sowie die vielen eingestreuten Beispiele und Tipps zum Scheitern. Gerade letztere lockern das Ganze auf, da sie versuchen, Empfehlungen nicht mit dem erhobenen Zeigefinger zu vermitteln, sondern von der andere Seite, indem Tipps zum Scheitern gegeben werden.

Ganz allgemein gefällt mir die Ausrichtung des Buchs einfach gut. Eine gute Mischung aus Basistechniken, Informationen zum richtigen Entscheiden, zur Zusammenarbeit und Interaktion sowie Tipps und Tricks, wie sich die Muster gut in die Praxis integrieren lassen. Beide Daumen hoch.

Verlosung

Und wieder einige obligatorische Informationen zur Verlosung. Das Buch wurde mir freundlicherweise von Stefan Toth zur Verfügung gestellt. Gelesen habe ich es einmal. Dadurch ist das Buch in einem sehr guten Zustand. Auch die enthaltene E-Book Ausgabe ist noch verfügbar, da ich den Code nicht eingelöst habe.

Das Buch wird von mir verschickt. Alle Kosten übernehme selbstverständlich ich. Bis auf eine Adresse brauche ich dann auch nichts weiter. Dazu melde ich mich allerdings noch mal beim Gewinner beziehungsweise der Gewinnerin per E-Mail, die beim Kommentar mit angegeben werden muss. Die E-Mail Adresse ist natürlich nur von mir einsehbar.

Wer gewinnen möchte, hinterlässt bitte einen Kommentar, warum er oder sie das Buch gerne hätte. Das muss nichts Besonderes sein. Ich möchte nur gerne vermeiden, dass Kommentare auftauchen, die offensichtlich dadurch entstanden sind, das einmal von links nach rechts mit dem Gesicht über die Tastatur gerollt wurde. 🙂

Aus allen Kommentaren fische ich dann per Zufall einen heraus, so wie ich das bei den letzten Verlosungen auch gemacht habe. Die Verlosung läuft von heute, Sonntag den 12. Juni 2016 bis zum Freitag, den 17. Juni 2016 um 12:00 Uhr. Die Teilnahme ist ab 18 Jahren möglich und der Rechtsweg ist wie üblich ausgeschlossen.

Bei Fragen zum Buch oder sonstigen Angelegenheiten zur Verlosung freue ich mich immer über Kommentare und Nachrichten.

Vielen Glück allen!

Die Ziehung

Mittlerweile ist die Verlosung beendet. Wie immer habe ich, durch das folgende SQL-Statement, einen Kommentar herausgepickt.

SELECT 
      distinct comment_author, comment_author_email, comment_content
FROM
      wp_comments
INNER JOIN
      wp_posts
ON
      comment_post_ID = id
WHERE
      post_title = 'Gelesen + Verlosung: Vorgehensmuster für Softwarearchitektur (2. Auflage)'
AND
      comment_approved = 1
AND 
      user_id = 0
AND
      comment_date
BETWEEN 
      '2016-06-12 01:00:00'
AND 
      '2016-06-17 12:00:00'
ORDER BY 
      RAND()
LIMIT
      1

Herausgekommen ist folgender Kommentar. Die E-Mail Adresse habe ich unkenntlich gemacht.

Ziehung: Vorgehensmuster für Softwarearchitektur (Hanser, Stefan Toth)

 

Herzlichen Glückwunsch an den Gewinner Matthias. Ich habe gerade eine E-Mail rausgeschickt, da ich noch die Lieferadresse brauche.

Und natürlich gibt es auch in Zukunft weitere Verlosungen.

codefest.at [MS]: #Ch9weekly - XPC Cross-Plattform Conference

 

Jede Woche stellen wir ein interessantes Channel 9 Video für Euch hier zur Verfügung, damit Ihr stets einen Wissensvorsprung haben könnt.

Diese Woche gibt es die Aufnahmen von der XPC, also der Cross-Plattform Conference aus Deutschland, wo es zahlreiche Kurzvideos rund um Unity3D, Windows Bridge, HTML5, WebGL uvm.

Das komplette Programm:

  • Eröffnung, Keynote: Cross-Plattform ist ein alter Hut - Zeit, ihn abzustauben
  • Leichtgewichtige Architekturen im Zeitalter von "Mobile First"
  • Cross-Plattform Apps mit Xamarin.Forms entwickeln
  • Browser, Mobile und Desktop: Echte Cross-Plattform-Anwendungen mit HTML5 & Co.
  • Project Islandwood aka Windows Bridge für iOS
  • Cross-Plattform-Spieleentwicklung mit HTML5, WebGL und Unity3D
  • App-Notifications: nativ und cross-platform
  • Wie testet man Cross-Plattform-Apps?
  • Creating holistic experiences people really love

Hier gibt es die restlichen VIDEOS.

codefest.at [MS]: Letzter Aufruf für Flug MS0616 nach Trainingsmöglichkeiten

Wir bieten in den nächsten Tagen und Wochen einige Möglichkeiten um sich zu aktuellen Themen Rund um die Softwareentwicklung zu informieren. Anbei noch einmal eine kurze Zusammenfassung zu den Veranstaltungen:

codefest.at [MS]: Event (16. Juni): //build Zusammenfassung - Track für Open Source Enthusiasten

Ich habe bei unserer lokalen //build Zusammenfassung am 16. Juni die Aufgabe des “Track-Owners” für den Open Source Track übernommen.

Wir sehen uns bereits am Beginn des Tages in der Keynote gemeinsam mit Georg Binder und dem Leiter der DX Gruppe Nico Sorger. Nachdem die Agenda für jeden Track in einem “agile” Modus entstanden ist (und daher häufigen Anpassungen unterworfen ist) möchte ich hier (knapp vor Ende des Sprints) einen aktuellen Status zu den Vorträgen und Inhalten geben.

Track für Open Source Enthusiasten
Moderation: Gerwald Oberleitner

Vortrag 1:
.NET & Open Source, Andreas Willich (TechTalk)
Der Vortrag gibt einen aktuellen Staus zu .NET Core, ASP.Net Core und vielen weiteren Open Source Aktivitäten der .NET Foundation Inc.

Vortrag 2:
Node.js, NPM, Gulp & Co – Web Development Tools für Visual Studio Entwickler, Rainer Stropek (Time Cockpit)
Für Webentwicklung auf der Microsoft-Platform gibt es im Moment sehr viel Neues zu lernen. Nicht nur, dass ASP.NET Core einige grundlegende Änderungen bringen, die gesamte Toolsammlung für Webentwicklung ist nicht mehr wiederzuerkennen. Microsoft wendet sich verstärkt bestehenden, plattformunabhängigen Tools aus der Open Source Welt zu und integriert diese in die kommende Visual Studio Version. Das Ergebnis ist eine Vielzahl an neuen Werkzeugen, die auf den ersten Blick verwirrend wirkt. In dieser Session bringt Rainer Stropek Ordnung ins Chaos indem er drei der Tools vorstellt, die für Visual Studio Webentwicklung neu sind: Node.js, Gulp und NPM.

Vortrag 3:
Data in an open world – Daten skalierbar in Microsoft Azure speichern, analysieren, darstellen, Florian Mader (Microsoft)
Der Vortrag enthält einen Streifzug durch die Welt der Daten in Microsoft Azure und betrachtet die aktuellen Angebote auf der Basis von Open Source Projekten. Dazu gehören Hadoop, der MongoDB Treiber für die DocumentDB, ….

Vortrag 4:
Open DevOps – x-Platform Build & Release Management, Oliver Lintner & Gerwald Oberleitner (Microsoft)
"Microsoft loves Open Source": Unter dem neuen CEO S. Nadella wurde mit "Mobile First, Cloud First" eine neue Ära begonnen. Dies spiegelt sich auch in den DevOps & Application Lifecycle Management (ALM) Werkzeugen wieder. Grund genug sich die Werkzeuge und deren OSS Integration in dieser Session genauer anzusehen...
Wir werden uns anhand des Beispiels einer Android Applikation (Xamarin) und den Visual Studio Team Services den Continuous integration (CI) und Continuous delivery (CD) Workflow ansehen und auch wie wir Feedback von und zu unserer Applikation erhalten können.

Die Vortragenden und ich freuen uns auf Ihr kommen !

Sven Hubert: Qualität als Konzept: Umgang mit Abhängigkeiten von Test Cases im TFS

Ist man als Berater im Umfeld von Microsoft ALM im Bereich Testmanagement unterwegs, so kommt des Öfteren die Fragestellung auf, wie mit Abhängigkeiten von Test Cases im TFS umgegangen werden kann. Die kurze Antwort darauf lautet: „Es kommt darauf an.“

Um die Frage also wirklich beantworten zu können, muss man zunächst die Art der bestehenden Abhängigkeit zwischen den Test Cases bestimmen. Dabei gibt es grundsätzlich zwei Stufen: In der einfachen Form besteht die Abhängigkeit erst einmal nur darin, dass die Test Cases in einer bestimmten Reihenfolge ausgeführt werden müssen. D.h. es existiert eine Vorgänger-Nachfolger-Beziehung zwischen Test Cases, wobei ein Test Case erst dann ausgeführt werden kann, wenn alle seine Vorgänger Test Cases erfolgreich durchgeführt wurden. In der erweiterten Form der Abhängigkeit spielt nicht nur die Reihenfolge der Ausführung der Test Cases eine Rolle. Vielmehr bilden Daten, welche innerhalb der Ausführung eines Test Cases generiert werden den Input für weitere Test Cases (vgl. Abb. 1).

image

Abb. 1: Beispiel einfache vs. erweiterte Abhängigkeit von Test Cases

In der Theorie sollten keine der beiden Abhängigkeitsformen im Test Design eine Rolle spielen sondern durch geeignetes Schneiden der Test Cases oder aber entsprechendes Testdatenmanagement vermieden werden. In der Praxis gibt es jedoch immer wieder Fälle, in denen dies insbesondere in den höheren Testarten, wie z.B. Integrations- oder User Acceptance Tests, und aus verschiedensten Gründen, wie z.B. hoher Komplexität sowie damit verbundenen hohen Kosten zur Erzeugung von adäquaten Testdaten, nicht umgesetzt werden kann.

In diesen Fällen ist es also wichtig die bestehenden Abhängigkeiten im TFS abzubilden, um eine reibungslose Testausführung zu ermöglichen. Out-of-the-Box sind die Möglichkeiten, die der TFS bzw. der Microsoft Test Manager (MTM) hierfür bietet jedoch sehr begrenzt. Daher haben wir in unseren verschiedenen Projekten Ansätze gesammelt, wie damit umgegangen werden kann, welche wir Ihnen im Folgenden vorstellen möchten:

 

Einfache Abhängigkeit von Test Cases

Im Falle der einfachen Abhängigkeit gibt es out-of-the-Box im MTM die Möglichkeit Test Cases in einer statischen Test Suite in eine Reihenfolge zu bringen. Dazu wird die Order-Funktion verwendet. Diese erlaubt es die einzelnen Test Cases händisch zu nummerieren (vgl. Abb. 2) . Die Test Cases werden dann in der dadurch definierte Reihenfolge ausgeführt. Wichtig hierbei ist es zu wissen, dass diese Funktion nicht im TFS Web Access zur Verfügung steht und auch die im MTM definierte Reihenfolge nicht in den TFS Web Access synchronisiert wird und somit auch nicht im TFS Web Test Runner zur Verfügung steht. Nutzt man also diese Art zum Festlegen der Ausführungsreihenfolge von Testfällen, ist man bei der manuellen Testausführung auf den MTM angewiesen und kann nicht den leichtgewichtigeren Web Test Runner verwenden.

Des weiteren ist diese im MTM implementierte Sortierfunktion nicht per Drag & Drop bedienbar sondern kann nur durch die Angabe von Nummern definiert werden. Aufgrund dessen ist diese Funktion für eine große Anzahl an Test Cases innerhalb einer statischen Suite kaum mehr praktikabel. Umfasst eine statische Suite jedoch nur eine geringe Anzahl an Test Cases und sind die notwendigen Lizenzen vorhanden um den MTM nutzen zu können, ist dies wohl die einfachste Möglichkeit eine Reihenfolge für die Ausführung von Test Cases zu definieren.

image

Abb. 2: Order-Funktion für statische Test Suites im MTM

 

Ein zweiter Ansatz eine Reihenfolge für Test Cases zu definieren, welche nicht ausschließlich an den MTM gebunden ist, ist es ein benutzerdefiniertes Feld zum Work Item Typen Test Case hinzuzufügen. In diesem kann analog zur Order-Funktion im MTM die jeweilige Nummer eines Test Cases in der Ausführungsreihenfolge definiert werden. Das Feld kann dann als Spalte angezeigt werden, nach welcher sortiert werden kann. Da sowohl im MTM als auch im TFS Web Access beim Ausführen aller Test Cases innerhalb einer Test Suite die Anzeigereihenfolge als Ausführungsreihenfolge verwendet wird, hat man so ebenfalls eine relativ einfache Möglichkeit gefunden mit Abhängigkeiten umzugehen.

Ein erheblicher Nachteil bei diesem Ansatz besteht darin, dass er nur zuverlässig anwendbar ist wenn sich die jeweiligen Test Cases nur in einer einzigen Test Suite befinden, da ansonsten die über das benutzerdefinierte Feld definierte Nummer nicht eindeutig ist. D.h. befindet sich ein und derselbe Test Case in mehreren Test Suiten, ist nicht klar auf welche Test Suite sich die Nummerierung in dem Feld bezieht. Mittels vordefinierter Nummernkreise lässt dieses Symptom zwar lindern, aber es bleibt ein Workaround, welcher auf bestimmte Szenarien begrenzt ist.

 

Ein letzter Ansatz um einfache Abhängigkeiten von Test Cases zu definieren ist es in der jeweils übergeordneten Test Suite die Reihenfolge der Test Cases festzuhalten. Hierfür kann wiederum ein benutzerdefiniertes Feld oder ein bereits bestehendes verwendet werden. Bei der Test Ausführung muss der Tester dann die Test Suite parallel geöffnet haben und ist selbst dafür verantwortlich die Test Cases in der gegebenen Reihenfolge ausführen.

Dieses Vorgehen birgt auf der einen Seite eine sehr hohe Fehleranfälligkeit, da die Reihenfolge nicht auf den ersten Blick ersichtlich ist und nicht bei der Ausführung automatisch übernommen wird. Auf der anderen Seite jedoch kann es auch verwendet werden, wenn sich Test Cases in verschiedenen Test Suiten befinden. Außerdem kann man dem Tester weitere ggf. notwendige Hinweise für die Testausführung geben.

 

Erweiterte Abhängigkeit von Test Cases

Für den Fall einer erweiterten Abhängigkeit (Output-Input-Datenabhängigkeit) zwischen Test Cases bietet der TFS weder im TFS Web Access noch im MTM eine dafür dedizierte Möglichkeit zur Umsetzung. In vielen Fällen ist es ausreichend in der Beschreibung der Test Steps Bezug zu nehmen, z.B. „Öffnen des vorher generierten Datensatzes“. Dies setzt jedoch voraus, dass der gleiche Tester beide Stellen testet. Insbesondere im Bereich der User Acceptance Tests können beispielsweise Key User aus den verschiedenen Organisationseinheiten zum Einsatz kommen, die das System später auch verwenden. Wenn man nun beispielsweise einen Bestellprozess in einer ERP-Anwendung unter realen Bedingungen testen möchte, so sind daran verschiedene Tester beteiligt. In solchen Szenarien braucht man andere Ansätze, um die Datenabhängigkeit abzubilden.

Eine Möglichkeit dafür besteht darin, den zuletzt vorgestellten Ansatz zur Definition einer Ausführungsreihenfolge zu erweitern. D.h. in der jeweils übergeordneten Test Suite werden die bestehenden Datenabhängigkeiten zum einen vorab definiert und zum anderen während der Testausführung die konkreten Daten dokumentiert (z.B. in Form einer Tabelle; siehe Abb. 3). Die generierten und so dokumentierten Daten können dann in darauf aufbauenden Test Cases weiterverwendet werden.

Dieser Ansatz kann mit den vorgestellten Möglichkeiten zur Definition einer Ausführungsreihenfolge kombiniert werden, wobei die bereits vorgestellten Vor- und Nachteile zu beachten sind.

image

Abb. 3: Beispiel für Definition von Input-Output-Abhängigkeiten innerhalb einer Test Suite

Dies funktioniert auch bei der Wiederverwendung von Test Cases, da diese typischerweise in unterschiedlichen Test Suiten, ggf. in verschiedenen Testplänen referenziert werden. Die Test Suite bleibt dabei jedoch eindeutig und demnach sind die entstandenen Daten auch spezifisch für eine Test Suite gespeichert.

 

Weitere Überlegungen

Bei den vorgestellten Formen der Abhängigkeit zwischen Test Cases kann es wie vorher beschrieben vorkommen, dass die voneinander abhängigen Test Cases von unterschiedlichen Testern, z.B. aus unterschiedlichen Fachbereichen oder Abteilungen, durchgeführt werden müssen.

In diesem Fall muss signalisiert werden, wann ein Test Case zur Ausführung bereit ist. Hierfür kann man zunächst alle Test Cases bis auf den als erstes auszuführenden als Blocked markieren. Nach der erfolgreichen Ausführung eines Test Cases werden dann alle darauf aufbauenden Test Cases zurück auf Active gesetzt. Damit wird dem jeweils zuständigen Tester signalisiert, dass der Test Case bereit zur Ausführung ist. Dieses Vorgehen wird für alle Test Cases fortgeführt (vgl. Abb. 4).

image

Abb. 4: Test Cases als Blocked / Active markieren

 

Fazit

Out-of-the-Box bietet der TFS keine Möglichkeit an Abhängigkeiten von Test Cases abzubilden und bei der Testausführung zu berücksichtigen, welche durchgängig sowohl im TFS Web Access als auch im MTM nutzbar ist.

Die vorgestellten Ansätze um sowohl Abhängigkeiten in Form von Ausführungsreihenfolge als auch Output-Input-Abhängigkeiten abzubilden sind in diversen Projekten entstanden und basieren darauf, innerhalb der TFS Testtoolkette zu bleiben, d.h. kein separates Tool zu verwenden. Sie sind keine Pauschallösungen, welche alle Szenarien abdecken, sollen aber Denkanstoß sein, wie man mit diesen Themen umgehen kann.

Haben Sie bereits selbst Erfahrungen mit einer der vorgestellten Ansätze gesammelt oder haben Sie selbst weitere Ansätze zum Umgang mit Abhängigkeiten von Test Cases im TFS entwickelt? Gerne senden Sie uns ihr Feedback zu diesem Thema.

Manfred Steyer: Eigene Formular-Steuerelemente für Angular 2 schreiben

Sollen eigene Angular 2-Komponenten mit deklarativen (template-driven) und imperativen Formularen zusammenspielen, ist das Interface ControlValueAccessor zu implementieren. Die von diesem Interface definierten Methoden erlauben ein Abgleichen der Komponente mit dem Objektgraphen, über den Angular 2 ein Formular beschreibt.

Solche Steuerelemente arbeiten - wie input-Elemente - mit ngModel bzw. ngControl zusammen. Zur Veranschaulichung nutzt das nachfolgende Beispiel eine benutzerdefinierte Komponente date-control, die sich an die Eigenschaft mit ngModel an die Eigenschaft date bindet:

<!-- Deklaratives (template-driven) Forms-Handling -->
<date-control [(ngModel)]="date"></date-control>

Alternativ dazu kann sich solch eine Komponente jedoch auch über das imperative Forms-Handling an ein vordefiniertes Control-Objekt binden. Das nachfolgende Beispiel zeigt dies, indem es das date-control mit ngControl an das Control-Objekt mit dem Namen date bindet. Dieses Control-Objekt erwartet Angular in der über ngFormModel festgelegten ControlGroup.

<!-- Imperatives Forms-Handling -->
<form [ngFormModel]="filter">   
    <date-control ngControl="date"></date-control>
    [...]
</form>

Die ControlGroup sowie das Control sind dabei über die Komponente bereitzustellen:

@Component({
    selector: 'flight-search',  
    template: require('./flight-search.component.html'),
    directives: [DateControlComponent]
})
export class FlightSearchImpComponent {


    public filter: ControlGroup;

    constructor(private fb: FormBuilder) {


        this.filter = fb.group({
           date: ['2016-05-01']
        });
    }

    [...]
}

Dieser Beitrag beschreibt die nötigen Schritte zur Implementierung von ControlValueAccessor. Das gesamte Beispiel findet sich hier.

ControlValueAccessor

Das von Angular 2 bereitgestellte Interface ControlValueAccessor bietet drei Methoden zum Abgleich des Zustands eines Steuerelement mit dem von Angular für das Formular eingerichteten Objektgraphen.

//
// From the Angular2-Sources
//
export interface ControlValueAccessor {
    writeValue(obj: any): void;
    registerOnChange(fn: any): void;
    registerOnTouched(fn: any): void;
}

Um einen Wert ins Steuerelement zu schreiben, nutzt Angular die Methode writeValue. Da Angular jedoch auch über Änderungen am Laufenden bleiben muss, registriert das SPA-Flagschiff mit registerOnChange und registerOnTouched jeweils einen Callback. Ersteren ruft das Steuerelement per Definition auf, wenn der Benutzer den Wert ändert. Letzteres signalisiert, dass das Feld zumindest den Fokus hatte.

ControlValueAccessor implementieren

Das nachfolgende Beispiel demonstriert die Realisierung des Interfaces ControlValueAccessor. Es handelt sich dabei um eine einfache Komponente zum Bearbeiten von Datumswerten. Die Methode splitDate nimmt ein Datum entgegen und zerlegt es in seine Bestandteile, die es anschließend im (hier nicht abgebildeten) Template zum Editieren anbietet. Den umgekehrten Weg beschreitet die Methode apply, indem sie diese einzelnen Bestandteile wieder zum einem Datum zusammenfügt.

import { Component } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/common';

@Component({
    selector: 'date-control',
    template: require('./date-control.component.html')
})
export class DateControlComponent 
                    implements ControlValueAccessor {

    day: number;
    month: number;
    year: number;
    hour: number;
    minute: number;

    constructor(private c: NgControl) {
        c.valueAccessor = this;
    }

    writeValue(value: any) {
        this.splitDate(value);
    }

    onChange = (_) => {};
    onTouched = () => {};

    registerOnChange(fn): void { this.onChange = fn; }
    registerOnTouched(fn): void { this.onTouched = fn; }


    splitDate(dateString) {
      var date = new Date(dateString); 

      this.day = date.getDate();
      this.month = date.getMonth() + 1;
      this.year = date.getFullYear();
      this.hour = date.getHours();
      this.minute = date.getMinutes();
    }

    apply() {

        var date = new Date();
        date.setDate(this.day);
        date.setMonth(this.month - 1);
        date.setFullYear(this.year);
        date.setHours(this.hour);
        date.setMinutes(this.minute);
        date.setSeconds(0);
        date.setMilliseconds(0);

        this.onChange(date.toISOString());
        this.onTouched();
    }

}

Damit diese Komponente mit dem Forms-Handling von Angular 2 zusammenspielen kann, implementiert sie das Interface ControlValueAccessor. Zusätzlich lässt sie sich die aktuelle Instanz von NgControl injizieren. Diese Instanz repräsentiert die Komponente im von Angular für ein Formular erzeugten Objektgraphen. Über die Eigenschaft valueAccessor gibt die Komponente bekannt, dass sie selbst als ihr eigener ControlValueAccessor fungiert.

Die Implementierung von writeValue nimmt einen neuen Wert vom Framework entgegen und delegiert ihn an splitDate. Die Implementierungen von registerOnChange und registerOnTouched nehmen hingegen den von Angular übergebenen Callback entgegen und hinterlegen diese in den Member-Variablen onChange bzw. onTouched.

Standardmäßig verweisen diese Member auf Funktionen, die keine Aufgaben erfüllen. Auf diese Weise ist gewährleistet, dass sie zu jedem Zeitpunkt auf eine gültige Funktion verweisen. Somit muss sie ein Aufrufer nicht gegen null bzw. undefined prüfen.

Nach dem Bearbeiten des Datums ruft das Template die Methode apply auf. Sie fügt die einzelnen Bestandteile des Datums zu einem Datum zusammen und übergibt es durch Aufruf von onChange an Angular. Zusätzlich bringt es der Vollständigkeit halber die Methode onTouched zur Ausführung.

Manfred Steyer: Writing custom form controls for Angular 2 [EN]

The German version of this post can be found here.

If you want your components to work with declarative (template-driven) and imperative forms, you have to implement the interface ControlValueAccessor. The methods defined by this interface permit Angular 2 to read and set the state of the control in question.

Such controls can be used with ngModel or ngControl. To illustrate this, the following example uses a custom date-control that binds a variable date with ngModel:

<!-- Deklaratives (template-driven) Forms-Handling -->
<date-control [(ngModel)]="date"></date-control>

Alternatively, such a component can use imperative forms to bind to a predefined Control-object. The following example illustrates this by binding the date-control with ngControl to the Control with the name date. Angular expects this Control-object in the ControlGroup that has been specified with ngFormModel:

<!-- Imperatives Forms-Handling -->
<form [ngFormModel]="filter">   
    <date-control ngControl="date"></date-control>
    [...]
</form>

The ControlGroup and the Control are provided via the component:

@Component({
    selector: 'flight-search',  
    template: require('./flight-search.component.html'),
    directives: [DateControlComponent]
})
export class FlightSearchImpComponent {


    public filter: ControlGroup;

    constructor(private fb: FormBuilder) {


        this.filter = fb.group({
           date: ['2016-05-01']
        });
    }

    [...]
}

This article describes the steps necessary to implement ControlValueAccessor. The total sample can be found here.

ControlValueAccessor

The interface ControlValueAccessor provides three methods for synchronizing the state of a control with the object graph Angular uses to represent a form:

//
// From the Angular2-Sources
//
export interface ControlValueAccessor {
    writeValue(obj: any): void;
    registerOnChange(fn: any): void;
    registerOnTouched(fn: any): void;
}

To write a value to the control, Angular uses the method writeValue. Since Angular must know about changes to the date, the SPA-flagship uses registerOnChange and registerOnTouched to register callbacks. The control has to call the first one, when the users changes the state. The latter one indicates that the field at least had the focus.

Implementing ControlValueAccessor

The following example demonstrates the implementation of the interface ControlValueAccessor. For this, it shows a simple component for editing dates. The method splitDate takes a date and breaks it down into its parts, which are offered for editing by the (here not shown) template. The method apply is putting those together to a date again.

import { Component } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/common';

@Component({
    selector: 'date-control',
    template: require('./date-control.component.html')
})
export class DateControlComponent 
                    implements ControlValueAccessor {

    day: number;
    month: number;
    year: number;
    hour: number;
    minute: number;

    constructor(private c: NgControl) {
        c.valueAccessor = this;
    }

    writeValue(value: any) {
        this.splitDate(value);
    }

    onChange = (_) => {};
    onTouched = () => {};

    registerOnChange(fn): void { this.onChange = fn; }
    registerOnTouched(fn): void { this.onTouched = fn; }


    splitDate(dateString) {
      var date = new Date(dateString); 

      this.day = date.getDate();
      this.month = date.getMonth() + 1;
      this.year = date.getFullYear();
      this.hour = date.getHours();
      this.minute = date.getMinutes();
    }

    apply() {

        var date = new Date();
        date.setDate(this.day);
        date.setMonth(this.month - 1);
        date.setFullYear(this.year);
        date.setHours(this.hour);
        date.setMinutes(this.minute);
        date.setSeconds(0);
        date.setMilliseconds(0);

        this.onChange(date.toISOString());
        this.onTouched();
    }

}

To be able to interact with the Forms-Handling of Angular 2, the component implements the interface ControlValueAccessor. In addition, it gets the current NgControl by the means of Dependency Injection. Angular uses this instance to represent the control within the object graph that has been created for the form. It sets the property ValueAccessor to the component itself. This means, that the component is it's own ValueAccessor.

The implementation of writeValue takes a new value from the framework and delegates it to splitDate. The implementations of registerOnChange and registerOnTouched however take callbacks from Angular and puts them into onChange and onTouched.

After the date has been changed, the template invokes the method apply. It adds the individual parts of the date together and passes it to Angular using onChange. In addition, for the sake of completeness, it executes the calback onTouched.

Manfred Steyer: Slides and samples from my talk about ASP.NET Core for MVC- and WebAPI-Devs at NDC Oslo 2016

Please find below, the slides and samples from my talk about ASP.NET Core for MVC- and WebAPI-Devs at NDC Oslo 2016:

codefest.at [MS]: Visual Studio 2015 Update 3 RC

Heute ist gerade noch eine rasche aktuelle Meldung reingekommen: Developer, die schon auf die nächste Version von Visual Studio Update gewartet haben, erhalten ab heute Visual Studio 2015 Update 3 RC.

Hier geht es zum Download:

SNAGHTML175820fa

Die Ankündigung Visual Studio 2015 Update 3 RC im Visual Studio Blog informiert darüber, dass der vorliegende Release Candidate vor allem Stabilität und Performance bringt, jedoch auch einige Feature Updates enthalten sind.

Die wesentlichen Verbesserungen betreffen Tools for Apache Cordova, Application Insights and HockeyApp, Debugging and Diagnostics, Visual Studio IDE, C#/VB/Roslyn sowie Tools für Universal Windows Apps.

Einen Überblick der Neuerungen gibt es unter Visual Studio 2015 Update 3 RC anzusehen.

Eine detaillierte Liste der Updates gibt es in den Visualstudio Releasenotes VS2015 Update 3 RC, gemeldete Probleme sind unter Visual Studio 2015 Update 3 RC Known Issues zu finden.

SNAGHTML176260a2

Viel Spaß mit VS2015 Update3 RC!

Karsten Kempe: Visual Studio Team Services – Neue Branch-Übersicht und Kanban-Filter

VSTSMit dem letzten Sprint-Update hat es zwei coole Änderungen gegeben, die ich Euch vorstellen möchte. Zum Einen hat die Branch-Übersicht in den Visual Studio Team Services ein neues Layout bekommen und zum Anderen erlaubt nun das Kanban-Board Mehrfachfilterung. Sehr schick und übersichtlich ist es geworden. Seht selbst.

Branch-Übersicht

Hilfreich ist die neue Unterteilung von „Mine“ und „All“. Damit kann man sich als Entwickler nun besser auf die Branches fokussieren, die auch tatsächlich im Alltag relevant sind.

NewBranchViewFür alle die es noch nicht gesehen haben: Das Kontext-Menu beherbergt dich wichtigsten Funktionen wie „New Branch“, „Create Pull-Request“, „View History“, aber auch „Branch Policies“.

Wenn Ihr alle Branches sehen wollt, dann schaltet einfach um auf den „All“-View. Einfacher geht’s nicht.

Mehrfachfilterung Kanban-Board

Ein weiteres Highlight in diesem Update ist die Mehrfachfilterung auf dem Kanban-Board. Die Filterung ist so ins System integriert worden, dass sie benutzerspezifisch persistiert wird und der Filter somit beim erneuten Aufruf (egal an von welchem Device oder Browser) immer noch aktiv ist.

MehrfachfilterKanban

Diese Neuigkeiten und viele mehr, gibt es auf der Feature Timeline zum Nachlesen.

Fabian Deitelhoff: Teil 4 – Der Raspberry Pi 2 als Mediacenter mit OSMC (Alles zu Quellen & Scrapern)

Die letzten Teile der Serie haben uns zu einem fast vollständigen Mediacenter geführt, zudem nicht mehr viel fehlt, um damit beispielsweise Videos abzuspielen. Falls ihr OSMC schon vorher installiert hattet und erst jetzt in diese Serie einsteigt, ist das allerdings auch kein Problem. Dieser Teil der Serie sollte euch dann trotzdem weiterhelfen, da es jetzt um das Einrichten von Quellen aller Art geht.

Zunächst geht es darum, was Quellen eigentlich sind, welche Quellen von OSMC unterstützt werden und wie diese konfiguriert werden müssen, damit ihr auch Videos und Co. abspielen könnt. Falls ihr die vorherigen Teile der Serie übersprungen habt, empfehle ich euch trotzdem noch den vorherigen Artikel. Denn in Teil vier werden einige grundlegende Konfigurationsschritte gezeigt, um eine Erstinstallation von OSMC einzurichten.

Dieser Blogpost ist Teil einer Serie zum Thema “Der Raspberry Pi 2 als Mediacenter mit OSMC”. Im Rahmen dieser Serie sind die folgenden Teile erschienen. Der jeweils aktuelle Beitrag ist hervorgehoben.

  1. Teil – Der Raspberry Pi 2 als Mediacenter mit OSMC (Einführung)
  2. Teil – Der Raspberry Pi 2 als Mediacenter mit OSMC (Hardware)
  3. Teil – Der Raspberry Pi 2 als Mediacenter mit OSMC (Installation)
  4. Teil – Der Raspberry Pi 2 als Mediacenter mit OSMC (Alles zu Quellen & Scrapern)

Wer ein Mediacenter mit dem Raspberry Pi 1 einrichten möchte, wird eventuell bei der vorherigen Serie zum Thema fündig. Zumindest was die Hardware anbelangt. Der Teil zur Software ist wieder in der aktuellen Serie relevant.

Was sind Quellen?

Ganz zu Beginn eines Mediencenters sieht es in der Oberfläche noch düster und leer aus. Jeder, der bis hier hin gekommen ist oder vielleicht schon eine Installation von OSMC hatte, wird das schnell bestätigen können. Die Software ist zwar installiert, aber wirklich viel damit anfangen, vor allem alles, was in Richtung Mediacenter geht, lässt sich nicht. Denn es fehlt vor allem eins: Medien.

Diese Medien lassen sich in OSMC, wie schon beim Vorgänger, durch Quellen hinzufügen beziehungsweise eher bereitstellen. Hinzugefügt werden Quellen, über die dann Medien abspielbar sind. Das bedeutet im Umkehrschluss auch, dass die Medien nicht wirklich zu OSMC hinzugefügt werden. Unser Mediacenter verwaltet die Filme, Bilder etc. pp. nur. Der Sinn und Zweck von Quellen ist damit schnell erklärt: Sie dienen als Ursprung/Bezugspunkt für alle Medien, die in OSMC abgespielt, angezeigt oder angehört werden sollen.

Teil 4 – Der Raspberry Pi 2 als Mediacenter mit OSMC (Alles zu Quellen & Scrapern)

Welche Quellen werden unterstützt?

OSMC unterstützt eine ganze Reihe von verschiedenen Quellen, die sich alle komfortabel über die Oberfläche konfigurieren lassen. Die folgende Liste umfasst alle Quellen, die standardmäßig in OSMC nutzbar sind, ohne externe Erweiterungen in Form von Addons zu berücksichtigen.

  • HDHomerun Geräte
  • Home-Ordner
  • Netzwerk-Dateisystem (NFS)
  • Root-Dateisystem
  • SAP-Streams
  • UPnP Geräte
  • Video-Wiedergabelisten
  • Windows-Netzwerk (SMB)
  • Zeroconf-Browser

Die darunter liegenden Techniken sind unter Umständen mehrfach vorhanden. So nutzten die Einträge „Home-Ordner“ und „Root-Dateisystem“ beide das Dateisystem vom Raspberry Pi. Aber das ist an dieser Stelle gar nicht so wichtig.

Ich nutze ein Netzwerk-Dateisystem, da ich alle Daten auf meiner Netzwerkfestplatte gespeichert habe, die ich im Hardware-Teil zu dieser Serie schon verlinkt habe. Diese Option ist, neben dem Zugriff auf ein Windows-Netzwerk über SMB, vermutlich auch mit die beliebteste, um Medien über Quellen in OSMC einzubinden.

Die konkrete Konfiguration für Videos, Bilder und Musik ist in den unteren Abschnitten mit zahlreichen Abbildungen erklärt.

Ordnung muss sein

Bevor wir uns konkret um das Einrichten von Quellen kümmern, möchte ich noch ein paar Worte zur Organisation von Dateien im Dateisystem verlieren. Es ergibt viel Sinn, sich vor dem Einrichten der Quellen Gedanken darüber zu machen, wie die einzelnen Dateien bei den Quellen organisiert werden sollen. Denn stellen wir nach dem Einrichten fest, dass die Organisation im Dateisystem nicht wirklich Vorteilhaft ist, müssen wir nicht nur die Dateien umsortieren, sondern im Zweifel auch die Quellen in OSMC neu konfigurieren. Zusätzliche Arbeit die wir uns gut und gerne sparen können.

Eine wirkliche Organisation habe ich auch nur für Filme und Serien. Musik und Bilder habe ich einfach, thematisch sortiert, in Ordner auf der Netzwerkfestplatte. Thematisch sortiert bedeutet, dass ich Musik nach Album und Bilder nach Entstehung sortiert habe. Letzteres zum Beispiel bei Events nach Datum sortiert. Also nichts total ausgeklügeltes oder aufwändiges. Ich muss aber auch dazu sagen, dass ich mein Mediacenter zu 98% für Filme und Serien nutze. Bilder schaue ich mir darüber so gut wie nie an und Musik wird ganz selten gespielt. Diese Aufgabe hat mittlerweile Spotify übernommen.

Wenn wir daran denken, eine ordentlich Einteilung unserer Daten vor dem Einrichten des Mediacenters vorzunehmen, ist alles ohne großen Aufwand getan. Nachträglich möchte ich das nicht mehr machen. Vor allem nicht, wenn ich mein OSMC dann noch komplett anpassen müsste. Grundsätzlich geht das aber. Der Abschnitt zum Anpassen von Quellen zeigt, dass Quellen auch nachträglich geändert werden können. Aufwand bedeutet das aber natürlich trotzdem.

Da Filme bei mir immer einzeln sind, habe ich alle in einem Ordner. Die Serien sind, oh Wunder nach Serien sortiert, in Unterordnern in einem eigenen Ordner abgelegt. Ich hoffe, dass wird über die Abbildung deutlich. Was für Vorteile das hat, zeigen die nächsten Abschnitt recht deutlich, wenn es um die Auswahl der Datenquellen für die jeweiligen Quellen geht.

Videos abspielen (inkl. Einstellungen)

Abspielen von Videos ist sicherlich für viele der Hauptzweck, über ein Mediacenter nachzudenken und es letztendlich selbst zu bauen. Also kümmern wir uns auch direkt um das Einrichten von Quellen für Videos aller Art. Dazu gehören nicht nur Filme, sondern natürlich auch Serien.

Bevor ich die Quellen einrichte, konfiguriere ich immer einige Sachen beziehungsweise überprüfe die Standardeinstellungen. Diese Einstellungen sind unter Einstellungen | Video zu finden (siehe Abbildungen 1 und 2). Optionen gibt es dort eine Menge, allerdings ist nicht alles relevant.  Zumindest für mich nicht. Wer Fragen zu speziellen Einstellungen hat, kann daher gerne eine Nachricht oder einen Kommentar hinterlassen.

Abb. 1: Einstellungen des Mediacenters. Abb. 2: Einstellungen bezogen auf Videos.

Unter Bibliothek nehme ich die Einstellungen vor, wie sie in Abbildung 3 zu sehen sind. Ich finde es gut, wenn die Handlung bei ungesehenen Filmen angezeigt wird, wenn OSMC Vorschaubilder von Darstellern herunterlädt und wenn die Bibliothek beim Start des Mediacenters aktualisiert wird. Mit Bibliothek wird die Sammlung aller Videos bezeichnet, die OSMC in seine Datenbank aufgenommen hat. In die Datenbank kommen aber auch nur die Metadaten. Also um welches Genre handelt es sich, wie wurde bewertet etc. pp. Die Filmdatei bleibt weiterhin in der Quelle und wird nicht irgendwohin kopiert.

Bei der Wiedergabe (siehe Abbildung 4) ist mir wichtig, dass die Standard-Tonspur bevorzugt und das nächste Video nicht direkt nach dem Ende des vorherigen abgespielt wird. Den Teletext habe ich in der aktuellen Konfiguration im aktiven Zustand belassen. Vermutlich deaktiviere ich ihn in Zukunft, da ich das Feature nicht wirklich nutze. Die Dateilisten, zu sehen in Abbildung 5, stelle ich so ein, dass Video-Informationen nicht aus den Dateien extrahiert werden. Auch die Vorschaubilder (Thumbnails) für Kapitel lasse ich nicht generieren, ebenso wie die Vorschaubilder der Filme an sich. Alles kostet recht viel Rechenleistung. Wie sich das auf dem aktuellen Raspberry Pi 2 verhält, habe ich aber zugegebenermaßen noch nicht getestet. Bei den vorherigen Versionen war mir die Hardware damit zu sehr ausgelastet. Die Video-Informationen kommen ohnehin aus externen Datenbanken und werden durch Scrapper gesammelt, so dass ich die Daten der Video-Dateien nicht benutze.

Abb. 3: Einstellungen zur Video-Bibliothek. Abb. 4: Einstellungen zur Wiedergabe von Filmen und Serien. Abb. 5: Einstellungen der Dateilisten.

Bei den Untertiteln bevorzuge ich die Sprache des Streams. Wenn also Deutsche Untertitel eingestellt sind, möchte ich diese auch angezeigt bekommen (siehe Abbildung 6). Die Einstellungen für Discs (siehe Abbildung 7), also externe Datenträger, habe ich nicht verändert, da ich aktuell keine Hardware dafür angeschlossen habe. Auch die Einstellungen unter Barrierefreiheit habe ich nicht verändert, wie in Abbildung 8 abgebildet. Da muss natürlich jeder für sich entscheiden, ob das so passt.

Abb. 6: Einstellungen zu Untertiteln. Abb. 7: Einstellungen zu externen Abspielgeräten (Discs). Abb. 8: Einstellungen zur Barrierefreiheit.

Nach diesen ersten Einstellungen können wir eine neue Quelle hinzufügen. Im Menü unter Videos | Dateien (siehe Abbildung 9) kann ich Dateien zur Mediathek hinzufügen, die sich dann später abspielen lassen. OSMC fragt anschließend einige Informationen ab. Zum Beispiel den Namen der Quelle (siehe Abbildung 10) und wo sich diese befindet. Wir erinnern uns: Dafür gab es mehrere Möglichkeiten. Zum Beispiel eine Netzwerkfestplatte, die ich einsetze. In Abbildung 11 wähle ich daher für meinen Fall den Eintrag Netzwerk-Dateisystem (NFS) aus und gebe die genaue Adresse an. OSMC zeigt die IP-Adresse auch schon an und wir müssen nur noch zum korrekten Ordner navigieren (siehe Abbildung 12).

Abb. 9: Video-Dateien zur Mediathek hinzufügen. Abb. 10: Die neue Quelle braucht einen Namen. Abb. 11: Den Ort der Quelle angeben. Abb. 12: OSMC findet meine Netzwerk-Festplatte und zeigt die IP-Adresse an.

Bei mir ist, wie oben bei den Tipps zur Ordnung schon geschrieben, das Verzeichnis Videos | Filme. Abbildung 13 zeigt alle Einstellungen der neuen Quelle noch mal auf einen Blick. Wenn der Name und der Ort passen, kann es mit OK weitergehen. Als nächstes müssen wir auswählen, welche Art von Medien sich denn hinter der neuen Quelle befinden. Da es sich um Filme handelt, wählen wir als Scrapper The Movie Database aus (siehe Abbildung 14). Scrapper sind kleine Programme, die Informationen einer Datei im Internet nachschlagen. Also zum Beispiel die Handlung, Schauspieler, Altersfreigaben und viel mehr. Vor allem aber wird auch ein kleines Vorschaubild heruntergeladen, das uns in der Mediathek angezeigt wird, damit wir viel schneller den richtigen Film aussuchen können und uns nicht nur anhand eines Namens durch die Liste hangeln müssen.

Zusätzlich sind noch einige Optionen interessant, wie zum Beispiel die Sprache (siehe Abbildung 15) und von woher wir Filmbewertungen beziehen wollen. In meinem Fall gerne von IMDb (siehe Abbildung 16). Aber das ist Geschmackssache. Diese Einstellungen erreichen wir über den Menüpunkt Einstellungen unten rechts beim Festlegen eines Inhalts.

Abb. 13: Name und Verzeichnis der neuen Quelle. Abb. 14: The Movie Database als Information zu den Inhalten. Abb. 15: Bevorzugte Sprache für die Informationen. Abb. 16: Weitere Einstellungen wie die Quelle für Bewertungen.

Damit sind die Quellen für Spielfilme eingerichtet. Im Menüpunkt Videos zeigt uns OSMC die auch schon fleißig an. Allerdings erst, nachdem die interne Datenbank aktualisiert wurde. Das bedeutet, dass OSMC erst die neu hinzugefügte Quelle durchsucht, die dort gefunden Dateien mit The Movie Database abgleicht und die Informationen intern speichert, um sie uns anzeigen zu können. Wie das aussehen kann zeigen die Abbildung 17 und 18.

Abb. 17: Übersicht der hinzugefügten Filme mit Vorschaubild. Ab. 18: Übersicht der hinzugefügten Filme als Liste.

Zu Videos gehören aber auch Serien. Und auch die wollen als Quelle in unsere Bibliothek aufgenommen werden. Da das Verfahren praktisch identisch ist, spare ich mir an dieser Stelle viel Text und zeige euch lieber ein paar Bilder. Bei den Videos gibt es nun einen Eintrag Filme (siehe Abbildung 19). Das ist die zuvor hinzugefügte Quelle für Filme. Über Videos hinzufügen geht es jetzt wieder zur Auswahl des Speicherorts. In meinem Fall wähle ich dort das Verzeichnis für meine Serien aus, die ich in einem anderen Verzeichnis aufbewahre (siehe Abbildung 20).  Anschließend ist noch die ein oder andere Option interessant, die in den Abbildungen 21 und 22 zu sehen sind. Die Informationen kommen dieses Mal von TVDB. Ansonsten ist das Prozedere wie bei den Spielfilmen.

Abb. 19: Serien hinzufügen. Abb. 20: Speicherort für die Serien auf der Netzwerk-Festplatte. Abb. 21: TVDB für Informationen zu den Inhalten. Abb. 22: Einstellungen von TVDB.

Damit sind die Spielfilme und Serien eingerichtet. Abbildungen 23 und 24 zeigen, wie eine Übersicht der Serien aussehen kann. Wie bei den Filmen gibt es eine Listenansicht. Und zusätzlich dazu eine Ansicht der letzten Episoden, was nur bei Serien Sinn ergibt.

Abb. 23: Übersicht der vorhandenen Serien als Liste. Abb. 24: Zuletzt hinzugefügte Serien.

Musik & Bilder

Bei Musik und Bildern sieht es genau so aus. Über den Eintrag Musik beziehungsweise Bilder im Hauptmenü können Quellen für diese beiden Inhalte erstellt werden. Die Menüführung ist vollständig identisch zu dem Beispiel mit den Videos. Die Galerie unten enthält einige Screenshots dazu (Abbildungen 25 bis 29). Es ist allerdings tatsächlich nichts Besonderes.

Abb. 25: Menüeintrag um Musikdateien hinzuzufügen. Abb. 26: Musik hinzufügen. Abb. 27: Auswahl eines Ordners wie bei Videos. Abb. 28: Menüeintrag zum Bilder hinzufügen. Abb. 29: Auswahl eines Ordners.

Da diese Vorgehensweise so identisch ist, spare ich mir an dieser Stelle große Worte. Bei Fragen einfach einen Kommentar verfassen oder eine direkte Nachricht schreiben. Im Zweifel passe ich diesen Teil dann noch mal an, wenn etwas unklar sein sollte.

Allerdings ist es noch nicht wirklich schön, sich Bilder über das Mediacenter anzuschauen oder Musik zu hören. Beides wird erst durch Plugins wirklich gut, die ich aber in einem anderen Teil vorstellen möchte. Dieser Teil ist schon umfangreich genug.

Quellen editieren

Wenn die Quellen erst einmal angelegt sind, kann es im Nachhinein passieren, dass wir doch noch Änderungen vornehmen möchten. Erfreulicherweise lassen sich Quellen nachträglich bearbeiten. Nicht ganz so schön ist allerdings, dass dazu ein Eingabegerät notwendig ist. Zumindest ist mir aktuell nicht bekannt, dass das auch mit der Fernbedienung geht. Ich habe dafür temporär eine Maus über Bluetooth an das Mediacenter angeschlossen. Denn dann kann ich mit der rechten Maustaste auf eine Quelle klicken und diese editieren. Die beiden Abbildungen 30 und 31 zeigen dazu jeweils einen Screenshot.

Abb. 30: Kontextmenü zum Bearbeiten einer Quelle. Abb. 31: Inhalts einer Quelle wechseln.

Abbildung 31 zeigt, was passiert, wenn der Inhalt einer Quelle geändert wird. Also zum Beispiel, weil die Quelle von Filmen auf Serien umgestellt wurde. Dann möchte OSMC den Inhalt wechseln, neue Metadaten laden und so weiter. Daher die Abfrage, ob wir das auch wirklich wollen. Ansonsten können wir den Ordner der Quelle ändern, ein Bild festlegen oder die Quelle auch ganz löschen, um nur ein paar Beispiele zu nennen.

Was sind Scraper?

Scraper sind auch unter dem Begriff Web Scraper bekannt. Letzteres ist die eher allgemeinere Bezeichnung. Der Begriff Scraper taucht dagegen vermehrt im Zusammenhang mit zum Beispiel OSMC auf.

Dahinter verbergen sich kleine Programme die Informationsquellen im Internet nutzen, um dort Daten anzufragen beziehungsweise abzufragen. Bei der Konfiguration oben haben wir schon Scraper genutzt. Zum Beispiel ist The MovieDB ein Scraper. Ganz genau ein Scraper, der ebendiese MovieDB nutzt, um Informationen zu Filmen abzufragen.

Diese Informationen sind die Metadaten eines Films oder einer Serie. Wir haben ja nur die Datei mit einem Dateinamen auf irgendeinem Laufwerk zur Verfügung. Wer da jetzt mitgespielt hat, wie die Handlung aussieht, ein Vorschaubild etc. pp. befinden sich nicht in der Datei. Also müssen diese Informationen irgendwoher kommen. Genau diese Arbeit übernehmen Scraper für uns.

Zwischenfazit

Und das war der vierte Teil der Serie. Ich habe es leider nicht eher geschafft, was mir sehr leid tut. Allerdings ist gerade viel los und es steht auch noch ein Umzug an, was meine zur Verfügung stehende Zeit nicht gerade vergrößert.

Mittlerweile ist unser Mediacenter so weit, dass wir Filme und Serien gucken können. Auch Musik und Bilder sind verfügbar, wenn auch noch nicht wirklich schön, aufgrund der fehlenden Plugins.

Im fünften Teil der Serie kümmern wir uns um allgemeine Einstellungen des Mediacenters, die das komplette System betreffen und nicht nur einzelne Bereiche wie Filme oder Serien.

Bis dahin danke ich euch für die zahlreichen Kommentare und E-Mails zum Thema. Ich helfe immer gerne und lasse die Anmerkungen und Fragen auch in weitere Teile einfließen.

Sven Hubert: WiX Toolset Teil 2: Wie sieht das denn aus? – Das WiX Toolset User Interface

Das WiX Toolset wird bereits mit verschiedenen Benutzeroberflächen ausgeliefert. So kann ein einfacher Installationsassistent durch das Hinzufügen eines UIRef Elementes innerhalb des Product Elementes erstellt werden. Diese bereits mitgelieferten User Interfaces bieten verschiedene, anpassbare Optionen. So ist beispielsweise eine Installationsroutine, die das Einstellen des Installationspfades erlaubt, genauso enthalten wie ein Assistent, der das an und abwählen von Features integriert. Eine Liste aller bereits enthaltener Benutzeroberflächen und deren Anwendung finden sie hier.

Doch was ist, wenn die Standard Oberflächen nicht ausreichen? Am Beispiel eines erweiterten EULA Dialogs möchte ich an dieser Stelle die Möglichkeiten zur Individualisierung der Benutzeroberfläche aufzeigen. Um die Anforderungen einer internationalen Anwendung zu erfüllen, muss natürlich auch die EULA in verschiedenen Sprachen vorliegen. Um diese im Installationsassistenten anzeigen zu können, benötigt unser Dialog eine Sprachauswahl. Dazu erstellen wir einen komplett eigenen Dialog.

Die Definition eines neuen Dialoges erfolgt an beliebiger Stelle innerhalb eines UI Elements. Dazu wird ein neues Dialog Element inklusive ID erstellt und mit beliebig vielen Control Elementen befüllt. Im Folgenden Screenshot wird die komplette Definition eines Dialoges zur EULA Auswahl dargestellt.

clip_image002

Die Unterscheidung der Sprachen innerhalb des Dialoges erfolgt über das Property LicenseLanguage, das außerhalb des Dialoges definiert wird und den initialen Wert „en“ erhält.

clip_image004

Um dieses Property zu beschreiben werden in der Benutzeroberfläche Radiobuttons verwendet. Diese werden über ein Control vom Typ RadioButtonGroup eingefügt. Über die X und Y Werte können die Positionen innerhalb des Fensters bestimmt werden. Das Property Attribut gibt an, welches Property durch die Radiobuttons beeinflusst werden soll. Die einzelnen Radiobutton Elemente beinhalten schließlich einen Wert, der bei der Auswahl in das Property geschrieben wird sowie einen Text, der neben dem Button angezeigt wird. In diesem Fall kommt der Text aus einer Lokalisierungsdatei.

clip_image006

Der Dargestellte Text wird schließlich auch wieder über ein Control bestimmt. Dieses Control hat den Typ ScrollableText, um auch größere Texte lesbar zu gestalten. Der Text selbst wird über das Text Element aus einer Datei im RTF Format eingelesen. Um die Auswahl zu ermöglichen werden noch zwei Condition Elemente eingefügt, die das Control verstecken, beziehungsweise anzeigen, wenn das LicenseLanguage Property bestimmte Werte einnimmt. Um Operatoren abzubilden, die der XML Parser als XML Syntax erkennen würde, bedienen wir uns des CDATA Elementes.

clip_image008

Analog dazu wird auch das Akzeptieren der Lizenz verwaltet. In einer Checkbox wird das Property LicenseAccepted auf den Wert 1 gesetzt, wenn die Checkbox markiert wurde. Im „Next“ Button wird überprüft, ob der Wert des Properties 1 ist, ansonsten wird der Button deaktiviert. Der Unterschied ist an dieser Stelle, dass das Property LicenseAccepted nicht im Vorfeld angelegt, sondern direkt im Checkbox Element erzeugt wird.

clip_image010

clip_image012

Natürlich soll der Dialog auch das Logo der Anwendung beinhalten. Dazu wird ein Control vom Typ Bitmap angelegt, das als Text Attribut die ID eines Binary Properties übergeben bekommt. Dieses zeigt auf eine in den Ressourcen hinterlegte Bitmap Datei.

clip_image014

clip_image016

Nachdem der Dialog erstellt wurde, muss er nun in den bestehenden Installationsassistenten integriert werden. Dazu werden alle Dialoge der Reihenfolge nach in Publish Elementen unterhalb des UI Elements aufgelistet. Innerhalb des Publish Elements wird der Dialog spezifiziert, der ein bestimmtes Control beinhaltet. Diesem Control werden schließlich Events zugewiesen. Im gezeigten Beispiel werden die Standard-Dialoge WelcomeDlg, VerifyReadyDlg und ExitDialog genutzt, und der MyLicenseAgreementDlg dazwischen eingefügt. Dabei wird auch noch einmal überprüft, ob das LicenseAccepted Property den Wert 1 beinhaltet.

clip_image018

Und so sieht der fertige EULA Dialog aus:

clip_image020

 

Im nächsten Teil der WiX Blog-Reihe lesen sie, wie sie Shortcuts richtig erstellen, sowie eine installierte Anwendung auch wieder sauber vom System entfernen.

Jan-Cornelius Molnar: Compiling UDF with ANSYS 16 and Visual Studio 2015

Compiling UDF with ANSYS 16 and Visual Studio 2015 To compile User Defined Functions (UDF) with ANSYS you need to install a C++ compiler. ANSYS recommends Visual C++ which is freely available in form of Visual Studio Community . In this article I will...(read more)

Kay Giza [MS]: Greift zu! Die Microsoft Virtual Academy (MVA) hat jetzt einen Embed-Player

Seit einigen Wochen besteht jetzt endlich auch die Möglichkeit, einzelne Kurse oder ganze Lektionen auf Dritten Webseiten via embed Player einzubinden. Beispielsweise um auf Inhalte aufmerksam zu machen oder gar Interessierten komplette Lernfade zu empfehlen. Ob auf der eigenen Webseite, in Foren, auf Blogs oder Weiterbildungs-Portalen. Wie das geht? ... [... 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

Fabian Deitelhoff: Verlosung: „Windows Store Apps mit XAML und C#“ + „Apps entwickeln für Windows 8 und RT“

In diesem Beitrag geht es nur indirekt um eine Rezension, da ich die beiden Sachen, die ich verlosen möchte, nur teilweise gelesen beziehungsweise mir nur teilweise angeschaut habe. Aufgrund des Umfangs beider Werke fehlte mir die Zeit, sie komplett durchzuarbeiten. Zumal beide auch schon etwas älter sind. Da ich aber Dinge ungerne einfach wegwerfe, möchte ich beides trotzdem verlosen. Vielleicht ist für den ein oder anderen doch etwas dabei.

Langer Rede kurzer Sinn: Dieses Mal geht es um das Buch Windows Store Apps mit XAML und C# und zweimal um das Video-Training Apps entwickeln für Windows 8 und RT.

Die Inhalte

Windows Store Apps mit XAML und C# (Rheinwerk, Thomas Claudius Huber) Apps entwickeln für Windows 8 und RT (Rheinwerk, Tom Wendel)

Ich hatte beides genutzt, um mich in die Thematik der Windows Store Apps einzuarbeiten. Rein aus Interesse und für private Projekte nebenher. Das hat auch sehr gut funktioniert, leider hat es meine Zeit dann nicht zugelassen, dass ich die Projekt fertigstellen konnte. Was auch der Grund war, warum ich dann irgendwann aufgehört habe und mir nicht beide Werke in Gänze zu Gemüte geführt habe.

Wer Informationen zu XAML und C# haben möchte, wird ebenso bedient, wie mit Wissen zu WinRT und dem Windows Store. Vermutlich ist auch noch viel von dem Wissen zu XAML nutzbar, selbst wenn das Buch und das Video-Training zu Technologien sind, deren Zukunft nicht ganz so gewiss ist. Es sollte sich aber schon für eine Einarbeitung in XAML lohnen, da zum Beispiel folgende Themen abgedeckt werden:

  • GUIs
  • Styles
  • Templates
  • 2D-Grafiken
  • Animationen
  • Sensor-Unterstützung

Fazit & Bewertung

Eine tatsächliche Wertung traue ich mir an dieser Stelle nicht zu. Einfach aus dem Grund, weil ich weder das Buch noch das Video-Training vollständig gelesen oder gar durchgearbeitet habe. Was ich von beiden mitbekommen, gelesen und gesehen habe, fand ich allerdings sehr gut.

Tom Wendel macht einfach hervorragende Video-Trainings, zum Beispiel auch eins zur Spieleprogrammierung. Er kann gut erklären, den Beispielen ist leicht zu folgen und sie ergeben Sinn. Also weit über „Hallo Welt“-Prototypen hinausgehend, was ich immer ganz wichtig finde.

Für das Buch sieht es genau so aus. Thomas Claudius Huber hat einen guten Schreibstil, mit dem er ohne Probleme Wissen rüberbringen kann. Erfreulich fand ich auch, dass das Buch recht schnell zum Punkt kommt. Schon auf Seite 90 geht es direkt mit der ersten Beispiel-App los. Allerdings weiß ich dadurch nicht, ob sich das Buch für komplette Neueinsteiger handelt. Einige Programmierkenntnisse sollte schon vorhanden sein, behaupte ich mal.

Zur Verlosung

Und wieder einige obligatorische Informationen zur Verlosung. Beides wurde mir freundlicherweise vom Rheinwerk Verlag zur Verfügung gestellt. Die zweite Kopie des Video-Trainings von Tom Wendel direkt. Alles ist in einem sehr guten Zustand.

Ich verschicke auch alles direkt. Die Kosten übernehme selbstverständlich ich. Bis auf eine Adresse brauche ich dann auch nichts weiter. Dazu melde ich mich allerdings noch mal beim Gewinner beziehungsweise der Gewinnerin per E-Mail, die beim Kommentar mit angegeben werden muss. Die E-Mail Adresse ist natürlich nur von mir einsehbar.

Wer gewinnen möchte, hinterlässt bitte einen Kommentar, warum er oder sie das Buch oder das Video-Training gerne hätte. Das muss nichts Besonderes sein. Ich möchte nur gerne vermeiden, dass Kommentare auftauchen, die offensichtlich dadurch entstanden sind, das einmal von links nach rechts mit dem Gesicht über die Tastatur gerollt wurde. 🙂

In den Kommentaren können auch gerne das Buch und ein Video-Training genannt werden. Alles drei auf einmal geht nicht. Ein Video-Training möchte ich gerne separat verschicken.

Aus allen Kommentaren fische ich dann per Zufall einen heraus, so wie ich das bei den letzten Verlosungen auch gemacht habe. Die Verlosung läuft von heute, Sonntag den 05. Juni 2016 bis zum Freitag, den 10. Juni 2016 um 12:00 Uhr. Die Teilnahme ist ab 18 Jahren möglich und der Rechtsweg ist wie üblich ausgeschlossen.

Bei Fragen zum Buch oder sonstigen Angelegenheiten zur Verlosung freue ich mich immer über Kommentare und Nachrichten.

Vielen Glück allen!

codefest.at [MS]: #Ch9weekly - NuGet Package

 

Jede Woche stellen wir ein interessantes Channel 9 Video für Euch hier zur Verfügung, damit Ihr stets einen Wissensvorsprung haben könnt.

Diese Videoserie gibt einen Einblick in die Welt von NuGet packages. NuGet ist eine open-source Paketverwaltung für Softwareentwicklung unter .NET. Die NuGet Packages selber kann man HIER herunterladen.

Wie Ihr selber ein NuGet package erstellt, seht Ihr dann in diesem Video

Sven Hubert: Continuous Quality und warum Standardisierung unabdingbar ist

Höchste Qualität in allen Disziplinen im Entwicklungsprozess – wohl ein Wunsch eines jeden Entwicklungsteams. Wenn man an kurze Lieferzyklen denkt und die Geschwindigkeit, in der eine Funktion von der Idee bis zum Kunden gebracht wird, ist Continuous Quality sogar ein Must-Have-Requirement an den Prozess. Doch wie erreicht man dies?

Im Blog der DWX (Developer Week Konferenz) ist dazu unser Blogpost Continuous Quality und warum Standardisierung unabdingbar ist erschienen. Er gibt eine Einführung in das Thema und einen Ausblick auf unseren Vortrag zu Continuous Quality.

Sven Hubert: Notifizieren auf Build VNext BuildCompleted Events

Mit dem TFS 2015 wurde das neue Team Build System für die OnPremise-Version eigeführt. Seitdem ist die Umstellung von XAML Builds auf das neue JSON basierte Build-Format in vollem Gange. Die Vorteile des neuen Build Systems liegen auf der Hand und müssen an dieser Stelle nicht nochmals thematisiert werden. Doch nicht nur die bestehenden Build Definitionen müssen angepasst und umgestellt werden, auch bestehende Erweiterungen für den TFS müssen für die neue Technologie fit gemacht werden. Nicht jeder kann oder will auf VSTS und seine Extensions umsteigen. Somit besteht noch immer Bedarf an großen und kleinen Erweiterungen für TFS onPremise Installationen.

Doch zurück zu dem eingangs erwähnten Umstieg vom alten auf das neue Buildsystem. Was passiert, wenn eine Erweiterung auf fertiggestellte Builds reagieren soll? Richtig, sie hängt sich an den TFS und notifiziert sich auf das entsprechende Event. Anwendungsfälle dafür könnten spezielle Benachrichtigungen, die Anbindung von externen Tools oder schlicht das Triggern weiterer Operationen über die TFS API sein. Im Grunde stellt dies keine besondere Herausforderung dar. Von Microsoft wird für derartige Anwendungsfälle das ISubscriber Interface bereitgestellt. Mit Hilfe dieses Interfaces ist es möglich, sich auf verschiedenste Events des TFS zu notifizieren.

Das Interface selbst implementiert nur zwei Properties (Name und Priority) sowie die zwei Methoden SubscribedTypes, über die alle Events definiert werden, auf die man sich notifiziert und ProcessEvent, die aufgerufen wird, sobald eines der definierten Events auftritt.

Um die Unterschiede beim Umstieg auf das neue Build-System zu verstehen, wird im ersten Schritt das alte, XAML basierte, Buildsystem betrachtet. Möchte man über fertiggestellte XAML Builds informiert werden, so muss das BuildCompletionNotificationEvent als Rückgabewert der Methode SubscribedTypes definiert werden. Innerhalb der ProcessEvent Methode kann dann die weiterführende Implementierung vorgenommen werden. Die Assembly, in der die Implementierung des ISubscriber Interfaces vorgenommen wurde, muss anschließend in dem Ordner %ProgramFiles%\Microsoft Team Foundation Server 14.0\Application Tier\Web Services\bin\Plugins abgelegt werden und fertig ist das eigene TFS Plugin.

Notifizieren auf VNext Builds

Wer jetzt denkt, das würde reichen um auch VNext Build Events abzufangen, der irrt. Diese werden nicht nur über einen eigenen Event Typ abgebildet, die Assembly muss auch in einem anderen Ordner abgelegt werden.

Doch der Reihe nach: Das benötigte BuildCompletedEvent für VNext Builds, das als Rückgabewert von SubscribedTypes definiert werden muss, versteckt sich im Namespace Microsoft.TeamFoundation.Build.WebApi.Events der Assembly Microsoft.TeamFoundation.Build2.WebApi, welche im NuGet Paket Microsoft.TeamFoundationServer.ExtendedClient enthalten ist.

Der zweite Schritt ist das Ablegen der Plugin-Assembly, welche die Implementierung des ISubscriber Interfaces enthält, im Ordner %ProgramFiles%\Microsoft Team Foundation Server 14.0\Application Tier\TFSJobAgent\Plugins. Eine TFS Erweiterung welche sowohl XAML Build Completion Events, als auch JSON Build Completion Events verarbeiten kann, ist demnach an zwei Orte auf dem App-Tier zu verteilen.

clip_image002

Fazit

Eigene Erweiterungen für den TFS zu schreiben ist im Grunde einfach, Microsoft stellt eine umfangreiche API zur Verfügung, die nur benutzt werden will. Gelegentlich ist es jedoch etwas undurchsichtig, welche Klasse sich in welcher Assembly versteckt und wie diese Klasse richtig benutzt wird.

Sven Hubert: Software ist wie LEGO®

Gute Software zu entwickeln ist ein hartes Stück Arbeit. Umso größer ist die Freude und Erleichterung, wenn „es endlich geschafft ist“. Das Produkt kann verteilt und genutzt werden. Alle Anwender sind glücklich und zufrieden. Das Projekt ist fertig und man kann sich neuen Themen widmen.

Wäre es nicht schön, wenn die Realität so aussehen würde? Leider ist es in der Praxis jedoch etwas anders. Ein Produkt ist niemals fertig. Es gibt immer wieder Änderungswünsche, Erweiterungen und Fehlerbehebungen. Um dennoch effizient arbeiten zu können, spielt das Thema Modularisierung in der Softwareentwicklung eine große Rolle. Es reduziert den Einflussbereich von Änderungen und erhöht die Wiederverwendbarkeit von Modulen. Zusätzlich steigert es die Änderbarkeit der gesamten Anwendung durch die Möglichkeit einzelne Module flexibel hinzuzufügen oder zu ersetzen.  In der Theorie klingt das super. Praktisch sieht die Modularisierung von vielen Anwendungen jedoch leider so aus, wie ein bunt gemischter Haufen Legosteine, der von einer geordneten Struktur meilenweit entfernt ist:

Lego_Unmanaged

http://techbeacon.com/think-big-microservices-lego-software-development-takes-shape

Das muss jedoch nicht sein. Mit den passenden Tools wird das Verwalten von Modulen und deren Abhängigkeiten, auch als Dependency Management bekannt, zum Kinderspiel. In der folgenden Blog-Serie wird aufgezeigt, worin die größten Herausforderungen und Fallstricke beim Verwalten von Abhängigkeiten liegen. Es werden unterschiedliche Werkzeuge zur Umsetzung aufgeführt und ihre Einsatzbereiche beschrieben. So soll es Ihnen am Ende möglich sein, Ihre Bausteine richtig zusammen zu setzen und dem Fertig einen Schritt näher zu kommen.

https://trustonteachestech.wordpress.com/2013/05/01/the-use-of-frameworks/

https://trustonteachestech.wordpress.com/2013/05/01/the-use-of-frameworks/

LEGO® und das LEGO Logo sind eingetragene Marken der LEGOGruppe.

Holger Schwichtenberg: XAML-Debugging-Leiste in Visual Studio ausschalten

Der Debugging-Overlay für den "Live Visual Tree" und den "Live Property Explorer" kann stören. Daher ist es gut zu wissen, wie man ihn abschaltet.

Fabian Deitelhoff: Gelesen + Verlosung: Spiele entwickeln mit Unity 5

Vor einiger Zeit habe ich eine Rezension zum Buch Spiele entwickeln mit Unity veröffentlicht. Das Buch ist wirklich gut und auch zu Unity 5 gibt es ein Werk vom gleichen Autor Carsten Seifert. Daher gibt es nun mit diesem Beitrag auch zum Buch Spiele entwickeln mit Unity 5 eine Rezension inklusive Verlosung.

Das Buch im Überblick

Spiele entwickeln mit Unity 5

Hanser Fachbuch, 07/2015, 631 Seiten, Deutsch
ISBN: 978-3446445635, 39,99 Euro

Sprache: Deutsch
Ausstattung: Gebunden
E-Book: Auch als E-Book verfügbar
Probekapitel: Leseprobe ansehen
Gesamtnote: sehr gut – 5,0 von 5 Sternen
Leseempfehlung: Ja

Spiele entwickeln mit Unity 5 (Hanser Fachbuch, Carsten Seifert)

Der Inhalt

Das Buch ist, wie schon beim Vorgänger, klar und strukturiert aufgebaut, sehr schön gestaltet und bietet sehr viele Infos rund um die Entwicklung von Spielen mit Unity 5. Und das nicht nur für 2D- und 3D-Spiele, sondern auch für das Multiplattform-Publishing für Desktop, Web und Mobile.

Neben einführenden Kapiteln zur Installation, der Oberfläche und Infos zu einem Unity-Projekt, gibt es auch im neuen Buch eine Einführung in C# in Kombination mit Unity. Besondern für Interessierte, die bisher noch nichts mit C# gemacht haben, ist das sehr gut. Danach geht es, unter anderem, mit Kapiteln zur Skript-Programmierung, 2D- und 3D-Objekte, Kameras, Licht, Schatten und Partikeleffekte weiter. Und das sind nur einige Themen, die im Buch angesprochen werden.

Fazit & Bewertung

Auf mittlerweile über 600 Seiten bietet das Buch von Carsten Seifert zur Spieleentwicklung mit Unity 5 eine geballte Ladung Wissen. Sehr positiv ist, dass nicht nur Grundlagen, zum Beispiel zu Unity und C# erklärt werden, sondern auch darauf aufbauende Themen Gegenstand des Buchs sind.

Dazu kommen noch zwei Beispiele in größeren Kapiteln, die konkret zeigen, wie Spiele entwickelt werden können. Beim ersten Beispiel handelt es sich um ein 2D-Touch-Game, beim zweiten und einem 3D Dungeon Crawler.

Zu guter Letzt gibt es auch Infos zum Produktionsprozess in der Spieleentwicklung, um das Buch zu einem guten Abschluss zu bringen.

Zur Verlosung

Und wieder einige obligatorische Informationen zur Verlosung. Das Buch wurde mir freundlicherweise vom Hanser Verlag zur Verfügung gestellt. Gelesen habe ich es einmal. Dadurch ist das Buch in einem sehr guten Zustand. Auch die enthaltene E-Book Ausgabe ist noch verfügbar, da ich den Code nicht eingelöst habe.

Das Buch wird von mir verschickt. Alle Kosten übernehme selbstverständlich ich. Bis auf eine Adresse brauche ich dann auch nichts weiter. Dazu melde ich mich allerdings noch mal beim Gewinner beziehungsweise der Gewinnerin per E-Mail, die beim Kommentar mit angegeben werden muss. Die E-Mail Adresse ist natürlich nur von mir einsehbar.

Wer gewinnen möchte, hinterlässt bitte einen Kommentar, warum er oder sie das Buch gerne hätte. Das muss nichts Besonderes sein. Ich möchte nur gerne vermeiden, dass Kommentare auftauchen, die offensichtlich dadurch entstanden sind, das einmal von links nach rechts mit dem Gesicht über die Tastatur gerollt wurde. 🙂

Aus allen Kommentaren fische ich dann per Zufall einen heraus, so wie ich das bei den letzten Verlosungen auch gemacht habe. Die Verlosung läuft von heute, Montag den 30. Mai 2016 bis zum Freitag, den 03. Juni 2016 um 12:00 Uhr. Die Teilnahme ist ab 18 Jahren möglich und der Rechtsweg ist wie üblich ausgeschlossen.

Bei Fragen zum Buch oder sonstigen Angelegenheiten zur Verlosung freue ich mich immer über Kommentare und Nachrichten.

Vielen Glück allen!

Die Ziehung

Mittlerweile ist die Verlosung beendet. Wie immer habe ich, durch das folgende SQL-Statement, einen Kommentar herausgepickt.

SELECT 
      distinct comment_author, comment_author_email, comment_content
FROM
      wp_comments
INNER JOIN
      wp_posts
ON
      comment_post_ID = id
WHERE
      post_title = 'Gelesen + Verlosung: Spiele entwickeln mit Unity 5'
AND
      comment_approved = 1
AND 
      user_id = 0
AND
      comment_date
BETWEEN 
      '2016-05-30 01:00:00'
AND 
      '2016-06-03 12:00:00'
ORDER BY 
      RAND()
LIMIT
      1

Herausgekommen ist folgender Kommentar. Die E-Mail Adresse habe ich unkenntlich gemacht.

ziehung-gewinner-unity-5-buch-hanser

Herzlichen Glückwunsch an den Gewinner Andy. Ich habe gerade eine E-Mail rausgeschickt, da ich noch die Lieferadresse brauche.

Und natürlich gibt es auch in Zukunft weitere Verlosungen.

Johannes Renatus: Resharper Code Templates über Resharper Extension bereitstellen

Ich hoffe zumindest, dass jeder der mit Resharper arbeitet sich auch schon einmal die Resharper Code Templates angeschaut hat. Denn diese sind sehr einfach zu erstellen und können einem viel Arbeit abnehmen. Außerdem kann man die Templates auch exportieren und die wichtigsten Templates für das Team auf einem Share oder Webserver als NuGet Paket für […]

Alexander Schmidt: WPF und MVVM richtig einsetzen – Teil 3

Erläuterungen zu IDataErrorInfo

friends header

bloggers headline

links header

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