Sven Hubert: Inhalte der Zertifizierung Software Testing with Visual Studio 2012 (70-497)

Microsoft hat mit der Team Foundation Server 2012 Version die ALM Zertifizierung erweitert. Im letzten Blog Post zum MCSD ALM wurde auf die Inhalte der Zertifizierung Administering Visual Studio Team Foundation Server 2012 (70-496) eingegangen.

Dieser Blog Artikel geht auf die Inhalte der Zertifizierungsprüfung für das Testen von Software mit Visual Studio und dem Microsoft Test Manager ein und liefert einen Leitfaden zur Vorbereitung auf die Prüfung 70-497.

Hinweis: Die folgenden Themenbereiche können unter anderem Bestandteil der Zertifizierung sein, müssen aber nicht zwingend in dieser Form darin vorkommen.

Die Hauptgebiete der Prüfung, werden jeweils mit ca. 33 Prozent zum Gesamtumfang der Prüfung gewichtet:

  • Create and Configure Test Plans
  • Manage Test Cases
  • Manage Test Execution

Die nachfolgende Auflistung ist in Englisch gehalten. Generell sollten Sie auch die Zertifizierung in Englisch durchführen, da es sonst zu Missverständnissen in den Begrifflichkeiten des TFS geben kann.

Create and Configure Test Plans

Manage Test Cases

Manage Test Execution

Inhalte der Zertifizierung Software Testing with Visual Studio 2012 (70-497) is a post from: AIT Blog

Sven Hubert: Wartung und Versionierung von Process Templates

Den Workflow oder einzelne Prozessschritte in der Softwareentwicklung anzupassen, sind mit dem Team Foundation Server relativ leicht möglich. Man muss nur das Process Template anpassen und hat im Handumdrehen ein neues Feld zum Task hinzugefügt oder andere kleine Erweiterungen gemacht. Dabei wird der Nutzer auch durch verschiedene Tools, wie z.B. den Team Foundation Server Power Tools sehr gut unterstützt. Doch wie bewahrt man das Process Template vor unnötigen Anpassungen und wie sieht es eigentlich mit der Versionierung dieser Änderungen aus? Woher weiß man, welchem Team Project im TFS welches Process Template in welcher Version des Process Templates zugrunde liegt?

Oberstes Gebot bei der Bearbeitung von Process Templates ist die Verwendung der Versionskontrolle. Bevor man eine Anpassung macht, sollte man den Source Code eines Process Templates zunächst in seiner noch unveränderten Form in einem TFS Repository einchecken. Dies ermöglicht die Vorteile einer versionssicheren Dateiablage zu nutzen, um später Änderungen besser nachvollziehen oder Stände miteinander vergleichen zu können. Wenn man häufig Anpassungen der Art macht, dann ergibt sich in der Versionskontrolle in regelrechtes Sammelsurium an Process Templates (siehe Abbildung 1).

Abbildung 1: Sammelsurium an Process Templates

Abbildung 1: Sammelsurium an Process Templates

Damit hat man einen sehr wichtigen Grundstein für die Weiterentwicklung gelegt, auf dem man stabil und verlässlich weiter an seinem Template arbeiten kann. Dies ist jedoch nur der erste Schritt. Direkt als nächstes ist es wichtig, ein haltbares Versionierungsschema zu implementieren.

Nachdem ein neues Team Project auf Basis eines bestimmten Process Templates im Team Foundation Server erstellt wurde, kann man nämlich nicht mehr so einfach herausfinden, welches Process Template beim Anlegen des Team Projects verwendet wurde. Mit der Version 2012 des Team Foundation Servers hat Microsoft hier nachgebessert. Die Datei Classification.xml des Process Templates ist in der Lage eigene Properties aufzunehmen.

Genau dieses Feature (übrigens auch schon in TFS 2010 verfügbar) hat Microsoft nun erstmals selbst genutzt, um ein Property namens “Process Template” einzufügen (siehe dazu Abbildung 2). In dem Screenshot ist die Datei Classification.xml des von Microsoft ausgelieferten Process Templates Microsoft Visual Studio Scrum 2.2 zu sehen. Die in Zeile 25 beginnende Sektion properties gab es bereits vor dem Team Foundation Server 2012. Nun hat Microsoft diese jedoch selbst genutzt, um Versionsinformationen zu hinterlegen. Diese werden beim Erstellen eines neuen Team Projects mit in der TFS Datenbank gespeichert und sind somit später abrufbar (später mehr dazu).

 

Abbildung 2: Classification.xml des Scrum 2.2 Templates

Abbildung 2: Classification.xml des Scrum 2.2 Templates

An dieser Stelle kann man nun ansetzen und auf die gleiche Weise weitere Eigenschaften bekanntmachen. Zwei zusätzliche Informationen, die sich als nützlich erwiesen haben, sind die Versionsnummer, unter der das Template initial verwendet wurde sowie ein Verweis auf das Process Template, welches als Basis für die eigene Weiterentwicklung gedient hat. Die konkrete Vergabe der Versionsnummer kann natürlich frei gewählt werden. In dem hier gezeigten Beispiel ist das AIT-Versionsnummernschema zum Einsatz gekommen. Ein möglicher Aufbau der Datei Classification.xml nach diesem Schema ist in Abbildung 3 dargestellt.

Abbildung 3: Classification.xml eines angepassten Process Templates

Abbildung 3: Classification.xml eines angepassten Process Templates

Wie bereits angekündigt, ist es ein Leichtes, diese Informationen wieder aus einem existierenden Team Project auszulesen. Dafür gibt es verschiedene Möglichkeiten. Man kann sich z.B. ein kleines Tool schreiben, welches über die TFS API diese Informationen zur Verfügung stellt. Eine Alternative ohne die TFS API ist der Zugriff auf die TFS Datenbank mit einem einfachen Select-Statement.

SELECT [tbl_projects].[project_id]
  , [tbl_projects].[project_name]
  , [tbl_project_properties].[name]
  , [tbl_project_properties].[value] 
FROM [tbl_projects]
INNER JOIN [tbl_project_properties]
 ON [tbl_projects].[project_id] = [tbl_project_properties].project_id
WHERE [tbl_projects].[project_name] like 'AIT.Scrum%'

Diese Abfrage kann einfach wiederverwendet werden. Man muss lediglich den Namen des Team Projects in der Where-Clause austauschen. Abbildung 4 zeigt das Ergebnis der Abfrage.

Abbildung 4: Ergebnis der SQL-Abfrage

Abbildung 4: Ergebnis der SQL-Abfrage

Nachdem der Quellcode des Process Templates nun unter vollständiger Kontrolle der Quellcodeverwaltung ist und das Process Template auch noch ein paar Versionsinformationen erhalten hat, kann man den nächsten Schritt in der Weiterentwicklung erschließen: Branch-Struktur der Process Templates.

Die Tatsache, dass der Source Code durch die vorher beschriebenen Schritte sowieso im Source Control des TFS verfügbar ist, kann nun noch durch Verwendung von Branches ausgenutzt werden. Das Elternelement eines Branch-Baums ist dabei stets das vom Hersteller ausgelieferte Process Template. In dem Beispiel des Scrum Templates von Microsoft ist Microsoft Visual Studio Scrum 2.2 also das Wurzelelement eines Branch-Baums (siehe Abbildung 5).

Abbildung 5: Branch-Hierarchie

Abbildung 5: Branch-Hierarchie

In dem in der Abbildung dargestellten Beispiel gibt es im Unternehmen zwei verschiedene Business Units, die für die Entwicklung verschiedener Produktlinien verantwortlich sind. Dabei verwenden sie unterschiedliche Prozesse, was den Einsatz verschiedener Process Templates im TFS nach sich zieht. Die Entwicklung der beiden Produktlinien B.I und B.II ist bzgl. der Zustände der einzelnen Work Items jedoch gleich. Sie unterscheiden sich nur auf Feldebene der einzelnen Work Item Typen. Deshalb ist es sinnvoll, für diese Process Templates noch einmal einen gemeinsamen Knoten in der Branch-Hierarchie abzubilden, hier: Business Unit B.

In der Praxis hat sich gezeigt, dass es nur schwer möglich ist, Anpassungen, die innerhalb eines Process Templates entstanden sind, z.B. bei Product Line B.II, durch Reverse Integration auf andere Zweige zu verteilen. Jedoch dokumentiert die Branch-Struktur hervorragend die Entstehung sowie die Beziehungen der einzelnen Anpassungen. Außerdem kann man Änderungen allgemeiner Art relativ gut durch Forward Integration verteilen.

Hierbei ist es wie in der Softwareentwicklung entscheidend, dass die Branch-Hierarchie sorgfältig definiert wurde. In dem Beispiel aus Abbildung 5 ist es durchaus denkbar, zwischen dem Wurzelknoten und den beiden Business Units noch einen gemeinsamen Zwischenknoten einzufügen, um Änderungen, die für alle Templates zutreffen, an einer Stelle implementieren zu können. Ein Beispiel dafür kann ein Feld sein, welches in einem bestimmten Work Item Type (z.B. Task) in allen Templates vorhanden sein soll.

Wenn man diese Forward Integration zum Verteilen von Neuerungen weiter durchdenkt, kommt man noch zu einem weiteren Knackpunkt: die Formatierung des XML-Codes. Wenn man Process Template Anpassungen im großen Stil macht, kann es sinnvoll sein, sich auf bestimmte Richtlinien zur XML-Formatierung zu einigen, um Vergleichs- und Merge-Operationen zu vereinfachen oder überhaupt erst sinnvoll zu ermöglichen.

Deutlich wird dies durch folgendes Beispiel: Einem Work Item Type (z.B. Product Backlog Item des Scrum Templates) soll ein neues Feld hinzugefügt werden. Dafür sind mindestens zwei Stellen zu bearbeiten. Zunächst muss das neue Feld innerhalb des XML-Tags Fields bekannt gemacht werden. Hier kommt die erste Herausforderung, denn an welcher Stelle innerhalb der genannten XML-Sektion die Felddefinition eingefügt wird, ist aus Sicht des TFS irrelevant. Jedoch ist es für einen Vergleich zweier Dateien unabdingbar, dass man sich auf eine einheitliche Vorgehensweise geeinigt hat. Dies könnte z.B. so aussehen, dass neue Felder stets unten in dem Bereich Fields in alphabetischer Reihenfolge angefügt werden. Eine Alternative ist, die Felddefinitionen so zu sortieren, dass sie mit der Reihenfolge der Elemente an der Oberfläche übereinstimmen.

Die zweite Schwierigkeit in diesem Umfeld ist, dass die XML-Formatierung einheitlich ist. Darunter fallen Punkte wie “Tabulator oder Leerzeichen zum Einrücken” oder die Verwendung von Kommentaren. Auch hier wird die Weiterentwicklung durch eine Vereinheitlichung erleichert.

Wie den vorherigen Erläuterungen zu entnehmen ist, entpuppt sich die nachhaltige Pflege und Weiterentwicklung von Prozess Templates als etwas komplexer als man vielleicht auf den ersten Blick meint. Deshalb ist es umso wichtiger auch die Änderungswünsche der Nutzer kritisch zu hinterfragen und wie in anderen Projekten ein sorgfältiges Requirements Management zu leben. Eine Möglichkeit, die Process Tempaltes stabiler zu halten, ist die Verwendung der Tags, die seit dem Update 2 (TFS 2012.2) zur Verfügung stehen. Damit kann die Anzahl der Änderungen deutlich reduziert werden. Denn alle Anfragen nach weiteren Feldern, um zusätzliche Metainformationen zu speichern, um dann beispielsweise nach weiteren Kriterien auszuwerten, können nun von den Benutzern selbst gelöst werden.

Fazit

Process Template Customization ist sehr ähnlich zu einem Softwareentwicklungsprojekt. Es gilt zunächst, die Anforderungen gründlich zu sondieren. Darüber hinaus müssen gewisse Qualitätskriterien eingehalten werden. Anpassungen des Process Templates müssen auch getestet werden. Schließlich müssen Versionen oder Releases definiert werden, die geordnet veröffentlicht und installiert werden.

Wartung und Versionierung von Process Templates is a post from: AIT Blog

Martin Hey: SetWindowHookEx - cool oder nur Fingerübung?

Die Anforderung ist recht schnell erklärt: Erkenne, wann ein Fenster einer Anwendung maximiert, minimiert oder wiederhergestellt wird. "Das kann doch so schwer nicht sein" denkt man sich da, schließlich wirft Windows ja nur so mit Nachrichten um sich, die man einfach nur abfangen muss. Die Windows-API ist dein Freund. Ok, ganz so einfach ist es dann doch nicht, sonst bräuchte dieser Blogpost ja nicht geschrieben werden.

Damit das Fensterhandling und auch so ziemlich alles andere in Windows funktioniert, werden Nachrichten an Fenster gesendet. Zumeist macht Windows das selbst (z.B. Fenster 358: Maximiere dich"). Kommt diese Nachricht am Fenster an, gibt es dort eine Kette von "Abonnenten" - die hook chain. Und in diese Kette kann man eigene Funktionen eingliedern lassen, die dann Teil dieser Kette werden.

Mit diesem Wissen ist die relevante Methode ist auch recht schnell gefunden: SetWindowsHookEx in der user32.dll. Damit gliedert man eine Funktion in die hook chain ein und bekommt dabei einen Handle für den nächsten Teilnehmer der Kette - also den an den die Nachricht dann geschickt werden muss, wenn meine Bearbeitung fertig ist.

Eine gute Anlaufstelle für Fragen, wenn es um die Syntax oder die Verwendung geht, ist entweder die Windows API-Dokumentation in der MSDN - wo C-Syntax verwendet wird und die Parameter inzwischen auch recht ausführlich beschrieben sind - oder pinvoke.net - wo es auch Beispiele zur Umsetzung in C# oder VB.NET gibt. Dort lernt man dann auch schnell, dass man einige Voraussetzungen schaffen muss, um diese Funktionen verwenden zu können.

 

Wie implementiert man den Hook?

Zunächst werden die Methoden definiert, die importiert werden sollen: Mit SetWindowHookEx kann die Methode in die Kette eingereiht werden. Und natürlich benötigt man dann auch noch UnhookWindowsHookEx, um diesen Eintrag später auch wieder entfernen zu können. Des weiteren habe ich schon erwähnt, dass man dafür Sorge tragen muss, den Folgeeintrag in der Kette aufzurufen, deshalb wird auch noch CallNextHookEx benötigt.

[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int code, HookDelegate func, IntPtr hInstance, uint threadId);

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

Im Import von SetWindowsHookEx wird im zweiten Parameter auf einen Delegate verwiesen. Dieser muss ebenfalls definiert werden:

public delegate int HookDelegate(int code, IntPtr wParam, IntPtr lParam);

Und man sieht, dass SetWindowsHookEx eine ThreadId erwartet. Damit die Funktion aber nun mit einen Fenster-Handle verwendet werden kann, wird nun noch GetWindowThreadProcessId benötigt, um dieses Mapping durchführen zu können. aber das ist nur Makulatur und für die eigentliche Funktionalität irrelevant:

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);

So weit, so gut. Nun sieht man in den Deklarationen aber auch, dass sehr viele int-Werte verwendet werden. Für Menschen sind Zahlen immer etwas schwierig zu lesen - aus diesem Grund werden noch ein paar Enumerationen deklariert. 

Der Hooktype definiert, welche Art von Nachricht interessant sind. Danach richtet sich im späteren Verlauf, wie die Informationen der Nachricht interpretiert werden müssen:

public enum HookType : int
{
    WH_JOURNALRECORD = 0,
    WH_JOURNALPLAYBACK = 1,
    WH_KEYBOARD = 2,
    WH_GETMESSAGE = 3,
    WH_CALLWNDPROC = 4,
    WH_CBT = 5,
    WH_SYSMSGFILTER = 6,
    WH_MOUSE = 7,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_FOREGROUNDIDLE = 11,
    WH_CALLWNDPROCRET = 12,
}

Für die gewünschte Funktionalität wird WH_CallWndProcRet von Interesse sein, da diese Art von Nachricht dann aufgerufen wird, wenn eine Fensterfunktion fertig ausgeführt ist. Die Nachricht dieses Nachrichtentyps lässt sich mit folgendem Struct darstellen:

[StructLayout(LayoutKind.Sequential)]
public struct CwpRetStruct
{
    public IntPtr lResult;
    public IntPtr lParam;
    public IntPtr wParam;
    public uint message;
    public IntPtr hwnd;
};

Dabei wird dann im Feld message stehen, welche Nachricht geschickt wurde - im gezeigten Fall werden nur Systemcommands von Interesse sein:

public enum WindowsMessages : uint
{
    WM_SYSCOMMAND = 0x0112
}

Und im Feld wParam wird stehen, welche genaue Ausprägung dieses Command hat:

public enum SystemCommands : int
{
    SC_SIZE = 0xF000,
    SC_MOVE = 0xF010,
    SC_MINIMIZE = 0xF020,
    SC_MAXIMIZE = 0xF030,
    SC_NEXTWINDOW = 0xF040,
    SC_PREVWINDOW = 0xF050,
    SC_CLOSE = 0xF060,
    SC_VSCROLL = 0xF070,
    SC_HSCROLL = 0xF080,
    SC_MOUSEMENU = 0xF090,
    SC_KEYMENU = 0xF100,
    SC_ARRANGE = 0xF110,
    SC_RESTORE = 0xF120,
    SC_TASKLIST = 0xF130,
    SC_SCREENSAVE = 0xF140,
    SC_HOTKEY = 0xF150,
    SC_DEFAULT = 0xF160,
    SC_MONITORPOWER = 0xF170,
    SC_CONTEXTHELP = 0xF180,
    SC_SEPARATOR = 0xF00F,

    SCF_ISSECURE = 0x00000001,

    SC_ICON = SC_MINIMIZE,
    SC_ZOOM = SC_MAXIMIZE,
}

Nun aber genug der Vorbereitungen: Die Funktionalität muss auch noch implementiert werden. Der Rumpf meiner Klasse sieht nun wie folgt aus:

public class WindowMessageInterceptor : IDisposable
{
    private IntPtr nextHookPtr;

    private HookDelegate callbackDelegate;

    public WindowMessageInterceptor(IntPtr hWnd)
    {
    }

    public void Dispose()
    {
    }
}

Der Konstruktor erwartet ein Fensterhandle, es gibt Membervariablen für die Delegateinstanz und den Pointer auf den Folgeeintrag in der hook chain, im Konstruktor wird der Hook später gesetzt werden und im Dispose wird der Hook wieder entfernt werden.

Der Konstruktor sieht mit diesem Wissen auch recht unspektakulär aus:

public WindowMessageInterceptor(IntPtr hWnd)
{
    // determine ThreadId for specified Window
    var threadId = GetWindowThreadProcessId(hWnd, IntPtr.Zero);

    // initialize the callback delegate
    this.callbackDelegate = new HookDelegate(this.HookCallbackFunction);

    // setup a window message hook and add it to hook chain
    this.nextHookPtr = SetWindowsHookEx((int)HookType.WH_CALLWNDPROCRET, this.callbackDelegate, IntPtr.Zero, threadId);

    if (this.nextHookPtr == IntPtr.Zero)
    {
        throw new Exception("unable to apply hook");
    }
}

und ebenso das Dispose:

public void Dispose()
{
    if (this.nextHookPtr == IntPtr.Zero)
    {
        return;
    }

    UnhookWindowsHookEx(this.nextHookPtr);
    this.nextHookPtr = IntPtr.Zero;
}

Spannend ist die Callback-Funktion:

private int HookCallbackFunction(int code, IntPtr wParam, IntPtr lParam)
{
    // If code is less than zero, the hook procedure must return the value returned by CallNextHookEx.
    if (code < 0)
    {
        return CallNextHookEx(this.nextHookPtr, code, wParam, lParam);
    }

    // otherwise do all the things and call NextHookEx afterwards
    // convert the lparam to our struct
    var message = (CwpRetStruct)Marshal.PtrToStructure(lParam, typeof(CwpRetStruct));

    // evaluate the message
    if (message.message == (uint)WindowsMessages.WM_SYSCOMMAND)
    {
        Console.Write("syscommand detected: ");

        switch (message.wParam.ToInt32())
        {
            case (int)SystemCommands.SC_RESTORE:
                Debug.WriteLine("window restored from maximized state");
                break;
            case (int)SystemCommands.SC_MINIMIZE:
                Debug.WriteLine("window minimized");
                break;
            case (int)SystemCommands.SC_MAXIMIZE:
                Debug.WriteLine("window maximized");
                break;
            default:
                Debug.WriteLine("not important");
                break;
        }
    }

    return CallNextHookEx(this.nextHookPtr, code, wParam, lParam);
}

Was passiert hier? 

Zunächst wird geprüft, ob der Code größer als 0 ist. Laut API-Dokumentation ist die Nachricht nur dann auch für diese Methode gedacht. Im Anschluss daran muss die Nachricht ausgewertet werden. Damit das passieren kann, bietet das Framework die Methode PtrToStructure. Damit kann der lParam-Wert des Callbacks, in dem sich die Informationen befinden, in das Nachrichtenformat konvertiert werden. Und aus dieser Nachricht interessiert nun, wie man der API entnehmen kann der wParam-Wert.

Im Anschluss wird der Hook an den Folgeempfänger weitergeleitet.

 

Der Test

Für den Test gibt es einen weiteren Konstruktor, der als ThreadId einfach die ThreadId der aktuellen Applikation übergibt:

public WindowMessageInterceptor()
{
    // initialize the callback delegate
    this.callbackDelegate = new HookDelegate(this.HookCallbackFunction);

    // setup a window message hook and add it to hook chain
    this.nextHookPtr = SetWindowsHookEx((int)HookType.WH_CALLWNDPROCRET, this.callbackDelegate, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());

    if (this.nextHookPtr == IntPtr.Zero)
    {
        throw new Exception("unable to apply hook");
    }
}

Und das funktioniert auch ganz gut: Die entsprechenden Nachrichten werden angezeigt. Und auch wenn man das Fensterhandle der aktuellen Anwendung übergibt, funktioniert alles super

Aber.....

Versucht man das Ganze nun mit einem fremden Fensterhandle, so schlägt das Setzen des Hooks fehl. Aber warum?

Auch hier hilft die Dokumentation weiter. Sinngemäß steht dort: Hooks können innerhalb der eigenen Anwendung gesetzt werden, indem als Modul-Handle (Parameter 3) IntPtr.Zero übergeben wird und dann im vierten Parameter die ThreadId. Um den Hook auf fremde Fenster zu setzen, muss als ModulId die ModulId des fremden Programms angegeben werden, der Callback muss in einer Dll sein und das Fremde Programm muss diese Dll geladen haben. Und genau das ist der Knackpunkt, denn hier greifen Sicherheitsmechanismen von .NET, die genau das verhindern.

Resümee

Für den gezeigten Anwendungsfall kommt man mit SetWindowsHookEx nicht weiter, da nur die aktuelle Anwendung abgefragt werden kann. Und das geht mit Bordmitteln wesentlich einfacher, indem man Events auf dem Hauptfenster abonniert - in WPF wäre das das WindowStateChanged-Event.

Thomas Schissler: TFS Incremental build und writeable files

Der TFS Build geht standardmäßig so vor, dass er vor einem Build, alle Dateien sauber löscht und dann den kompletten Workspace neu aus der Versionsverwaltung holt. Ein solcher “Clean Build” birgt natürlich das geringste Risiko, dass veraltete Dateien in den Build einfließen oder dass der Build Dateien benutzt die gar nicht mehr in der versionsverwaltung enthalten sind. Aber gerade bei größeren Projekten ist das natürlich auch sehr ineffizient. deshalb kann man im TFS Build einstellen, wie er sich verhalten soll.

In den Build Process Parametern gibt es eine Einstellung dafür.

image

Dieser Parameter hat 3 mögliche Einstellungen:

  1. All – Mit dieser Einstellung werden sowohl der Source Code all auch alle Outputs des Builds gelöscht (Clean Build). Dies ist die Default-Einstellung
  2. Outputs – Der Build löscht die Outputs, nicht aber die Sourcen. Für die Sourcen wird ein get Latest ausgeführt, d.h. es werden nur geänderte Dateien vom TFS heruntergeladen
  3. None – Sowohl Outputs als auch Sourcen bleiben erhalten. Nach einem Get Latest wird ein Build ausgeführt und dabei nur Projekte gebaut bei denen sich die SOurcen bzw. die Referenzen geändert haben

So weit so gut. Ich hatte einen Build auf “Outputs” gestellt und dann folgenden Fehler bekommen:

Warning C:\Builds\101\Projekt\artiso_Working1_CI\Sources\Solutions\artisoSolutions\WCH_Diff\NoDeploy.testsettings - Unable to perform the delete operation because the file already exists locally

Völlig unlogisch, dass eine Datei nicht gelöscht werden kann, weil sie schon existiert, aber nun gut. Die Ursache war dann auch schnell gefunden. Um die Version in der AssemblyInfo.cs während des Builds zu ändern, hebe ich den Schreibschutz dieser Dateien auf. Und der Get hat nun ein problem, wenn da Dateien rumliegen die keinen Schreibschutz haben, da diese ja geändert sein könnten und er die nicht einfach überschreibt. Es gibt aber eine kleine Einstellung im Workflow mit der man dieses Verhalten anpassen kann:

Man sucht die Gte Workspace Activity im Workflow

image

Dann stellt man in den Properties die GetOptions auf “Overwrite”

image

Damit überschreibt der Build beim Get nun die Dateien ohne Schreibschutz-Attribut und der Build läuft problemlos durch – und das nun auch deutlich schneller als zuvor.

 

 

 

>>

ppedv Team Blog: mobile Websites SEO per Sitemap

Ein recht junges Problem mobiler ASP.NET Websites ist die Indizierung durch Suchmaschinen wie BING oder Google. Persönlich mag ich den Begriff SEO (Search Engine Optimization) nicht, da er vorgaukelt, das man Websites für Google optimieren muss. Sollte man eigentlich nicht. Websites sollten optimal für den Benutzer sein. Der Job von Suchmaschinen wiederum ist es optimale Ergebnisse passend zu den Bedürfnissen des Users zu bringen.

In diesem Fall ist es aber anders. Parallel zu www.ppedv.at Website gibt es eine Site die fokussiert auf mobile Nutzung ist http://m.ppedv.at. Inhaltlich sehr unterschiedlich. Ruft man nun mit einem Browser die Website auf, sieht man quasi nichts. Auch der Spider (bot) der Suchmaschine sieht nichts und kann damit auch keinen Links folgen.

Laut google sollen mobile Sitemaps helfen. In den Webmaster Tools kann man sein Begehr schon mal anmelden.

image

Ich formulier das so, weil die Position und Verhalten von Google Königlich und ich Untertan (unterirdisch) bin.

In meinem Fall lasse ich nun so eine mobile Sitemap per Code generieren um immer aktuell zu sein. Entsprechende online und offline Sitemap Generatoren bieten das nicht.

Für die fixen Hyperlink wurde eine XML Vorlage angelegt. Darin kann man auch die XML Struktur gut herauslesen.

   1:  <?xml version="1.0" encoding="UTF-8"?>
   2:  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
   3:          xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0">
   4:    <url>
   5:      <loc>http://m.ppedv.at/</loc>
   6:      <lastmod>2013-05-14</lastmod>
   7:      <changefreq>monthly</changefreq>
   8:      <priority>0.5</priority>
   9:      <mobile:mobile/>
  10:    </url>
  11:    <url>
  12:      <loc>http://m.ppedv.at/S/11</loc>
  13:      <lastmod>2013-05-14</lastmod>
  14:      <changefreq>monthly</changefreq>
  15:      <priority>0.5</priority>
  16:      <mobile:mobile/>
  17:    </url>
  18:    <url>
  19:      <loc>http://m.ppedv.at/S/2,12,14,19</loc>
  20:      <lastmod>2013-05-14</lastmod>
  21:      <changefreq>monthly</changefreq>
  22:      <priority>0.5</priority>
  23:      <mobile:mobile/>
  24:    </url>
  25:    <url>
  26:      <loc>http://m.ppedv.at/S/5,6</loc>
  27:      <lastmod>2013-05-14</lastmod>
  28:      <changefreq>monthly</changefreq>
  29:      <priority>0.5</priority>
  30:      <mobile:mobile/>
  31:    </url>
  32:    <url>
  33:      <loc>http://m.ppedv.at/kontakt</loc>
  34:      <lastmod>2013-05-14</lastmod>
  35:      <changefreq>monthly</changefreq>
  36:      <priority>0.5</priority>
  37:      <mobile:mobile/>
  38:    </url>
  39:    <url>
  40:      <loc>http://m.ppedv.at/S/4,21</loc>
  41:      <lastmod>2013-05-14</lastmod>
  42:      <changefreq>monthly</changefreq>
  43:      <priority>0.5</priority>
  44:      <mobile:mobile/>
  45:    </url>
  46:  </urlset>

Dann werden per VB.NET und XML Literals ( eine wunderbare Funktion die es in C# nicht gibt) neue Nodes anhand einer Tabelle hinzugefügt. Das ganze in einer HTML entkernten ASPX Seite.

   1:  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   2:          Dim x As XDocument = XDocument.Load(Server.MapPath("~/app_data/sitemap.xml"))
   3:          x.AddAnnotation(SaveOptions.OmitDuplicateNamespaces)
   4:   
   5:   
   6:          Dim pp As ppcompanyEntities = New ppcompanyEntities
   7:         
   8:          Dim query = pp.SEMINARE.Where(Function(s) s.isActive )
   9:          For Each s In query
  10:              Dim n = <url>
  11:                          <loc>http://m.ppedv.at/d/<%= s.SEID %></loc>
  12:                          <lastmod><%= Date.Now.ToString("yyyy-MM-dd") %></lastmod>
  13:                          <changefreq>daily</changefreq>
  14:                          <priority>0.5</priority>
  15:                          <mobile:mobile/>
  16:                      </url>
  17:              x.<urlset>.First.Add(n)
  18:          Next
  19:   
  20:   
  21:          Response.Write(x.ToString)
  22:   
  23:   
  24:      End Sub

Allerdings sind im urlset zwei Namensräume deklariert. Um den Code (hier speziell mobile: ) überhaupt kompilieren zu können braucht es passende Imports.

   1:  Imports <xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0">
   2:  Imports <xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

Danach werden diese XML Namensräume sozusagen doppelt und mehrfach aber bei jedem URL Element eingefügt. Zeile 3 verhindert dieses wiederum.

Dann bleibt nur noch abzuwarten, wann königliche Hoheit, mein Gnadenersuch um wohlwollende Aufnahme in den Index auch erhört.

Wer das komplette XML File benötigt, kann es natürlich unter http://m.ppedv.at/sitemap.xml abrufen.

Sven Hubert: Agiles Arbeiten im Team

Mit der Version 2012 hat Microsoft für den Team Foundation Server die Unterstützung für Teams hinzugefügt und die agilen Planungstools ins Web verlagert. Doch welchen Einfluss haben die Teams auf die Strukturierung von Work Items? Wie können Teams die agilen Planungstools effektiv nutzen?

Arbeiten im Team

In den bisherigen Versionen vom Team Foundation Server wurden über Work Item Areas und Iterations nur funktionale und zeitliche Aspekte abgebildet. Mit der 2012er Version vom Team Foundation Server rücken die Organisationsstrukturen im Unternehmen mehr in den Fokus. Neben funktionalen Aspekten müssen nun auch organisatorische Aspekte abgebildet werden.

Hierzu sollte die Verwendung der Work Item Areas angepasst werden, um die Arbeit in Teams zu vereinfachen. Der Wurzelknoten für die Work Item Areas entspricht der Firma und bildet die höchste organisatorische Einheit. Unterhalb des Wurzelknotens werden Unterknoten für jede Organisationseinheit bzw. Produktgruppe ein Team angelegt. Unterhalb von jedem dieser Teams  können weitere Teams für Untereinheiten bzw. Teilprodukte eingefügt werden. Hierüber werden die organisatorischen Aspekte abgebildet. Unterhalb der Teams erfolgt eine weitere Untergliederung im Bezug auf die funktionalen Aspekte der Produkte. Hierzu werden weitere Unterknoten für jeden Funktionsbereich angelegt. Die Unterteilung bzgl. der fachspezifischen Aspekte sollte hierbei für alle Teams einer Gruppe idealerweise gleich sein.

Am Beispiel der AIT Netfactory lässt sich dies wie folgt umsetzen: Unter dem Firmennamen als Wurzelknoten (AIT) befinden sich die Unterknoten für die Produkt Teams (Netfactory Team, Dependency Management Team etc.). In Abbildung 1 ist hier nur die Unterstruktur für das Netfactory Team dargestellt. Produktübergreifende Teams – wie zum Beispiel ein Plattform Team – sind auf der gleichen Ebene wie die Produkt Teams anzulegen. Das Netfactory Team unterteilt sich in zwei weitere Unterteams für das Front- und Backend (Netfactory Backend Team und Netfactory Frontend Team). Innerhalb der Teams werden für die funktionalen Bereiche Alarming, Database, Reporting, Application Framework und Trending nochmals Unterknoten angelegt.

Produkt- und Team-spezifische Work Item Areas

Abbildung 1 – Produkt- und Team-spezifische Work Item Areas

Über die Work Item Iterations erfolgt klassischer Weise eine zeitliche Unterteilung und die Abbildung von Iterationen bzw. Sprints. Bei der Arbeit mit Teams und agilen Planungstools ändern sich hier zwei Aspekte: Die zeitliche Dimension eines Sprints wird mit dem TFS 2012 nun über ein Start- und Enddatum spezifiziert und zusätzlich zu den zeitbezogenen Iterationen wird eine Backlog Iteration angelegt, in der die noch nicht geplanten Anforderungen gehalten werde.

Am Beispiel der AIT Netfactory ergibt sich die folgende Work Item Iteration Struktur: Zusätzlich zum Backlog gibt es eine Release 1.0 und Release 2.0 Iteration. Für das Release 1.0 erfolgt eine weitere Unterteilung in Sprint 1, Sprint 2 und Sprint 3, mit definierten Zyklen, die in Form von Start- und Enddatum dargestellt werden (Siehe Abbildung 2).

Work Item Iterationen

Abbildung 2 – Work Item Iterationen

Im Anschluss werden nach dem Anlegen der Teams für jedes Team die nach ihm benannten Work Item Area Knoten inkl. aller Unterknoten zugewiesen, die für das Team gültigen Sprints inkl. des Team Backlogs definiert und die Mitglieder dem Team zugeteilt.

Für das Team Netfactory Team ist dies die Work Item Area Netfactory Team inkl. aller Unterknoten und die Iteration Release 1.0 als Backlog Iteration mit den Sprints 1 bis 3 für die agile Planung.

Agiles Arbeiten mit den Planungstools

Beim agilen Arbeiten werden die Vorteile einer nach organisatorischen, funktionalen und zeitlichen Kriterien definierten und über Teams abgebildeten Struktur deutlich: (Entwickler-)Teams wird über das Taskboard die fokussierte Sicht auf ihre Aufgaben ermöglicht (siehe Abbildung 3 und 4). Gleichzeitig haben Projektmanager die Möglichkeit die aktuellen und zukünftigen Sprints teamübergreifend für ein Produkt zu planen und im Daily Stand-up den Status aller (Entwickler-)Teams über das Taskboard  darzustellen (siehe Abbildung 5).

Frontend Team

Abbildung 3 – Taskboard des Netfactory Frontend Teams

Backend Team

Abbildung 4 – Taskboard des Netfactory Backend Teams

Product Team

Abbildung 5 – Übergreifende Sicht auf alle Tasks im Netfactory Team während des Daily Stand-up Meetings

Fazit

Mit einer auf die organisatorischen Bedürfnisse eines Unternehmens angepassten Work Item Area und Iteration Struktur können mit dem Team Foundation Server sowohl für das Management eine allgemeine Übersicht zur Planung und zum aktuellen Ist-Zustand als auch für die Entwicklungsteams fokussierte Sichten auf die zu erledigenden Aufgaben zur Verfügung gestellt werden.

Agiles Arbeiten im Team is a post from: AIT Blog

codefest.at [MS]: Apps zu einem bestimmten Datum in den Windows Store veröffentlichen

Der Windows Store gibt Entwicklern die Möglichkeit, Apps nicht nur gleich nach der Zertifizierung sondern stattdessen auch zu einem bestimmten Datum zu veröffentlichen. Es gibt verschiedenste Gründe, warum man ein konkretes Veröffentlichungsdatum bei der App-Einreichung angeben würde.

Beispiele dafür können sein, dass man noch entsprechende Marketingaktivitäten für die App durchführen möchte und die Veröffentlichung entsprechend ankündigen will. Eine App, die von großem öffentlichen Interesse ist, wird zum Beispiel zeitgleich zur entsprechenden Medienpräsenz veröffentlicht werden.

Wenn Unternehmen Apps für bestimmte Arbeitsprozesse für Kunden entwickeln, ist es vielleicht nötig, die Kunden im Vorhinein zu verständigen oder vorzubereiten.

Es kann aber auch möglich sein, dass ich beispielsweise ein Datum als Zielvorgabe für meine App bekomme, aber im Vorhinein schon weiß, dass ich zu dem Zeitpunkt nicht verfügbar bin, weil ich in dieser Zeit bereits andere Termine habe. Da ich aber die Möglichkeit habe, Apps später zu einem bestimmten Datum in der Zukunft zu veröffentlichen, kann ich mir vorher einteilen, wann ich die App entwickle und einreiche und mich dann darauf verlassen, dass die App nach erfolgreicher Zertifizierung wirklich an dem Tag in dem Windows Store erscheint, den ich angebe.

Wie funktioniert das Ganze? Ich gehe, davon aus, dass die allgemeine Prozedur, wie Apps in den Windows Store eingereicht werden, bekannt ist. Es gibt hier in Codefest eine gute Anleitung zum Einreichen von Apps in den Windows Store.

Wir gehen zunächst in unser Dashboard vom Windows Store, nachdem wir uns auf dev.windows.com mit unserem Microsoft Account eingeloggt haben. Dort gibt es in der linken Spalten den Link Submit an App, wo der Einreichungsprozess für die App beginnt.

image

In diesem Prozess reservieren und speichern wir uns den Namen für unsere App.

Der zweite Schritt bei der Einreichung sind die Verkaufsdetails und in diesem Schritt können wir auch unser Veröffentlichungsdatum festlegen. Hier würde man zuerst den Preis für die App festlegen, dann die regionalen Märkte, in denen die App im Store erscheinen soll und letztendlich kommt der Punkt Release Date, bei dem ich mein gewünschtes Veröffentlichungsdatum angeben kann.

Das heißt, wenn ich beispielsweise möchte, dass meine App am 1. Juli 2013 erscheint, dann gebe ich in dem Punkt Release Date dieses Datum an.

 

StorePublishDate

Da bei mir die Anzeigesprache im Store US-amerikanisch ist, wird bei mir auch der Monat an erster Stelle angegeben. Aber es wird im Feld explizit angegeben, dass es sich um das Monat-Feld bzw. Tag-Feld handelt.

Der Rest des Einreich-Prozesses funktioniert wie gehabt. Nachdem ich alle Punkte der Einreichung ausgefüllt, mein Package hochgeladen und auf Submit App to Store geklickt habe, ist mein Teil der Einreichung beendet. Nun werden verschiedene Tests mit der App durchgeführt und sobald sie alle Tests bestanden hat, wird sie erfolgreich zertifiziert.

Meine App wird nach erfolgreicher Zertifizierung aber nicht in den Store erscheinen, sondern erst zu dem Datum, das ich bei Release Date angegeben habe.

Beachten sollte man noch, dass nachdem der Submit Button betätigt wurde, der Entwickler nicht mehr auf den Zertifizierungs- und Veröffentlichungsprozess Einfluss nehmen kann. Wenn man daher im Nachhinein das Datum ändern möchte, so müsste man die App erneut als zweite Version hochladen und mit einem anderem Release Date einreichen.

Alles in allem ist dieses Feature des Windows Store jedoch eine recht praktische Sache, da es dem Entwickler der App ermöglicht wird, auf andere Umstände Rücksicht zu nehmen, wenn die App veröffentlicht wird.

Christian Binder [MS]: Interessante Trainings zu Visual Studio 2012 in der Microsoft Virtual Academy

Software Testing with Visual Studio 2012 (exam 70-497) Jump Start

Live Event Details
May 28, 2013
9:00am - 5:00pm (PDT)

Link: https://www.microsoftvirtualacademy.com/liveevents/software-testing-with-visual-studio-2012-jump-start?CR_CC=200211930

Administering Visual Studio Team Foundation Server 2012 (exam 70-496) Jump Start

Live Event Details
May 29, 2013
9:00am - 5:00pm (PDT)

Link: https://www.microsoftvirtualacademy.com/liveevents/administering-visual-studio-team-foundation-server-2012-jump-start

Applying ALM with Visual Studio 2012 (exam 70-498) Jump Start

On demand Jump Start training
Link: https://www.microsoftvirtualacademy.com/training-courses/applying-alm-w-visual-studio-2012-jump-start

Building Business Apps with Visual Studio Lightswitch

https://www.microsoftvirtualacademy.com/training-courses/building-business-apps-with-visual-studio-lightswitch

ppedv Team Blog: Wissensmanagement - Wissensidentifikation

Einige wichtige Themen meiner Bachelorarbeit sind die Wissensidentifikation und die Wissens(ver)teilung.

Hier ein Einblick in das Thema der Wissensidentifikation.

Heutzutage fällt es vielen Unternehmen schwer, den Überblick über sowohl interne, wie auch externe Informationen und Daten zu behalten, was zu mangelnder Transparenz und in weiterer Folge zu Ineffizienzen und falschen Entscheidungen führen kann. Die Wissensidentifikation bezieht sich vor allem auf die Analyse und Definition des Wissensumfeldes des Unternehmens, um interne und externe Transparenz zu wahren beziehungsweise zu schaffen und die Mitarbeiter des Unternehmens dadurch in ihren Suchaktivitäten zu unterstützen. (Probst, et al., 2006)

Aspekte beziehungsweise Themen im Bereich der Wissensidentifikation in einem Unternehmen beziehen sich auf:

  • Die interne Intransparenz – Oft vorzufinden in multinationalen Großunternehmen, welches häufig durch die Dezentralisierung verursacht wird.
  • Den Umgang mit der Informationsflut – Die Menge an Informationen zwingt zur Selektierung, wobei aber oft das gerade benötigte Wissen nicht beziehungsweise schwer auffindbar ist.
  • Den Grad der angestrebten Transparenz – Absolute Transparenz ist der Erfahrung nach nicht umsetzbar und häufig auch nicht erstrebenswert. Vielmehr benötigt ein Unternehmen angemessene Transparenz über kritische Wissensfelder, um Kompetenzen stärken, beziehungsweise neue aufbauen zu können.
  • Der personellen und strukturellen Transparenz – Die personelle Transparenz bezieht sich dabei auf das Erlangen eines Bewusstseins über die Fähigkeiten des Unternehmens, beziehungsweise der eigenen Mitarbeiter. Ebenfalls wichtig ist die Transparenz über das gemeinsame (kollektive) Wissen. Hier geht es darum, interne Spielregeln über Prozesse der Wissensteilung und Kommunikationsnetzwerke des Datenaustausches aufzudecken.
  • Der Beleuchtung des Wissensumfeldes des Unternehmens – Hier ist die Devise, über den Tellerrand hinauszuschauen. Chancen der Kooperation außerhalb des Unternehmens, in Form von externen Experten oder Netzwerken, sollten zum Wissensimport genutzt werden. Des Weiteren kann das Unternehmen dadurch eigene Wissenslücken und Defizite aufdecken beziehungsweise sichtbar machen.
  • Dem externen und internen Benchmarking – Auch die Methoden des externen Benchmarkings geben dem Unternehmen die Möglichkeit, Wissens- und Fähigkeitslücken aufzudecken. Das interne Benchmarking stellt des Weiteren eine der Voraussetzungen für den Austausch von Best-Practices dar.
  • Dem Bewusstsein, beziehungsweise dem Eingeständnis des eigenen Nicht-Wissens – Dies bildet die Grundlage, beziehungsweise den ersten Schritt, um einen Lernprozess anzustoßen und bestehende Wissens- bzw. Fähigkeitslücken zu schließen.

(Probst, et al., 2006)

Einflussfaktoren auf die Wissenstransparenz

Die oft nicht geregelten Zuständigkeiten im Bereich der Wissenstransparenz, beziehungsweise der Wissensidentifikation, stellt einen negativen Einflussfaktor dar. Gesammelte Informationen über Fähigkeiten der eigenen Mitarbeiter, werden oft nicht im gesamten Unternehmen verbreitet, sondern verbleiben meist in der Personalabteilung. Umstrukturierungen im Unternehmen, Job-Rotation und eine hohe Fluktuationsrate führen ebenfalls dazu, dass das Unternehmen den Überblick der Zuständigkeiten verliert.

Als positiver Einflussfaktor kann jedoch gesehen werden, dass heutzutage die technische Infrastruktur, um eine angemessene Wissensidentifikation gewährleisten zu können, in den meisten Unternehmen bereits vorhanden ist. Kaum ein PC ist heute nicht in irgendeiner Form vernetzt! Auch das vermehrte Einsetzen, beziehungsweise der Aufstieg von Wissensarbeitern, führte zu einer Verbesserung der Kommunikation in Unternehmen.

(Probst, et al., 2006)

Methoden zur Identifikation und Darstellung von Wissensbeständen, beziehungsweise Wissensträgern und Experten

Verschiedene Arten von Wissenskarten:

 

 

Wissens(land)karten stellen eine effektive, nicht aufwändige Methode zur grafischen Visualisierung von Verzeichnissen über Wissensbestände, Wissensträger, Wissensquellen, Wissensstrukturen und Wissensanwendungen dar. Wissenskarten erhöhen die Wissenstransparenz im Unternehmen und bieten die Möglichkeit, die Informationen auf einfachem Weg, einem großen Personenkreis (zeit- und ortsunabhängig) zugänglich zu machen, zum Beispiel über das Firmen-Intranet. (Probst, et al., 2006)

Einige Voraussetzungen sollten jedoch bei der Verwendung von Wissenskarten gegeben, beziehungsweise vorhanden sein.

  • Die Verantwortlichkeiten in Hinblick auf die Wissensidentifikation sind geregelt.
  • Jeder Mitarbeiter verfügt über die nötige Klarheit im Wissensmanagement.
  • Jeder Mitarbeiter ist in der Lage seine Wissenslandkarte selbst zu pflegen.
  • Das Unternehmen hat eine einheitliche Sprache bezüglich Wissensfelder, -träger und –ausprägungen definiert, beziehungsweise etabliert.

 

(Probst, et al., 2006)

Ein weiteres Beispiel einer Wissensträgerkarte sind die Yellow Pages (Gelbe Seiten bzw. Wissensbranchenbuch):

 

 

Yellow Pages eignen sich vor allem bei Unternehmen mit viel Erfahrungswissen, welches eher schwer zu speichern ist. Zu den, in den Yellow Pages enthaltenen Informationen über die Kernprozesse des Unternehmens, sind optimaler Weise die jeweiligen Wissens- und Entscheidungsträger mit deren Kontaktdaten hinterlegt. Mitarbeiter erhalten so die Möglichkeit, Experten schnell ausfindig zu machen. In weiterer Folge können die Yellow Pages über das Intranet publiziert werden. Verfügt jeder Mitarbeiter über eine eigene Seite im Intranet, können diese mit den jeweiligen Wissensgebieten der Yellow Pages verlinkt werden. Des Weiteren kann jeder Mitarbeiter seine eigene Seite regelmäßig selbst pflegen. (Probst, et al., 2006)

Wissenslücken

Wie bereits erwähnt wurde, werden im Zuge der Wissensidentifikation auch eventuell vorhandene Wissenslücken, beziehungsweise Defizite aufgedeckt. Durch das externe Benchmarking können in weiterer Folge externe Wissensquellen in Bezug auf ihre Verwertbarkeit im Unternehmen beurteilt und best-practices identifiziert werden.

 

 

Jedoch können durch das Benchmarking nur Lücken der ersten Ebene (siehe oben „Lücke 1") aufgedeckt und durch Maßnahmen des Wissenserwerbs (zum Beispiel durch Rekrutierung, Imitation, etc.) geschlossen werden. Die „Lücke 2“ stellt eine größere Herausforderung dar. Um schwer imitierbare, organisationale Kompetenzen aufzubauen, ist es notwendig neues Wissen zu entwickeln (zum Beispiel durch Forschung, Marktstudien, etc.) oder zu erwerben. Die Entscheidung über Wissenserwerb oder Wissensentwicklung sollte allerdings wohl überlegt sein. Diese Entscheidung sollte nicht nur von kurzfristigen finanziellen Erwägungen abhängig gemacht werden. (Probst, et al., 2006)

 

 



 

 

Holger Sirtl: Windows AzureConf mit zahlreichen aktuellen Videos rund um Windows Azure

Zurück aus dem Urlaub möchte ich noch nochmal einen Blick etwas zurück werfen auf ein cooles Online-Event zu Windows Azure, auf dem wieder zahlreiche Videos rund um Windows Azure produziert und zum Download bereitgestellt wurden: die AzureConf, die am 23. April in Redmond stattfand. Folgende Videos wurden erstellt und können heruntergeladen werden:

Vortrag Sprecher Dauer
Keynote: Scott Guthrie Scott Guthrie 01:36:08
Taking Control of Your Windows Azure Services Michael Collier 00:56:57
Windows Azure Web Sites - Things They Don't Teach Kids in School Maarten Balliauw 00:57:05
From Collocated Servers to Windows Azure Web Sites in Three Days Joey Schluckter 00:32:56
Essential Iaas for Developers Vishwas Lele 00:59:43
Developing Cross Platform Mobile Solutions with Azure Mobile Services Chris Woodruff 00:56.44
Debugging and Monitoring Windows Azure Cloud Services Eric D. Boyd 01:03.40
Lights, Camera, Action - Media Services on the Loose Mike Martin 00:56:50
Real World Architectures using Windows Azure Mobile Services Kristof Rennen 01:00:12
How we Made MyGet.org on Windows Azure Maarten Balliauw 00:58:33
Node.js End-to-End Rob Ashton 00:52:14

Alle Videos stehen auf Channel 9 zum Anschauen und Herunterladen bereit.

Golo Roden: Teilen leichtgemacht: Eigene Module für Node.js veröffentlichen

Jeder Node.js-Entwickler verwendet regelmäßig Module aus der Community. Warum nicht einmal den Spieß umdrehen und der Gemeinschaft ebenfalls eine Komponente zur Verfügung stellen? Mit der Paketverwaltung npm gelingt dies in wenigen einfachen Schritten.

Ralf Westphal: Gewinnen durch Vorläufigkeit

Warum soll im Business eigentlich immer alles perfekt sein? Oder, nein, nicht perfekt, aber "effizient". Ein Beispiel dafür ist mir gerade im Rahmen eines Hobbyprojekts untergekommen: der hey! publishing Verlag. Eine befreundete Autorin hat dort einen Roman veröffentlicht, "Die Martinis": Der ist als eBook erschienen. Und das war´s. Weiter ist nichts geschehen (Stand Anfang Mai 2013), obwohl

codefest.at [MS]: BuildWindows Second Chance

Dieses Jahr war die Microsoft BuildWindows Konferenz in S.F. in weniger als drei Stunden ausgebucht. Für alle jene, die gerne hingefahren wären, aber keinen Platz mehr gefunden haben, eröffnet der Veranstalter am 15. Mai eine zweite Chance. Mit der Ankündigung “We made more room” werden diesen Mittwoch ab 18 Uhr unserer Zeit weitere Tickets verkauft.

build-second-chance

Zum Buchen & Infos zur Konferenz siehe www.buildwindows.com.

Viel Spaß!

ppedv Team Blog: JQuery Mobile Ajax Callbacks

ASP.NET Websites und das ASP.NET Scriptmanager Steuerelement können unter Umständen in Konflikt geraten. Grund ist, das Jquery Mobile automatisch clientseitige redirects per XMLHTTPRequest nachlädt.

image

Der Vorteil dieses Callbacks ist, das man dann den Seitenwechsel wunderbar animieren kann. Es reicht ein simples Attributim Hyperlink  und dann wird geslided  oder gefaded beim Übergang auf die nächste ASPX oder HTML Seite.

   1:    <ul data-role="listview">
   2:          <li><a href="WebForm22a" data-transition="slide">test</a></li>
   3:      </ul>

slides

Wie erwähnt kann das aber auch Störungen hervorrufen. Um das Standard verhalten zu erzeugen, muss vor dem Laden des JQuery Mobile Scripts, AjaxEnabled auf false gesetzt werden.

   1:   <script src="Scripts/jquery-1.8.2.min.js"></script>
   2:   <script>$(document).on("mobileinit", function () { $.mobile.ajaxEnabled = false; }); </script>
   3:   <script src="Scripts/jquery.mobile-1.3.0.js"></script>

image

Natürlich gibt es dann keine animierten Transitions mehr.

codefest.at [MS]: Corp UX Speaker Arturo Toledo und Brady Voss am 25.Mai in Wien

Arturo Toledo, Windows 8 UX Team und Brady Voss, Windows Phone UX Team machen am 25.Mai im Rahmen unseres Hacktahons in Wien Halt. Mit einigen Infos aus den Product Teams und diesen Sessions  im Gepäck:

image

 

Vortragssprache: Englisch

 

Zur Anmeldung 

Weitere Infos zu den Sessions

 

Und noch ein paar Tipps und Tricks der Vortragenden:

 

1 - The link to Expression Design is http://www.microsoft.com/en-us/download/details.aspx?id=36180 (Only Windows, no OSX). We recommend you bring it installed :)

2 - The 4 books that are inspiring us for this tour:

- Designing with the Mind in Mind

- Sketching User Experiences

- The Design of Everyday Things

- The Vignelli Canon (Free) www.vignelli.com/canon

3 - Bring your Windows and/or Windows Phone apps so we can do Mini Facelift Reviews at the end of the seminar. Mini Facelifts are 10-15 minute 1:1 sessions with you - we will give you tips and tricks and sketch out ideas for you.

4 - List of Good Design Resources

http://dev.windowsphone.com/en-us/design - Windows Design Guidelines

http://msdn.microsoft.com/en-us/library/windows/apps/hh779072.aspx - Windows Phone Design Guidelines

http://www.toledo2.com/2012/10/23/24-weeks-of-windows-phone-design/ - 24 Weeks of Windows Phone Design

http://www.windows8designhandbook.com/ - Useful Shortcut Infographics for Windows

http://www.modernuiicons.com - THE icon collection for Metro apps

http://www.microsoft.com/en-us/download/details.aspx?id=36180 - Expression Design

http://is.gd/hWZ8fe Designing with the Mind in Mind

http://www.vignelli.com/cannon.pdf - Master Design Massimo Vignelli's Manifesto

http://www.swissted.com/ - Awesomeness (Swiss Posters)

http://www.flickr.com/photos/20745656@N00/sets/72157594296535170 - Swiss Posters

http://www.bing.com/images/search?q=Swiss+design+posters - Everything Swiss Design via Bing

http://www.internationalposter.com/search-results.aspx?defaultview=browse&title=Int'l%20Typographic%20Style&style=Int'l%20Typographic%20Style  - Nice Swiss Poster Collection

ppedv Team Blog: Eigenes Website-Template mit Masterpage und CSS als Farmsolution bereitstellen

Heute möchte ich zeigen, wie ein benutzerdefiniertes Website-Template inkl. eigener Masterpage und CSS-Datei als Farmsolution bereitgestellt werden kann. Im Beispiel habe ich das OrangeWebsite-Template von FreeSMP als benutzerdefinierte Masterpage verwendet.

  1. Zunächst ist in Visual Studio ein neues SharePoint Projekt vom Typ “Site Definition” als Farmsolution zu erstellen.
  2. Zum Einbinden der eigenen Masterpage ist dem Projekt im Solution Explorer mittels Kontextmenü –> Add –> New Item ein Modul hinzuzufügen. Diesem sollte gleich beim Erstellen ein aussagekräftiger Name verfgeben werden (im Bsp. “NewMasterPageModule”). Im neu erschienenen Modulordner ist anschließend ein Unterordner namens “_catalogs” und in diesem widerum einer names “masterpage” zu erstellen. Im Ordner Masterpage wird nun via Kontextmenü –> Add –> Existing Item die Masterpage importiert (vgl. Abbildung in Schritt 9).
  3. In der Elements.xml des Moduls sind weiterhin die Deployment-Pfade wie folgt anzupassen, damit die Masterdatei in den Catalogs-Bereich der Zielwebsite kopiert wird, wo auch die anderen Masterpages liegen.
       1:  <?xml version="1.0" encoding="utf-8"?>
       2:  <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
       3:    <Module Name="NewMasterpageModule" Url="_catalogs/masterpage">
       4:      <File Path="NewMasterpageModule\_catalogs\masterpage\OrangeWebsite.master" 
    Url="OrangeWebsite.master" />
       5:    </Module>
       6:  </Elements>
  4. Die Css-Datei wird nun über ein mapped-SharePoint Folder hinzugefügt. Dies geschieht im Kontextmenü des Projekts –> Add –> SharePoint Mapped Folder –> mit folgender Location: {SharePointRoot}\Template\LAYOUTS\1033\STYLES\. In diesen Mapped Folder wird nun die CSS importiert (Kontextmenü –> Add –> Existing Item).

  5. Gleiches Verfahren kann noch für ein Vorlagen-Image wiederholt werden. In dem Fall allerdings mittels Add –> SharePoint “Images” Mapped Folder und anschließend das Bild hier importieren. Das Vorlagen-Image dient später beim Erstellen einer neuen Website auf Basis des eigenen Website-Templates als Icon bzw. Symbol.

  6. Nun muss noch die CSS korrekt innerhalb der Masterpage referenziert werden. Dies geschieht mittels folgender Zeile:

    <SharePoint:CssRegistration name="OrangeWebsite.css" After="corev4.css"  runat="server"/>

    Die Markierung zeigt die Stelle innerhalb der Masterpage, an der die Anpassung vorgenommen wird:
    image
  7. Damit die Masterpage innerhalb der Website-Vorlage überhaupt verwendet werden kann, muss sie innerhalb eines Features bereitgestellt werden. Wenn dem Projekt das erste Artefakt (in unserem Bsp. das Modul für die Masterpage) hinzugefügt wird, erzeugt Visual Studio automatisch ein Feature, welches als Paketierungseinheit für das hinzugefügte Modul dient. Aus Gründen der Übersichtlichkeit und besseren Lesbarkeit empfiehlt es sich, Features mit Hilfe eines aussagekräftigen Namens umzubenennen (z.B. “MasterPage Feature”). Dies geschieht – genau wie das Einstellen des Feature-Scopes auf “Web” – im Feature Designer (Doppelklick auf das Feature oder über Kontextmenü).
    image

  8. Anschließend muss der SiteDefinition (in der Datei Onet.xml) noch die Referenz auf die benutzerdefinierte Masterdatei eingebunden werden. Dies erfolgt zum einen durch das Einfügen des MasterUrl- und CustomMasterUrl-Properties im Configuration-Tag

    <Configuration ID="0" Name="OurTemplate" MasterUrl="_catalogs/masterpage/OrangeWebsite.master" 
    CustomMasterUrl="_catalogs/masterpage/OrangeWebsite.master">


    und zum anderen durch das Einbinden des MasterPage Features im Abschnitt “WebFeatures”. Die FeatureID kann im Feature-Designer unter “Manifest” ermittelt werden.

    <WebFeatures>
       <Feature ID="e627ebdf-38eb-4d87-94b1-bdd8e41a3771"></Feature>
    </WebFeatures>

     

  9. Optional: Wie in Punkt 8 anhand der Attribute zu erkennen ist, wird unterschieden zwischen Standard- (MasterUrl) und benutzerdefinierter (CustomMasterUrl) Masterpage. In diesem Beispiel soll die OrangeMaster sowohl Default als auch Custom Masterpage darstellen. Folgender Schritt ist daher optional und nur dann wichtig, wenn mit Veröffentlichungsseiten (Publishing Pages) gearbeitet werden soll und diese eine andere Masterpage verwenden, als “normale” aspx Pages.
    Soll bspw. die mitgelieferte “Default.aspx” die Custom-Masterpage verwenden, ist in Zeile 1  der Default.aspx das MasterPageFile Attribut auf "~masterurl/custom.master" zu setzen.


    Nachdem der Lösung alle Artefakte hinzugefügt und ggf. umbenannt wurden, sollten im Solution-Explorer zusätzlich folgende Einträge vorhanden sein: 
    image

  10. Zum Testen kann nun mit dem Debuggingvorgang begonnen werden (F5) und auf der Seite im Browser eine neue Website basierend auf dem eigenen Website-Template erzeugt werden. Der Eintrag dazu befindet sich standardmäßig in der Kategorie “SharePoint Customizations”.
    image
    Anschließend wird die Default.aspx als Startseite der neu erstellten Website aufgerufen basierend auf der eigenen Masterpage bzw. CSS-Datei. 
    image

  11. Wenn das Projekt den Anforderungen entspricht kann der Solution Status auf Release gesetzt und im Solution Explorer im Kontextmenü der Lösung mittels “Package” die wsp-Datei erzeugt werden. Diese befindet sich dann im Projktordner unter \bin\Release\ und kann wie üblich mittels Powershell deployt werden.
    image

Gregor Biswanger: video2brain - Windows Store Apps mit XAML und C# – Das große Training + Geek-Gewinnspiel

Windows_Store_Apps_mit_XAML_und_C#–Das_große_Training

 

Passend zu meiner letzten DVD “Meine erste Windows 8 App”, gibt es jetzt das umfangreiche Video-Training zum Thema “Windows Store Apps mit XAML und C#”. In diesem Video-Training erkunden und erlernen wir ausführlich die faszinierenden Möglichkeiten der App-Entwicklung für Windows 8 und Windows RT. Wir steigen mit den Grundlagen von XAML ein und sind auch bald mit den wichtigsten Neuerungen der Windows Runtime vertraut. Mit den Best Practices zum Thema MVVM - Model View ViewModel - und vielen Profi-Tipps steigst Du bald auf zum versierten App-Entwickler und -Designer.

 

Weitere Informationen

- Produktübersicht
- Inhaltsverzeichnis

 

Kostenfreie Probevideos

 

Einführung in XAML

 

App in den Store stellen

 

Facebook Fanpage

Weitere Tipps und Tricks zur Windows Store App Entwicklung findest du regelmäßig auf der Facebook Fanpage von “Meiner ersten Windows 8 App”: https://www.facebook.com/MeineErsteWindows8App

 

Großes Geek-Gewinnspiel in Kooperation mit WindowsDeveloper.de bis zum 19.05.2013

 

geek-aktion

 

Zu Gewinnen gibt es eine Signierte-Version meiner DVD “Meine erste Windows 8 App”. Dabei wurde die DVD nicht von mir persönlich unterzeichnet, sondern ich habe diese direkt in Redmond vom WinRT-Team verewigen lassen. Dabei sind Unterschriften von Tim Heuer (Program Manager für Microsoft XAML), Unni Ravindranathen (Program Manager für Microsoft Expression) und drei weiteren Mitgliedern des WinRT Teams.

Außerdem verlosen wir vier Zugänge zum neuen video2brain-Online-Training “Windows Store Apps mit XAML und C#”.

 

windows8-gewinnspiel-dvd-feature

 

Zum Gewinnspiel geht es hier lang: [Geek-Gewinnspiel] Zeit für Windows 8! – Einsteiger-Tutorials zu gewinnen

Nun wünsche ich allen viel Spaß beim Rätseln!

 

Besten Dank

Besten Dank an das ganze video2brain-Team!


video2brain_logo

Swiss DPE Team [MS]: Jump Start Serien für Entwickler

Im Mai finden wieder eine Reihe von Jump Start Sessions der Microsoft Virtual Academy für Entwickler statt. Die umfangreichen, virtuellen Trainings sind kostenlos und fallen zeitlich genau auf den frühen Feierabend bei uns. Wer trotzdem keine Zeit findet, sollte sich dennoch anmelden, damit die Aufzeichnungen später konsumiert werden können.

JumpStarts

Unsere Kollegen von Österreich haben drei Top Sessions heraus gesucht:

Advanced Windows Store App Development using C# Jump Start

23. Mai | 18:00 – 01:00 Uhr

In dieser Jump Start Session von Microsoft Technical Evangelist Jerry Nixon und Daren May geht es in verschiedenen Beispielen darum, wie fortgeschrittene Developer mit C# Windows Store Apps entwickeln können.

Zur Session-Beschreibung und Anmeldung

Software Testing with Visual Studio 2012 (exam 70-497) Jump Start

28. Mai | 18:00 – 01:00 Uhr

Software testing at it’s best! Diese Session von Anthony Borton und Steven Borg zeigt, wie man Development Prozesse mit Visual Studio 2013 erstellt und verbessert und application lifecycle management (ALM) im Unternehmen verwendet.

Zur Session-Beschreibung und Anmeldung

Administering Visual Studio Team Foundation Server 2012 (exam 70-496) Jump Start

29. Mai | 18:00 – 01:00 Uhr

Anthony Borton und Steven Borg zeigen, wie man Team Foundation Server 2012 (TFS) für Codeverwaltung und ALM und effizientes Code-Building einsetzt.

Zur Session-Beschreibung und Anmeldung

Code-Inside Blog: IIS & Windows Authentication – Troubleshooting mit Negotiate & NTLM

image.png

Windows Authentifizierung ist eine einfache (und naheliegende) Authentifizierungs-Option für “Haus-interne” Webapplikationen.

Setup

Im IIS selbst kann man die Windows Authentifzierung sehr leicht anschalten:

iis

Natürlich kann man dies auch über die web.config steuern:

 <system.web>
  ...
  <authentication mode="Windows"/>
  ...
 </system.web>
 ...

Fehlermeldung “HTTP Error 401.2 – Unauthorized”:

Dies kann (wie fast immer) viele Gründe haben, z.B. weil man nicht die erforderten Rechte hat. Wenn man dies als Fehlerquelle ausschliessen kann, sollte man überprüfen ob überhaupt die Windows Authentifzierung angeschalten ist und ob das Feature in den Windows-Komponenten aktiviert ist:

image

Providers:

Im Normalfall gibt es zwei Provider: Negotiate und NTLM. Negotiate sagt einfach nur, dass Server und Client sich abstimmen. Allerdings hatte ich bislang zweimal das Problem, dass Server und Client sich auf Kerberos Authentifizierung geeinigt hatten, dies aber aus irgendeinem Grund nicht funktionierte. Als ich nur noch NTLM nutze ging es.

image

Troubleshooting Tipps:

Ruft man die Seite direkt auf dem Server über den IE auf, wird immer NTLM genommen (und nicht Kerberos).

Alle nicht IE-Browser versuchen sich über NTLM zu authentifizieren. Zum Testen nehm ich sowohl IE als auch Chrome.

Wer im IE eine automatische Anmeldung möchte, d.h. kein Login Prompt, muss die URL in der Intranet-Zone eintragen (oder die Policies verändern)

image

Windows Authentifizierung ist eine nette Sache – wenn sie funktioniert ;)

codefest.at [MS]: Microsoft Jump Start Series für Entwickler

Im Mai finden eine Reihe von Jump Start Sessions der Microsoft Virtual Academy für Software-Developer statt. Die virtuellen Trainings sind kostenlos und starten in unserer Zeitzone am frühen Abend ab 18 Uhr – viel besser als fernsehen. Smiley

Wer keine Zeit hat sollte sich dennoch anmelden und die Aufzeichnungen später ansehen.

mva-home

Hier drei interessante MVA-JumpStart-Veranstaltungen:

 

Advanced Windows Store App Development using C# Jump Start

am 23. Mai, von 18 Uhr bis 1 Uhr früh.

In dieser Jump Start Session von Microsoft Technical Evangelist Jerry Nixon und  Daren May geht es in verschiedenen Beispielen darum, wie fortgeschrittene Developer mit C# Windows Store Apps entwickeln können. Aus dem Inhalt:

  • Windows Store Apps Essentials
  • Implementing Animations and Transitions
  • Implementing Globalization and Localization
  • Branding and a Seamless User Interface
  • Advanced Data Scenarios in a Windows Store App
  • Creating Reusable Controls and Components
  • Implementing Advanced Contract Scenarios
  • The Windows Push Notification Service (WNS)
  • Capturing Media & Background Tasks
  • Generating Revenue with your App
  • Securing Windows Store App Data

Zur Session-Beschreibung und Anmeldung

 

Software Testing with Visual Studio 2012 (exam 70-497) Jump Start

am 28. Mai, von 18 Uhr bis 1 Uhr früh.

Software testing at it´s best! Diese Session von Anthony Borton und Steven Borg zeigt, wie man Development Prozesse mit Visual Studio 2013 erstellt und verbessert und application lifecycle management (ALM) im Unternehmen verwendet.

  • Create and Configure Test Plans
            - Create Test Plan Properties 
            - Define and Configure Test Settings 
            - Create and Configure Test Suites
  • Manage Test Cases:
            - Create Test Cases and Steps
            - Define Parameters
            - Manage Shared Steps and Requirements
  • Manage Test Execution:
            - Run and Analyze Recommended Tests
            - Perform Exploratory Testing and Analysis
            - Manage Bugs and Work Items

 Zur Session-Beschreibung und Anmeldung

 

Administering Visual Studio Team Foundation Server 2012 (exam 70-496) Jump Start

am 29. Mai, von 18 Uhr bis 1 Uhr früh.

Anthony Borton und Steven Borg zeigen, wie man Team Foundation Server 2012 (TFS) für Codeverwaltung und ALM und effizientes Code-Building einsetzt.

  • Install and Configure Visual Studio 2012 Team Foundation Server
  • Manage Visual Studio 2012 Team Foundation Server
  • Customize Visual Studio 2012 Team Foundation Server for Team Use
  • Administer Version Control

Zur Session-Beschreibung und Anmeldung

 

mva-jumpstart

Viel Spaß mit den kostenfreien MVA-Sessions!

Swiss DPE Team [MS]: Visual Studio 2012 Update 3 RC verfügbar!

Kurz nach der allgemeinen Verfügbarkeit des zweiten Updates für Visual Studio 2012 ist jetzt bereits das dritte Update als Release Candidate erhältlich und kann somit in Produktionsumgebungen eingesetzt werden. Anders als das zweite Update konzentriert sich Visual Studio 2012.3 allerdings nicht auf neue Funktionen, sondern behebt vor allem einige Fehler der bisherigen Version. Visual Studio 2012.3 kann über das Download Center bezogen werden.

Stefan Lange: dotnet Cologne 2013 – Windows Azure Mobile Services

Zu meinem Vortrag „Einführung in die Windows Azure Mobile Services“ auf der dotnet Cologne 2013 finden sich hier die Slides.

Die Slides wurden an den aktuellen RC der Mobile Services angepasst.

Materialien zum Vortrag:

Thomas Schissler: TFS 2012 Lab Management mit Windows XP VMs

Seit dem Update 2 ist es nun endlich wieder möglich, das Lab Management im TFS 2012 auch mit XP-Maschinen zu betreiben. Das Problem war hier bisher, dass der Test Agent 2012 das .Net Framework 4.5 benötigt, dass sich das aber auf XP nicht installieren lässt. Man kann nun die Test Agents für 2012 Update 2 hier herunterladen: http://www.microsoft.com/en-us/download/details.aspx?id=38186.

Wie man bei der Installation vorgehen muss, wird hier beschrieben: http://msdn.microsoft.com/en-us/library/jj153008.aspx#installagent. Das Dokument hat jedoch einen kleinen Schönheitsfehler. Es verschweigt nämlich die Tatsache, dass  man vor der Installation des Test Agents das .Net Framework manuell installieren muss. Das Setup des Test Agents versucht nämlich das Framework zu installieren, wenn keines vorhanden ist, dummerweise aber immer das 4.5er. Probleme gibt es übrigens auch, wenn nur ein älteres Framework (z.B. 3.5) installiert ist. Dort schlägt die Installation fehl. Auch hier hilft einfach Framework 4.0 manuell zu installieren.

image

Lustig finde ich auch die Fehlermeldung “0x800713ec – Asia” Smile

Falco Ostermann: How to: Searching in SharePoint using the new REST API and JavaScript

Als Entwickler versucht man heutzutage jegliche Informationen in SharePoint über die Suche zu beziehen. Ihr stellt euch die Frage Warum?

  • Performanter Lösungsweg, da der Suchindex asynchron aufgebaut wird
  • Security Trimming in der Ergebnisliste
  • Über C#, JavaScript oder REST abrufbar

In SharePoint 2013 wurden diese Ansätze natürlich weiterhin erweitert und vereinfacht ;-) . Da aufgrund von SharePoint Apps JavaScript immer wieder mehr an Bedeutung findet, möchte ich in diesem Artikel zeigen, wie die REST API für die Suche über JavaScript verwendet werden kann.

Accessing Search using REST API

Der Vorteil von Rest besteht darin, dass es sich lediglich um eine URL handelt. Dadurch kann der Aufruf und das Ergebnis im Browser getestet werden ohne eine Zeile Code zu schreiben. Die Grundstruktur von Rest sieht dabei wie folgt aus:

http://<Site Url>/_api/<SP API>/<Operation>?<Parameters>

In unserem Fall würde die Url wie folgt aufgebaut sein:

http://<Site Url>/_api/search/query?querytext=’test’

Wird diese Url im Bowser aufgerufen, so wird ein XML mit interessanten Eigenschaften als Antwort vom Server zurückgegeben. Zum Beispiel die Anzahl der Treffer.

Search Properties

Die Suchanfrage kann an Hand vieler Parameter gefiltert werden. Typische Anwendungsfälle wären zum Beispiel:

  • die Filterung der Ergebnisse an Hand des Autors oder einer speziellen Source ID
  • maximale Anzahl an Ergebnissen pro Seite (für Paging) oder Gesamt
  • Angabe der benötigten Managed Properties (Title, Author, Path)

Eine ausführliche Auflistung aller Möglichkeiten inklusive Code-Beispiel findet sich auf MSDN.

Calling the REST service from JavaScript

Ich habe mir zunächst über Napa eine neue SharePoint App erstellt und das AppManifest.xml mit den notwendigen Berechtigungen erweitert.

Damit wird sichergestellt, dass die App Zugriff auf die SharePoint Suche besitzt und die Anfrage nicht in einem Access Denied endet.

Im nächsten Schritt habe ich der Default.aspx eine einfache Suchmaske ohne viel Magie hinzugefügt.

<div>
    <input type="text" id="searchBox"></input>
    <input type="button" id="searchBtn" value="Search"></input>
    <div id="searchResult" />
</div>

Zum Schluss wechseln wir zur App.js und fügen den eigentlichen REST Aufruf hinzu. Bei dem hier dargestellten Lösungsweg handelt es sich um einen vereinfachten objektorientierten Ansatz. Es ist zu empfehlen diese Logik in eine eigene JavaScript Datei mit eigenem Namespace auszulagern, nur möchte ich der übersichtshalber hier darauf verzichten.

'use strict';
var context = SP.ClientContext.get_current();
var SPSearchResults = {
      elem : '',
      url : '',
      init : function(elem, query) {
          SPSearchResults.elem = elem;
          SPSearchResults.url = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='" + query + "'";
      },
      load: function() {
          $.ajax(
           {
                  url: SPSearchResults.url,
                  method: "GET",
                  headers: {"accept" : "application/json;odata=verbose"},
                  success: SPSearchResults.onSuccess,
                  error: SPSearchResults.onFailed
           }
          )
      },
      onSuccess: function(data) {
             var results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
             if(results.length === 0) {
                    $(SPSearchResults.elem).text("no results were found.");
             } else {
                    var resultHtml = "<div class='searchResults'>";
                    $.each(results, function(index, result) {
                              resultHtml += "Title: <a href='" + result.Cells.results[6].Value + "'>" + result.Cells.results[3].Value + "</a> <br/>" + 
                              "Content: " + result.Cells.results[10].Value + "<br/>" + 
                              "Type: " + result.Cells.results[17].Value + "<br/>" + 
                              "Modified: " + new Date(result.Cells.results[8].Value).toString("MMMM") + "<br/>";
                    })
                    resultHtml += "</div>";
                    $(SPSearchResults.elem).html(resultHtml);
             }
      },
      onFailed: function(error) {
             $(SPSearchResults.elem).text("An unexpected error occurred.");
      }
  }

// This code runs when the DOM is ready and creates a context object which is
// needed to use the SharePoint object model
$(document).ready(function () {
    $("#searchBtn").click(function() {
           SPSearchResults.init($("#searchResult"), $("#searchBox").val());
           SPSearchResults.load();
    });
});

Der dargestellte Code erstellt in der Methode init in Abhängigkeit des Suchwortes eine REST Query. Durch die Methode load wird diese Anfrage unter der Verwendung von jQuery ausgeführt. War die Anfrage erfolgreich so wird in der Methode onSuccess durch die Ergebnisse iteriert und in dem gewünschten Div angezeigt. Sollte diese Anfrage in einem Fehler enden, so wird diese über onFailed behandelt.

Fazit

Immer mehr Anwendungen setzen für die Aggregierung von Daten auf die SharePoint Suche um Performance zu gewährleisten. Dabei kann die Such API auch über JavaScript und REST angesprochen werden, um diese Vorteile auch in einer SharePoint App anzuwenden. Verwendet kann diese Lösung nicht nur in Apps, sondern auch in allen Farm- oder Sandbox-Solutions wo auf JavaScript gesetzt wird.

Ich persönlich begrüße es, dass die Suche für die Entwicklung immer mehr in den Vordergrund gestellt wird, da ich sehr viel Wert auf Performance lege. Ich hoffe dieser kurze Artikel hat euch ebenfalls von der Mächtigkeit der neuen SharePoint 2013 REST API überzeugt und wie immer freue ich mich auf Euer Feedback :-)

Code-Inside Blog: Json-Online-Tools: Viewer & Json2Csharp Generator

image.png

Wo APIs im Spiel sind, ist das JSON Format nicht weit. Da ich immer mal wieder zwei Tools benutze, möchte ich diese hier auch mal kurz würdigen.

JSON Viewer

Wer nur den JSON-Text vor sich hat sieht meist die Struktur nicht. Über JSON Viewer kann man sich recht einfach einen Überblick verschaffen: [URL]

image

JSON2CSharp

Der Titel sagt schon alles: Mit dem Tool kann man sehr einfach JSON in CSharp Code umwandeln. Dies ist dann ziemlich nützlich wenn man z.B. das Gegenstück zur einer JSON-API baut und mit den Resultaten “arbeiten” möchte: [URL]

image

Thomas Schissler: Coded UI Test unter Windows 8

Wenn man unter Windows 8 Coded UI Tests auf laufen lassen möchte, hat man Probleme, wenn man die Tests z.B. in einer Lab Umgebung mit Autologon ausführen möchte. D.h. die Maschine bootet aus einem Snapshot und wird automatisch angemeldet. Dann bekommt man als erstes den Windows 8 Startbildschirm. Da der Coded UI Test diesen nicht steuern kann, haben wir hier ein Problem. Mit einem kleinen Tool kann man Windows 8 aber auch so konfigurieren, dass es direkt mit dem Desktop startet. Vielleicht ist das ja auch für andere Szenarien als dem hier beschriebenen interessant Smile

http://win-8.de/MetroDeactivator/

codefest.at [MS]: Pizza Tour Windows 8 Development Nachlese

Für all jene die uns bei der diesjährigen Frühjahrs - Pizzatour nicht besuchen konnten und jene die einfach nur in den Unterlagen schmökern und nachlesen wollen:

Die Nachlese mit den Samples und Präsentationsunterlagen ist online verfügbar!

 

 

Pizza2013Image

Ralf Westphal: Mehr verdienen durch Experiment

Könnten Sie oder die Firma, für die Sie arbeiten, mehr verdienen? Ja? Wunderbar, dann los! Nein? Warum nicht? Woher weiß man das? Auf diese Frage bin ich neulich bei einem Aufenthalt im Marriott Hotel in Zürich gestoßen. Dort fand ich nämlich dieses Angebot vor: Zum Verkauf auf dem Zimmer standen solche 1 Liter Flaschen Wasser für 8,00 CHF (ca. 6,50 EUR) das Stück. Ein stolzer Preis,

Sascha Dittmann: Windows Azure Mobile Services - Windows Account Authentifizierung für Windows Store Apps

Windows Azure Mobile Services - Windows Account Authentifizierung für Windows Store AppsIn den bisherigen Teilen meiner Windows Azure Mobile Services Serie wurde eine Windows Store App erstellt, welche Nachrichten in der Cloud speichert.
Bislang waren diese Nachrichten keinem Benutzer zugeordnet worden.
Dies soll sich heute ändern, indem die Benutzer via Microsoft Account authentifiziert werden...

App im Live Connect Developer Center registrieren

Damit sich die Benutzer der Windows Store App via Microsoft Account authentifizieren können, muss diese zuerst im Live Connect Developer Center registriert werden.

Dazu navigiert man zuerst auf die My Applications Seite des Live Connect Developer Centers.

Mit einem Klick auf den Create Application-Link wird die Registrierung gestartet:

Live Connect Developer Centers - Create Application Link

Nachdem man den Namen der App sowie die primäre Sprache angegeben hat, klickt man auf "I accept":

Live Connect Developer Centers - Basic Information

 

Unter den API Settings findet man dann die Client ID und das Client Secret, die man im nächsten Schritt benötigt.

Außerdem muss die URL des entsprechenden Mobile Services als "Redirect Domain" eingetragen werden:

Live Connect Developer Centers - API Settings

 

Änderungen bei den Mobile Services

Die gerade erhaltene Client ID, sowie das Client Secret, trägt man anschließend in den Identity Bereich des Mobile Services ein und klickt "Save":

Windows Azure Mobile Services - Identity

Jetzt sind die Mobile Services bereit, um die Benutzer via Microsoft Account authentifizieren zu können.

 

Änderungen an der Windows Store App

Damit die Anwender der Windows Store App zur Eingabe ihrer Microsoft Account-Benutzerdaten aufgefordert werden, genügt eine Zeile Code:

await _mobileServiceClient.LoginAsync(
  MobileServiceAuthenticationProvider.MicrosoftAccount);

 

Um dabei auch mögliche Fehlermeldungen, die beispielsweise beim Abbrechen des Dialogs auftreten, abzufangen sieht die entsprechende Methode im ViewModel der "Let's Talk"-App wie folgt aus:

private async Task Authenticate()
{
  if (_mobileServiceClient.CurrentUser != null) return;

  var message = String.Empty;
  try
  {
    await _mobileServiceClient.LoginAsync(
      MobileServiceAuthenticationProvider.MicrosoftAccount);
  }
  catch (InvalidOperationException)
  {
    message = "login unsuccessful";
  }
  catch (Exception ex)
  {
    message = ex.Message;
  }
  if (!String.IsNullOrEmpty(message))
    await new MessageDialog(message, "Authenticate User").ShowAsync();
}

 

Für die Benutzer stellt sich das wie folgt dar:

Windows Store App - Eingabe des Microsoft Accounts

 

Bei der ersten Anmeldung muss außerdem der Zugriff auf die Daten des Benutzers bestätigt werden:

Windows Store App - Bestätigung der angeforderten Berechtigungen

 

Berechtigungen auf Tabellenebene anpassen

Nur angemeldete Benutzer sollen Nachrichten hinzufügen bzw. löschen können.

Um dies zu gewährleisten, müssen die Insert- und Delete-Rechte der Messages-Tabelle auf "Only Authenticated Users" gesetzt werden.

Außerdem sind in den "Let's Talk"-Apps Änderungen an den Nachrichten nicht zulässig, weshalb das Update-Recht nur für Skripte und Administratoren freigegeben wird:

Windows Azure Mobile Services - Message Table Permissions

 

Damit beim Hinzufügen einer Nachricht auch der Benutzer gespeichert wird, muss eine weitere Zeile im Insert-Skript hinzugefügt werden:

function insert(item, user, request) {
  if (!item.body || item.body.length < 2) {
    request.respond(statusCodes.BAD_REQUEST, 'The message text must be 2 or more characters long.');
    return;
  }

  item.createdAt = new Date();
  item.userId = user.userId;

  request.execute();
}

 

Durch das Dynamische-Schema-Feature der Mobile Services wird beim nächsten Speichervorgang die Messages-Tabelle um die UserID Spalte erweitert.

Auch das Löschen der Nachrichten soll nur dessen Besitzer erlaubt werden.

Dies kann durch folgendes Delete-Skript der Messages-Tabelle erreicht werden:

function del(id, user, request) {
  var messagesTable = tables.getTable('messages');

  messagesTable.where({
    id: id,
    userId: user.userId
  }).read({
    success: function(results) {
      if (results.length === 0) {
        request.respond(statusCodes.UNAUTHORIZED, 'You can only delete you own messages.');
      }
      else {
        request.execute();
      }
    }
  });
}

 

Dieses macht eine Lookup-Abfrage auf die Messages-Tabelle und wirft eine Fehlermeldung, wenn der Benutzer versucht eine fremde Nachricht zu löschen.

 

Wie geht es weiter?

Im nächsten Teil dieser Serie wird die Windows Store App mit einer Microsoft-Account-Authentifizierung via Live SDK erweitert, damit die Benutzer sich automatisch mit ihrem für die Windows Anmeldung genutztem Konto anmelden können.

 


Weitere Informationen Beispielanwendung:

Weitere Informationen:

ppedv Team Blog: KeywordQuery Class–deprecated

Unlängst habe ich wieder einmal die KeywordQuery Klasse für ein SharePoint Webpart verwendet. Allerdings kam beim Kompilieren das Warning: “  [deprecated ]” was mich, ehrlich gestanden, etwas verwundert hat.

image

Interessanterweise wird jedoch im MSDN die Klasse im Detail beschrieben. (msdn)

Jedoch ist die Lösung einfach. Früher gab es die Klasse im Namespace “Microsoft.SharePoint.Search.Query”. Diese Klasse ist nun veraltet und wird in der nächsten Version nicht mehr enthalten sein. Sucht man im MSND nach dem Begriff “KeywordQuery” wird leider als erstes Suchergebnis die veraltete Klasse angezeigt.

Der richtige Namespace ist “Microsoft.Office.Server.Search.Query”. Bei der Auswahl der dll, die bei bei Referenzen anzugeben ist, muss darauf geachtet werden die richtige auszuwählen!

image

Leider liegen beide Dateien im ISAPI Verzeichnis des SharePoint Servers.

Golo Roden: Verschachtelte Ansichten mit AngularJS

AngularJS unterstützt von Haus aus weder zusammengesetzte noch verschachtelte Ansichten, was sich aber mit Hilfe des Projekts UI-Router nachrüsten lässt. Es stellt die Dienste $stateProvider und $urlRouterProvider zur Verfügung und ermöglicht eine flexible Konfiguration von Zuständen und Adressen.

Alexander Zeitler: Slides / Demos zu meinen dotnet Cologne 2013 Sessions #dnc13 #hypermedia #spa #aspnetwebapi

Bereits zum 5. Mal fand am vergangenen Freitag die dotnet Cologne in Köln statt. Über 400 Teilnehmer und die Orga haben die Veranstaltung wieder zu einem Highlight der .NET Community gemacht.

Ich hatte die Gelegenheit, zwei Sessions beizutragen:

Hypermedia mit der ASP.NET Web API

REST ist der wohl am häufigsten mißbrauchte Begriff der letzten Jahre. Viele REST-APIs stellen sich bei genauer Betrachtung als klassische CRUD-Services heraus, ohne ein Kernelement von REST zu berücksichtigen: Hypermedia. Der Vortrag zeigt die Umsetzung von Hypermedia APIs mit ASP.NET Web API.

Die Slides finden sich hier:

Der Code kann hier heruntergeladen werden.

Single Page Applications – jenseits von “ToDo”

Mit dem ASP.NET and Web Tools 2012.2 Release hat Microsoft nun auch eine Projekt-Vorlage für Single Page Applications in Visual Studio 2012 platziert. Leider geht das Beispiel nicht über die klassische ToDo-App hinaus und auch sonst findet man wenig Dokumentation zum Aufbau von Single Page Applications, die komplexere Szenarien behandeln. In diesem Vortrag wird unter Verwendung individuell zusammengestellter JavaScript-Frameworks die Entwicklung großer Single Page Applications erklärt.

Die Slides finden sich hier.

Single Page Applications Slides

Sascha Dittmann: dotnet Cologne 2013 - Slides und Links zu meinen Sessions

dotnet Cologne 2013Am vergangenen Freitag öffnete die dotnet Cologne bereits zum fünften mal ihre Pforten.
Wie auch schon in den letzten Jahren strömten auch an diesem Tag wieder hunderte von Entwicklern die Räumlichkeiten des Komeds in Köln.
Die Slides bzw. Links zu meiner Microsoft HDInsight Session und der Windows Azure Mobile Services Session von Stefan Lange und mir findet ihr in diesem Blog Post...

Big Data mit Microsoft HDInsight für .NET Entwickler

Abstrakt

Wir leben in einem Datenzeitalter! Nach Schätzungen in 2006, betrug das weltweite "Datenuniversum" ca. 0.18 Zettabytes (10^21 Bytes bzw. 1 Mrd. Terrabyte). In 2011 hat sich dieses Volumen sogar verzehnfacht (1,8 Zettabytes). Somit wird in vielen Anwendungsszenarien das Thema Big Data und Big Processing immer wichtiger. Es fallen sehr viele Daten an, die von immer mehr Benutzern und Systemen konsumiert und ausgewertet werden wollen. Klassische relationale Datenbanksysteme, sowie Statistik- und Visualisierungstools, sind oft nicht in der Lage, derart große Datenmengen zu verarbeiten. Für Big Data kommt daher eine neue Art von Software zum Einsatz, die massiv parallel auf bis zu hunderten oder tausenden von Prozessoren bzw. Servern arbeitet, wie z.B. Microsoft HDInsight. Diese Session liefert einen Überblick über die Grundpfeiler des Frameworks hinter HDInsight und wie Analysen mit JavaScript und .NET Code durchgeführt werden können.

(Level 200)

 

Slides

SlideShare: dotnet Cologne 2013 - Microsoft HD Insight für .NET Entwickler

 

Weiterführende Links

 

Einführung in die Azure Mobile Services

Abstrakt

Die Mobile Services gehören zu den neuesten Azure Technologien und bieten Entwicklern ein solides und sicheres Backend für ihre mobilen Apps. Ob Datenbankzugriff, Authentifizierung, Server-seitige gescriptete Logik oder Notifications, alles kann bemerkenswert einfach konfiguriert und in der eigenen Anwendung genutzt werden. Stefan Lange zeigt wie elegant sich die Azure Mobile Services in Windows 8 und Windows Phone 8 einbinden lassen, aber auch wie man sie ganz unabhängig davon nutzen kann.

(Level 200)

 

Slides

Gemeinsam mit Stefan Lange habe ich die Windows Azure Mobile Services auf der dotnet Cologne 2013 vorgestellt:

SlideShare: dotnet Cologne 2013 - Windows Azure Mobile Services

 

Weiterführende Links


Holger Schwichtenberg: Softwarearchitektur mit dem Entity Framework

Bei der "Dotnet Cologne" hat der Dotnet-Doktor diskutiert, auf welche Weise man das ADO.NET Entity Framework in einem Mehrschichtmodell einsetzen kann.

Fabian Deitelhoff: mite: Erfahrungen nach einem Monat

Ende März hatte ich einen Artikel über meine Suche nach einer guten Zeiterfassung geschrieben. Damals habe ich mich für mite entschieden, dass viele Funktionen in einer einfach zu bedienenden Web-Oberfläche anbietet.

Nun ist etwas mehr als ein Monat vergangen und mein kostenloser Testmonat ist abgelaufen. Da steht natürlich die Frage im Raum, ob ich meinen Test-Account in einen kostenpflichtigen Account umwandeln soll.

Die Frage war nicht schwer zu beantworten. Mir gefällt mite ausgesprochen gut! Die Funktionen reichen für meine Zwecke aus. Das soll nicht negativ klingen, aber ich habe beispielsweise keine Möglichkeit gefunden, Sub-Projekte zu erstellen. Also ein Projekt das einem anderen untergeordnet ist. Letztendlich brauche ich diese Funktionalität aber gar nicht, als ich etwas über die geplante Projektstruktur nachgedacht hatte.

Nach einem Monat ist das – für mich – auch der Hauptvorteil an mite. Die einfache und simple Bedienung. Jede Funktion scheint durchdacht worden zu sein und sitzt in der Oberfläche genau am richtigen Fleck. Auch die Funktionen passen sehr gut zu meinen Anforderungen. Ich wollte lediglich verschiedene Projekte anlegen, denen ich Aufgaben zuordnen kann. Diese Aufgaben heißen in mite Leistungen. Das passt wunderbar. Theoretisch kann ich auch verschiedene Kunden anlegen, denen ich Projekte zuordnen kann. Aber auch das brauche ich nicht. Mein einziger Kunde bin ich selbst, da ich über mite lediglich die Zeit für eigene Projekte beziehungsweise Leistungen verfolge. Dieser passende Funktionsumfang hat dazu geführt, dass ich meinen Account kostenpflichtig erweitert habe. Bisher bereue ich diesen Schritt in keinster Weise.

Zeit erfassen

Eine grundlegende Frage war für mich aber die ganze Zeit noch offen: Werde ich meine Zeiten überhaupt ordentlich erfassen? Zumindest so genau und detailliert, dass ich sehen kann, wie viel Aufwand ich für welches Projekt verbrauche. Also beispielsweise wie viel Zeit ich tatsächlich ins Studium investiere, wie viel Zeit ich arbeite und wann ich überhaupt nichts mache ;) beziehungsweise nichts konkretes für die in mite hinterlegen Projekte. Letzteres fällt dadurch auf, dass ich keine Zeit auf ein konkretes Projekt buche. Von Anfang an war der Plan, nur Projekte beziehungsweise Leistungen anzulegen, die etwas mit meinem Studium oder meiner Selbstständigkeit als Autor zu tun haben. So fällt die Zeit gut auf, die ich mit etwas anderem verbringe :) .

Nach einem Monat ist das Fazit, dass das sehr gut funktioniert. Die meiste Zeit kann ich direkt buchen und die Uhr von mite mitlaufen lassen. Das funktioniert auch bei Aufgaben fürs Studium gut, wie Übungen und Vorlesungen. Dadurch entfällt das Abschätzen, wie viel Aufwand tatsächlich angefallen ist, was regelmäßig in wildes Raten ausartet.

mite-Report über vier Wochen.

Abb. 1: mite-Report über vier Wochen.

Abbildung 1 zeigt den Report für die letzten vier Wochen. Teilweise sind die Aufwände, die ich pro Tag gebucht habe, wesentlich geringer als ich geschätzt hätte. Manchmal aber auch wesentlich höher. Insgesamt habe ich vom 25. März bis um 03. Mai etwas über 191 Stunden gebucht. Dieses Gesamtbild passt recht gut, wenn ich die Aufgaben berücksichtige, die ich nicht über mite erfasse. Auch Reisezeiten auf dem Weg von Dortmund <-> Bonn sind in der Regel nicht mit erfasst. Außer ich arbeite auf der Strecke an etwas.

Fazit

Abschließend kann ich mite uneingeschränkt empfehlen. Die fünf Euro, die ich für mich als einzigen Benutzer pro Monat bezahle, sind es definitiv wert. Ich bin gespannt, wie sich die gebuchte Zeit in den nächsten Wochen und Monaten verhält. Es stehen einige größere Projekte an und auch die ersten Ausläufer der Prüfungsphase sind schon zu erkennen.

Klaus Bock: Warum fragmentiert die binäre Serialisierung

fragmented2... oder; die Krux mit den automatischen Größen von Streams.
Da in der heutigen Zeit, vor allem in der Welt von verwaltetem Code, kaum noch eigene proprietäre Dateiformate Anwendung finden, werden die Allerwenigsten auf dieses Problem stoßen. Auch die Tatsache, dass für beinahe jede Anforderung ein Framework oder eine Bibliothek vorhanden ist, trägt mit Sicherheit dazu bei, solche elementaren Probleme von der Bildfläche verschwinden zu lassen. Für eine ganze Reihe von Entwicklern hört der Gedanke an binäre Serialisierung auf, wenn sie ein Framework wie BSON oder Protocol Buffers zur Anwendung bringen können. Dies soll keine Kritik und schon gar keine negative sein. Ganz im Gegenteil. Diese Frameworks erleichtern die tägliche Arbeit in vielerlei Hinsicht. Verbergen leider aber auch die eigentliche Problematik der Serialisierung. Für mich gehört dieses Thema nach wie vor zu einem der interessantesten in der Softwareentwicklung. Jetzt aber zurück zum eigentlichen Thema.

Für ein aktuelles Projekt verwende ich ein eigenes binäres Dateiformat, in das Datenblöcke in serialisierter und komprimierter Form als byte-Arrays geschrieben werden. Während der Testphase auf einem Livesystem stellte ich fest, dass die Dateigröße überproportional zum Inhalt anwuchs. Zunächst maß ich dem Verhalten keine besondere Bedeutung bei, da ein ähnliches Verhalten auch bei Formaten wie etwa den Access Datenbankdateien oder den Dateien der Windows Registrierung ebenfalls auftritt. Insgesamt ließ mich das “Problem” aber nicht in Ruhe. Nachdem ich mir eine der Dateien im Hex-Format angesehen hatte, war schnell klar, was dem Problem zugrunde lag:
Zwischen den einzelnen Datenblöcken wurde immer eine ganze Menge an 0-Byte-Zeichen geschrieben.

hexview11

Das Resultat war ersichtlich. Aber woher kam dieses Verhalten?
Wie bereits Eingangs erwähnt, werden die Datenblöcke nach dem serialisieren auch komprimiert. Dazu wird die Klasse DeflateStream der Frameworks verwendet. Diese Klasse komprimiert den Inhalt eines Stream in einen anderen. Genau da entstand das Problem.
Das Problem ist vielmehr eine Eigenart der DeflateStream Klasse in Verbindung mit einem MemoryStream. Das Verhalten lässt sich am einfachsten mit einem kleinen Beispiel verdeutlichen. Folgend wird eine Liste aus zufälligen Zeichenfolgen in ein Byte-Array serialisiert und anschließend komprimiert. Mit der Variablen numberOfEntries kann die Anzahl der Einträge in der Liste und dadurch indirekt die Länge des komprimierten Datenblocks gesteuert werden. In der Variablen realLength wird die Anzahl der tatsächlich verwertbaren Bytes im Array ausgegeben. Bei einer geringen Anzahl von Einträgen in der temporären Liste, ist der Wert von realLength immer deutlich kleiner als die Länge des erzeugten Arrays output. Erst ab etwa 130 Einträge in der temporären Liste tritt dieses Verhalten nicht mehr auf. Ab dieser Größe wird die Ausgabe ohne nachgestellte 0-Byte-Zeichen erzeugt.

var numberOfEntries = 10;
var chars = "abcdefghijklmnopqrstuvwxyz";
var tempList = new List<string>(numberOfEntries);
var random = new Random();
for (int i = 0; i < numberOfEntries; i++)
{
    var start = random.Next(0, chars.Length - 1);
    var length = random.Next(start + 1, chars.Length) - start;
    var entry = chars.Substring(start, length);
    tempList.Add(entry);
}
var buffer = Encoding.Default.GetBytes(string.Join("|", tempList));
byte[] output = null;
using (var instream = new MemoryStream(buffer))
{
    using (var outStream = new MemoryStream())
    {
        using (var compress = new DeflateStream(outStream, CompressionMode.Compress))
        {
            instream.CopyTo(compress);
        }
        output = outStream.GetBuffer();
    }
}
// Die Länge des Ausgabe-Arrays
// Unter 130 Einträgen wird fast immer eine Länge von 256 erzeugt.
var arrayLength = output.Length;
// Die tatsächliche Anzahl an verwertbaren Bytes im Array
var realLength = output.Count(b => b > byte.MinValue);

Im obigen Beispiel, wird im zweiten using-Block der MemoryStream für die Ausgabe initialisiert, der nach dem Verlassen des innersten using-Blocks die komprimierten Daten enthält. Initial wird hier ein leerer Stream mit Capacity und Length 0 erzeugt. Der DeflateStream kopiert seinen Inhalt in diesen Stream und legt dabei so lange eine Länge von 256 Bytes fest, bis diese Größe überschritten wird. Erst dann wird der Ausgabestream mit der korrekten Länge des Inhalts des DeflateStream erzeugt. Das bedeutet als Resultat für die, aus den Ergebnissen erzeugte, Datei:

Je mehr Datenblöcke aus Inhalten mit geringer Größe erzeugt werden, desto fragmentierter ist das Ergebnis.

Zur Lösung dieses “Problems”, oder besser unschönen Verhaltens, stehen jetzt zwei Ansatzpunkte zur Auswahl:

  1. Am Anfang des Prozesses, in dem der Konstruktor des Ausgabestreams mit einer kleineren Kapazität initialisiert wird.
  2. Am Ende des Prozesses, in dem die Ausgabe bearbeitet wird.

Den ersten Ansatzpunkt habe ich verworfen, da die Größe des komprimierten Inhalts nicht genau vorhergesagt werden kann. Auch beim Versuch der Initialisierung mit einer Kapazität die klein genug ist, wurde im Test oft genug die Ausgabe mit 256 Bytes im Array erzeugt.

Zur Umsetzung des zweiten Ansatzpunkts, habe ich mich für eine Erweiterungsmethode entschieden, die ähnlich wie die TrimEnd-Methode der String-Klasse, alle nachgestellten 0-Byte-Zeichen aus dem Ausgabe-Array entfernt.

internal static byte[] TrimEnd(this byte[] bytes)
{
    var startLength = bytes.GetLength(0);
    var startPos = startLength - 1;
    var trimPos = startPos;
    for (int i = startPos; i > -1; i--)
    {
        if (bytes[i] > byte.MinValue)
        {
            trimPos = i;
            break;
        }
    }
    if (trimPos == startPos)
    {
        return bytes;
    }
    var trimmedLength = trimPos + 1;
    var trimmed = new byte[trimmedLength];
    Array.Copy(bytes, trimmed, trimmedLength);
    return trimmed;
}

Wenn jetzt beim Abruf des Inhalts diese Erweiterungsmethode aufgerufen wird, ist das Ergebnis jedes mal wie erwartet. Das Problem der Fragmentierung innerhalb der Datei hat sich somit erledigt.

output = outStream.GetBuffer().TrimEnd();

Fazit:

Der bewusste Verzicht auf bestehende Frameworks und Bibliotheken ist oft mit einem, manchmal deutlichem, Mehraufwand verbunden. Besonders dann, wenn unvorhergesehene Probleme oder Eigenarten auftauchen.
Andererseits verschaffen mir gerade diese unvorhersehbaren Situationen einen tieferen Einblick in die jeweilige Materie und somit meist ein besseres Verständnis für das eigentliche Problem.
Wie ich bereits weiter oben gesagt habe: Frameworks für spezielle Anforderungen sind eine feine Sache und meist auch eine große Arbeitserleichterung.
Dennoch wird es immer wieder Entwickler geben die einfach aus Neugier, was ohne sie machbar ist, darauf verzichten.

Technorati-Tags: | | |

Alexander Schmidt: JavaScript, IntelliSense und ASP.NET MVC-Sections

Ein kleines Ärgernis kommt einher mit der eigentlich gut gemeinten Funktion der Section. Sie zu nutzen ist in vielen Fällen unabdingbar und trotzdem nervig, weil die Code-Formatierung, IntelliSense usw. nicht mehr wie gewohnt arbeiten. codingfreaks zeigt eine Möglichkeit, das Problem zu umgehen. Worum gehts eigentlich? Einer der Faktoren, der die Nutzung von ASP.NET MVC so [...]

Holger Schwichtenberg: Async und Await – auch in .NET 4.0 möglich!

Das Erweiterungspaket Microsoft.Bcl.Async erlaubt asynchrone Programmier-Features für ältere Plattformen, namentlich .NET Framework 4.0, Silverlight 4 und Windows Phone 7.5.

Sascha Dittmann: Windows Azure Mobile Services - Busy Indicator für Windows Store Apps

Windows Azure Mobile Services - Busy IndicatorNichts ist schlimmer für den Benutzer einer Anwendung bzw. App, als vor dem Gerät zu sitzen und nichts scheint zu passieren.
Deshalb wird heute die "Let's Talk" Windows Store App mit einem Busy Indicator erweitert.
Wer neu zu meiner WIndows Azure Mobile Services Serie hinzugekommen ist, sollte sich vorher jedoch ansehen wie der Mobile Service angelegt, die Windows Store App erstellt und eine serverseitige Eingabevalidierung implementiert worden ist...

Ein HttpMessageHandler für den Busy Indicator

Um sich in die Client-Server Kommunikation des MobileServiceClient-Objektes einklinken zu können, muss zuerst eine Klasse erstellt werden, die von der abstrakten Klasse HttpMessageHandler ableitet.

Genauer gesagt muss diese neue Klasse von der DelegatingHandler-Klasse ableiten, da sie in ihrer SendAsync-Methode wiederum SendAsync aufrufen muss.

Somit erreicht man den gewünschten Effekt, dass die Nachrichten nur durchgereicht und nicht endgültig verarbeitet werden.

Eine einfache Variante des Busy-Handlers könnte dann wie folgt aussehen: 

public class BusyHandler : DelegatingHandler
{
  private int _callCount;
  private readonly Action<bool> _busyIndicator;

  public BusyHandler(Action<bool> busyIndicator)
  {
    _busyIndicator = busyIndicator;
  }

  protected override async Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    // update the count by one in a single atomic operation. 
    // If we get a 1 back, we know we just went 'busy'
    var outgoingCount = Interlocked.Increment(ref _callCount);
    if (outgoingCount == 1)
    {
      _busyIndicator(true);
    }

    var response = await base.SendAsync(request, cancellationToken);

    // decrement the count by one in a single atomic operation.
    // If we get a 0 back, we know we just went 'idle'
    var incomingCount = Interlocked.Decrement(ref _callCount);
    if (incomingCount == 0)
    {
      _busyIndicator(false);
    }

    return response;
  }
}

 

Änderungen am ViewModel

Damit in der View der Busy Indicator ein- bzw. ausgeblendet werden kann, muss als nächstes das ViewModel entsprechend erweitert werden.

Dazu habe ich eine IsBusy-Eigenschaft im Interface hinzugefügt ...

public interface IMainPageViewModel
{
  ObservableCollection Messages { get; }
  String MessageText { get; set; }
  Message SelectedMessage { get; set; }

  Boolean IsBusy { get; }

  DelegateCommand SendMessageCommand { get; }
  DelegateCommand DeleteMessageCommand { get; }
  DelegateCommand RefreshCommand { get; }
}

 

... und diese entsprechend implementiert.

private Boolean _isBusy;
public Boolean IsBusy
{
  get { return _isBusy; }
  set { SetProperty(ref _isBusy, value); }
}

 

Danach kann der BusyHandler zur Kommunikationspipeline des MobileServiceClient-Objektes hinzugefügt werden.

Dazu stellt die MobileServiceClient-Klasse den entsprechenden Konstruktor zur Verfügung:

_mobileServiceClient = new MobileServiceClient(
  App.MobileServiceUrl,
  App.MobileServiceKey,
  new BusyHandler(busy => IsBusy = busy));

 

Änderungen an der View

Zu guter Letzt muss in der View nur noch der entsprechende XAML Code hinzugefügt und an die IsBusy-Eigenschaft des ViewModels gebunden werden:

<Border Grid.ColumnSpan="2" Grid.RowSpan="3" 
        Visibility="{Binding IsBusy, 
        Converter={StaticResource BooleanToVisibilityConverter}}">
  <ProgressRing IsActive="true" Style="{StaticResource ProgressRingStyle}" />
</Border>

 

Für lesbareren Code, und zur Wiederverwendbarkeit in weiteren Views, bietet sich außerdem an die Style-Einstellungen des ProgressRing-Controls auszulagern:

<Style x:Name="ProgressRingStyle"  TargetType="ProgressRing">
  <Setter Property="HorizontalAlignment" Value="Center" />
  <Setter Property="VerticalAlignment" Value="Center" />
  <Setter Property="Foreground" Value="{StaticResource AccentColor}" />
  <Setter Property="Width" Value="100" />
  <Setter Property="Height" Value="100" />
</Style>

 

Wie geht es weiter?

Im nächsten Teil dieser Serie wird die Windows Store App mit einer Microsoft-Account-Authentifizierung erweitert.
Außerdem werden die Benutzer nur noch ihre eigenen Nachrichten löschen können.

 


Weitere Informationen Beispielanwendung:

Weitere Informationen:

Verwendete Bildquellen:
© Corinna Dumat / PIXELIO

Martin Richter: Kostenlose CPPDepends Lizenz für Open Source Entwickler

Ich hatte ja schon mehrfach in meinem Blog auf CPPDepend hingewiesen. Ein tolles Tool für die Code Analyse.

Jetzt gibt es eine kostenlose Version für alle Open-Source-Entwickler.
Mehr dazu findet sich in diesem Link, schaut einmal selbst ob die Lizenzbedingungen für Euch in Frage kommen könnten.

Um in den Genuss einer solchen Lizenz zu kommen muss man eigentlich nur seinen Namen und den Link auf das Projekt an Support@cppdepend.com senden. Einfacher geht es nicht ;)


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

Martin Hey: Goodbye MDI mit Excel 2013

Ich habe recht häufig den Fall, dass ich zwei Arbeitsblätter nebeneinander liegen haben musste, um diese zu vergleichen. In den letzten Versionen war es es so, dass beim Doppelklick auf eine Datei die mit Excel verknüpft war (*.xlsx, *.csv usw.) diese Datei brav geöffnet wurde, aber dummerweise immer in dem bereits bestehenden Excel-Hauptfenster. Da helfen mir auch die beiden Monitore und der erweiterte Desktop nicht viel. Besonders ärgerlich ist das, da ausnahmslos alle anderen Office-Programme sich hier genau wie erwartet verhielten und ein neues Hauptfenster öffneten.

Vor kurzen habe auch ich den Schritt gewagt und auf Office 2013 aktualisiert. Positiv überrascht war ich, als ich nun wieder genau den "Fehler" machte und einen Doppelklick auf eine Excel-Datei ausführte und mich seelisch schon darauf einstellte, wieder das bekannte Problem zu erleben... aber nein, es öffnete sich ein weiteres Excel-Fenster, welches ich frei positionieren konnte. Kleine Änderung, große Wirkung.

Kay Giza [MS]: Mythbuster: 10 Mythen und Irrtuemer ueber Office 365 fuer Privatanwender

Basierend auf meinem Blogposting 'Mythos entzaubert: Microsoft Update, Windows Update, Office Update' hatte ich eigentlich vor, die häufigsten Irrtürmer und Mythen rund um Office 365 hier zu posten. Mein Kollege Stephan Fasshauer hat dies nun wunderbar aufbereitet und dargelegt. Kudos wem Sie gebühren! Sie haben vielleicht auch die gleichen Fragen und brauchen Antworten? Beispielsweise: 'Online-Office' – Office 365 ist nur im Web-Browser verfügbar oder erfordert eine ständige Internetverbindung? Oder: PC-Bindung – Das neue Office ist an meinen PC gefesselt und kann nur einmal installiert werden... [... mehr Informationen in diesem Blogposting auf Giza-Blog.de]


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

Sascha Dittmann: Windows Azure Mobile Services - Eingabevalidierung mittels Tabellenskript

Windows Azure Mobile Services - CRUD für Windows Store AppsIn den bisherigen Teilen meiner Windows Azure Mobile Services Serie wurde ein Mobile Service angelegt und eine Windows Store App erstellt, die ihre Daten in der Cloud persistiert.
In diesem Blog Post geht es um die Eingabevalidierung mittels Tabellenskript...

Bislang akzeptiert der "Let's Talk" Dienst jede Nachricht, die von einer App gesendet wird.
Dabei ist es egal aus wie vielen Zeichen diese Nachricht besteht.

Durch eine serverseitige Validierung möchte ich allerdings verhindern, dass Nachrichten persistiert werden, die weniger als 2 Zeichen lang sind.

Eine Möglichkeit dies umzusetzen sind Tabellenskripte.

 

Tabellenskripte

Tabellenskripte sind JavaScript-Funktionen, die für jede CRUD-Operation der Mobile Services ausgeführt werden.

Sobald man in die Detailansicht einer Tabelle wechselt, kann man im SCRIPT-Bereich die einzelnen Skripte bearbeiten:

Windows Azure Mobile Services - Tabellenskripte

Datenvalidierung im Insert-Skript

Für die Datenvalidierung der Nachrichten öffnet man zuerst das Insert-Skript der Messages-Tabelle.

Dieses besteht zu Beginn nur aus dem Execute-Methodenaufruf des Request-Objektes:

function insert(item, user, request) {

    request.execute();

}

 

Des weiteren werden über die Funktionsparameter das zu persistierende Objekt (item) und der angemeldete Benutzer (user) übergeben.

Um die Body-Eigenschaft des Message-Objektes zu validieren genügt eine einfache If-Abfrage, die im Fehlerfall den Statuscode 400 (Bad Request) und eine entsprechende Fehlermeldung zurück gibt.

if (!item.body || item.body.length < 2) {
  request.respond(statusCodes.BAD_REQUEST, 
    'The message text must be 2 or more characters long.');
  return;
}

 

Die Mobile Services stellen dabei ein hilfreiches Objekt (statusCodes) zur Verfügung, welches die Http-Statuscodes enthält und so zur besseren Lesbarkeit des Codes beiträgt:

{
  OK: 200,
  CREATED: 201,
  ACCEPTED: 202,
  NO_CONTENT: 204,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  CONFLICT: 409,
  INTERNAL_SERVER_ERROR: 500,
  isValid: [Function]
}

 

Außerdem kann man im Insert-Skript natürlich auch das Item-Objekt aktualisieren bzw. erweitern.

Somit kann beispielweise die CreatedAt-Eigentschaft des Nachrichtenobjektes mit dem serverseitigen Zeitstempel versehen werden.

Das fertige Skript sieht dann wie folgt aus:

function insert(item, user, request) {
  if (!item.body || item.body.length < 2) {
    request.respond(statusCodes.BAD_REQUEST, 
      'The message text must be 2 or more characters long.');
    return;
  }

  item.createdAt = new Date();

  request.execute();
}

 

Wenn von der App jetzt eine Nachricht ohne Inhalt bzw. mit nur einem Zeichen gesendet wird, erhält der Benutzer die gewünschte Fehlermeldung:

Windows Azure Mobile Service - Fehlermeldung vom Tabellenskript

 

Wie geht es weiter?

Im kommenden Teil dieser Serie wird die Windows Store App mit einem Busy-Indicator erweitert, der dem Benutzer anzeigt wird sobald die App mit den Mobile Services kommuniziert.

 


Weitere Informationen Beispielanwendung:

Weitere Informationen:

Swiss DPE Team [MS]: Unzählige Gründe für die TechEd 2013 in Madrid

Der Frühbucherrabatt für die diesjährige TechEd 2013 in Madrid vom 25. – 28. Juni ist zwar schon durch, doch mittlerweile sind die Sessions und noch einige andere Extras bekannt. So werden 13 verschiedene Pre-Conference Seminare stattfinden. Besuchen Sie diese eintägigen, vollgepackten Seminare, um von den vertieften und praxisnahen Erfahrungen der Industrie-Experten zu lernen. Ausserdem erhalten alle Teilnehmer der TechEd 2013 einen exklusiven 50%-Rabatt für die Microsoft Certification Exams!

teched_EU_468x60_CH_v1

Teilnehmer sind nicht nur Zuhörer und lernen die aktuellsten Technologie-Trends kennen, sondern können gleich vor Ort mit den Experten ihre Interessen und Wissen in den Hands-on Labs und Technical Learning Centers vertiefen. Folgende neun Tracks werden im Zentrum der Konferenz stehen:

  • Architecture & Trustworthy Computing
  • Data Platform & Business Intelligence
  • Developer Tools & Application Lifecycle Management (ALM)
  • Modern Datacenter
  • Office 365 & Unified Communications
  • SharePoint & Enterprise Social
  • Windows Azure Application Development
  • Windows Client, Access & Managementv
  • Windows Phone

Jetzt anmelden und sein Wissen in vier Tagen updaten!

codefest.at [MS]: Persistente Datenspeicherung für Windows 8 Apps in HTML5/Javascript

In diesem Tutorial soll gezeigt werden, wie Daten in einer Windows 8 App mittels IndexedDB gespeichert und wieder ausgelesen werden können. Als Beispiel dient dazu eine einfache Benutzerverwaltungs-App, mit der Benutzer angelegt und wieder gelöscht werden.

Ein kurzer Überblick über IndexedDB

Im Zuge der immer vielfältigeren Möglichkeiten, die mit klassischen Webapplikationen geschaffen werden können, wurden auch Stimmen nach effizienten clientseitige Speichermöglichkeiten laut. Bis dato war die persistente Datenspeicherung hier so gut wie gar nicht möglich: Lediglich Cookies erlaubten das Schreiben und Lesen von Parametern. Diese waren aber allein schon aufgrund der geringen erlaubten Speichergröße maximal für einige zu speichernden Einstellungen auf Webseiten zu gebrauchen. Mozilla wagte hier einen Vorstoß und führte als eine der Ersten für ihren Browser eine Index-basierte Datenbank ein. Schließlich wurde die Spezifikation für eine solche Datenbank vor gut einem Jahr vom W3-Konsortium verabschiedet und ist offiziell Bestandteil von HTML5.

Verwendet werden kann IndexedDB nicht nur mit Browsern wie Internet Explorer 10, Chrome oder Firefox sondern dank der weitreichenden HTML5-Unterstützung auch mit Windows 8!

Schritt 1: Projekt öffnen und vorbereiten

Zunächst öffnen wir in Visual Studio 2012 ein neues Projekt und wählen den Unterpunkt JavaScript > Windows Store > Navigations-App aus. (Hinweis: Wer neu in der Welt der HTML5/Javascript-Apps ist, mag sich als Einstieg vielleicht zuvor dieses Tutorial ansehen)

01_start

Ist das Projekt angelegt, navigieren wir in den Ordner pages/home und öffnen home.html. Dort ändern wir zunächst den style von ui-dark.css auf ui-light.css, schreiben im span-tag der Klasse “pagetitle” “Benutzerverwaltung” statt “Willkommen bei DBSample” und löschen die Zeile “Hier Inhalt einfügen” zwischen den <p></p>-Tags.

02_vorbereitung

Als nächstes fügen wir die AppBar hinzu, die sich bei einem Rechtsklick in die App bzw. auf Touch-Devices von einer Wischbewegung vom unteren Rand nach oben öffnet. Dazu kopieren wir folgenden Code und fügen ihn in die home.html-Datei knapp über dem </body>-Tag ein:

    <div id="appbar" data-win-control="WinJS.UI.AppBar">
                <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'removeUser', 
label:'Löschen', icon:'delete'}" type="button"></button>

<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'addUser', label:'Neu',
icon:'add'}" type="button"></button>

    </div>

Wenn wir nun auf F5 klicken um die App zu starten und danach mit dem rechten Maustaste in die App klicken, sollte sich die noch funktionslose AppBar öffnen. Um die AppBar zu stylen, können wir uns übrigens der .win-appbar-property bedienen. Um den AppBar-Hintergrund grau zu färben, kopiere man nachfolgenden Code in die home.css-Datei:

.win-appbar {
    background-color: #CCCCCC;
}

Im nächsten Schritt legen wir ein Fenster an, das sich öffnet, wenn der User auf den “Neu”-Button in der AppBar klickt. Dazu schreiben wir ein <div>, in dem sich Text-inputs sowie Buttons befinden. Diesen Code fügen wir gleich nach dem <body>-Tag in home.html hinzu:

    <div id="addDiv">
        <h2>Neuen Benutzer hinzufügen</h2><p></p>
        <table>
            <tr><td>Name:</td><td><input type="text" id="username" /></td></tr>
            <tr><td>Alter:</td><td><input type="number" id="age"/></td></tr>
            <tr><td>Typ:</td><td><select id="type"><option>User</option><option>Administrator</option>
</select></td></tr>
        </table>
        <p></p>

<input type="button" id="addEntry" value="Eintragen"/> <input type="button" id="close"
value="Schließen"/>

    </div>

Um das <div> mittig auszurichten, kopiere man folgenden Code in die home.css-Datei:

#addDiv {
     color:black;
     display:none;
     height:250px;
     position: absolute;
     width:530px; 
     z-index: 50;
     border: 5px solid grey;
     top: 50%;
     left: 50%;
     margin-top: -125px;
     margin-left: -287px;
     background-color:white;
     font-size:20px;
     padding-top:20px;
     padding-left:20px;
}

Das div wird zunächst nicht angezeigt (display:none;), kümmern wie uns nun um den Öffnen/Schließen-Mechanismus. Dazu öffnen wir die home.js-Datei. In Zeile 7 sehen wir den Eintrag “ready: function (element, options)”. In dieser Funktion wird die Seite initialisiert, hier werden wir auch unsere EventListener anlegen, damit bei Klicks auf die Buttons der AppBar das Fenster geöffnet wird. In dieser Funktion legen wir die folgenden drei EventListener an:

document.getElementById("addEntry").addEventListener("click", addEntry);
document.getElementById("close").addEventListener("click", closeWindow);
document.getElementById("addUser").addEventListener("click", openWindow);

Wird auf den Button mit der ID “addEntry” geklickt, wird die Funktion addEntry ausgeführt; Äquivalentes gilt für die anderen zwei Listener.
Legen wir nun die openWindow() und closeWindow() Funktionen an. Wir kopieren den nachfolgenden Code und fügen ihn kurz nach der WinJS.UI.Pages.define-Funktion ein.

    function openWindow() {
        document.getElementById("appbar").winControl.hide();
        var elm = document.getElementById("addDiv");
        elm.style.display = "block";
        WinJS.UI.Animation.fadeIn(elm);
    }
 
    function closeWindow() {
        var elm = document.getElementById("addDiv");
        elm.style.display = "none";
    }

Unsere home.js Datei sollte bis jetzt wie folgt aussehen:

03_homejs 

Detail am Rande: In der openWindow-Funktion bedienen wir uns der von WinJS bereitgestellten fadeIn-Funktion um einen Fade-Effekt zu erzeugen. Eine Fade-Out-Animation gibt es auch – fadeOut heißt hier das Pendant.

Wenn wir nun auf den “Neu”-Button in unserer AppBar klicken, wird unser div geöffnet, die sich zentriert in der Bildschirmmitte befindet:

04_screen

Schritt 2: Datenbank anlegen

Mit IndexedDB werden Objekte in Form eines key-value-pairs gespeichert, am häufigsten wird zu diesem Zweck die JSON- Notation verwendet. Würden wir mit einer relationalen Datenbank arbeiten, müssten wir für unsere Benutzerverwaltung zunächst die Datenbank erstellen. Das könnte für relationale Datenbanken in MySQL etwa so aussehen:

CREATE DATABASE userDatabase;

In unserer IndexedDB legen wir eine Datenbank wie folgt an:

var request = window.indexedDB.open("userDatabase ", 1);

Der erste Parameter ist der Datenbankname, der zweite gibt die Versionsnummer an (immer wenn sich das Datenbankschema ändert, muss sich auch die Versionsnummer ändern). Die open()-Funktion selbst retourniert ein Request-Objekt, das mehrere Zustände beschreiben kann: Success, Error, Blocked und UpgradeNeeded wobei letzterer Zustand immer dann aufgerufen wird, wenn sich die Versionsnummer ändert.
Um die Datenbank anlegen bzw öffnen zu können, fügen wir folgende Funktion kurz oberhalb von openWindow in home.js ein:

    var db = null;
    function openDatabase() {
        var dbRequest = window.indexedDB.open("userDatabase", 1);
        dbRequest.onerror = function () { console.log("Fehler beim Erstellen der Datenbank"); };
        dbRequest.onblocked = function () { console.log("Datenbank blockiert"); };
 
        dbRequest.onsuccess = function (evt) {
            db = evt.target.result;
            showEntries();
        };
 
        dbRequest.onupgradeneeded = function (evt) {
            if (db) {
                db.close();
            }
            db = evt.target.result;
            var txn = evt.target.transaction;
            var bookStore = db.createObjectStore("userlist", { keyPath: "id", autoIncrement: true });
            bookStore.createIndex("username", "username", { unique: false });
 
            txn.oncomplete = function () { };
        };
    }
 
    function showEntries() {
 
    }

Die openDatabse()-Funktion soll bei der Initialisierung der Seite aufgerufen werden, wir fügen daher den Eintrag

openDatabase();

kurz unterhalb des EventListeners

document.getElementById("addUser").addEventListener("click", openWindow);

hinzu.

In relationalen Datenbanken würden wir im nächsten Schritt das Datenbankschema in SQL anlegen, was (in MySQL) etwa so aussehen könnte:

CREATE TABLE user (
  id INT PRIMARY KEY,
  username VARCHAR(40) ,
  age INT,
  type ENUM(‘Administrator’, ‘User’)
);

Mit diesem Code legen wir also eine Tabelle an, in die wir nun Daten ablegen können. Mit IndexedDB kreieren wir im Unterschied dazu Objekt-Storages. Das ist nichts anderes als ein Speicherplatz mit einem zugewiesenen Namen, in den Objekte (als key-value-pair) abgelegt werden können. Ein “richtiges” Schema für Tabellen wie bei relationalen Datenbanken gibt es hierbei nicht. Der entsprechende Code um ein solches Objekt-Storage für die Benutzerverwaltung anzulegen, könnte in etwa wie folgt aussehen:

db.createObjectStore("users",{keyPath: "id"});

keypath gibt hierbei jenen value an, mit der der Datensatz eindeutig identifiziert werden kann.

Unsere Datenbank steht nun bereit um Daten aufzunehmen, fügen wir nun eine Funktion addEntry() hinzu. Diese können wir oberhalb von openDatabase einfügen:

    var user = new WinJS.Binding.List();
    WinJS.Namespace.define("UserList", {
        user: user
    });
 
    function addEntry() {
 
        var username = document.getElementById("username").value
        var age = document.getElementById("age").value
        var type = document.getElementById("type").value
        var id = 0;
 
        if (user.length != 0) {
            user.dataSource.itemFromIndex(user.length - 1).done(function (item) {
                id = item.data.id + 1;
            });
        }
 
        var item = { "id": id, "username": username, "age": age, "type": type, "picture": 
"/images/user.png" };
 
        var transaction = db.transaction("userlist", "readwrite");
        var addRequest = transaction.objectStore("userlist").add(item);
        addRequest.onsuccess = function (evt) {
            user.push(item);
        }
        closeWindow();
    }

 

Um Daten löschen zu können, legen wir nun in der home.js-Datei einen weiteren EventListener in der ready-Funktion an:

document.getElementById("removeUser").addEventListener("click", deleteEntry);

… die zugehörige deleteEntry()-Funktion sieht so aus, diese kopieren wir unter die addEntry-Funktion:

    function deleteEntry() {
        var listView = document.getElementById("itemsListView").winControl;
 
        listView.selection.getItems().done(function (currentSelection) {
            currentSelection.forEach(function (selectedItem) {
 
                var dbKey = selectedItem.data.id;
                var listViewKey = selectedItem.key;
                
                var transaction = db.transaction("userlist", "readwrite");
                var deleteRequest = transaction.objectStore("userlist").delete(dbKey);
 
                deleteRequest.onsuccess = function () {
                    user.dataSource.remove(listViewKey);
                }
                deleteRequest.onerror = function () {
                }
            });
        });
        document.getElementById("appbar").winControl.hide();
    }



Schritt 3: ListView erstellen

Im letzten Schritt haben wir unter anderem die Zeile

var user = new WinJS.Binding.List();

hinzugefügt. Diese so definierte Liste “user” verwenden wir, um darin alle Benutzer zu speichern, die wir aus der Datenbank auslesen um diese schließlich zu unserer ListView hinzuzufügen. Die ListView selbst ist nichts anderes als eine von WinJS zur Verfügung gestellte control um eine Ansammlung an Items im Sinne des "Modern UI” anzuzeigen.
Um unsere Liste “user” beim Initialisieren zunächst mit den Daten aus der Datenbank zu füllen, ersetzen wir die leere showEntries()-Funktion, die sich bereits in unserer home.js-Datei befindet, mit folgendem Code:

    function showEntries() {
        if (db) {
            var request = [];
            var transaction = db.transaction("userlist", "readonly");
            var store = transaction.objectStore("userlist");
 
            var index = store.index("username");
            index.openCursor().onsuccess = function (event) {
                var cursor = event.target.result;
                if (cursor) {
                    user.dataSource.insertAtEnd(null, cursor.value);
                    cursor.continue();
                }
            };
        }
    }
 

Nun müssen wir unsere Liste “user” allerdings auch anzeigen. Zu diesem Zweck fügen wir den folgenden Code in unsere home.html-Datei kurz nach “<section aria-label="Main content" role="main">” hinzu:

        <div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
        <div class="mediumListIconTextItem">
        <img src="#" class="mediumListIconTextItem-Image" data-win-bind="src: picture" />
                <div class="mediumListIconTextItem-Detail">
                    <b>Username:</b> <span data-win-bind="innerText: username"></span><br />
                    <b>Alter:</b> <span data-win-bind="innerText: age"></span><br />
                    <b>Accounttyp:</b> <span data-win-bind="innerText: type"></span>
                </div>
            </div>
        </div>
        <div id="itemsListView" data-win-control="WinJS.UI.ListView" 
            data-win-options="{itemDataSource : UserList.user.dataSource, 
                itemTemplate: select('#mediumListIconTextTemplate')}">
        </div>

Hier wird die ListView angelegt und mit einem entsprechenden Template versehen, sodass unsere Daten formatiert ausgegeben werden. Wenn wir die App testen, auf “Neu” klicken und einen Benutzer anlegen, können wir schon Einträge speichern, allerdings sieht der Eintrag noch etwas unfömig aus. Um das zu ändern, fügen wir zunächst folgendes Bild in den /image-Folder hinzu:

user

Außerdem fügen wir folgenden Code in unsere home.css ein:

#itemsListView {
    height: calc(100% - 80px);
    width:calc(100% - 90px);
    border: 0px solid red;
}
 
#itemsListView .win-container:not(.footprint):not(.hover)
{
    background-color: transparent;
    color:black;
    border: 1px solid gray;
}
 
.mediumListIconTextItem
{
    width: 282px;
    height: 70px;
    padding: 5px;
    overflow: hidden;
    display: -ms-grid;
}
 
    .mediumListIconTextItem img.mediumListIconTextItem-Image 
    {
        width: 60px;
        height: 60px;
        margin: 5px;
        -ms-grid-column: 1;
    }
 
    .mediumListIconTextItem .mediumListIconTextItem-Detail
    {
        margin: 5px;
        -ms-grid-column: 2;
    }

Mit diesem Schritt sind wir bereits fertig: Wir können nun Benutzer hinzufügen indem wir in der AppBar auf “Neu” klicken. Wenn wir Benutzer löschen wollen, klicken wir mit der rechten Maustaste auf die jeweiligen Einträge um sie auszuwählen und dann nochmals mit der rechten Maustaste um auf den “Löschen”-Button klicken zu können.

05_fertig

Ein nettes Feature wäre noch, wenn sich bei einer Auswahl an Einträgen die AppBar automatisch öffnet, diese Funktion fügen wir im finalen Schritt 4 noch hinzu.

Schritt 4: Öffnen der AppBar durch selectionchanged-Events

Zunächst fügen wir wieder einen EventListener in der ready-Funktion in home.js ein:

document.getElementById("itemsListView").winControl.addEventListener("selectionchanged", changedSelection);

Danach fügen wir die nachfolgende changedSelection-Funktion zB unterhalb von deleteEntry hinzu:

    function changedSelection(eventObject) {
        document.getElementById("appbar").winControl.show();
    }

In Worten gesprochen passiert hier folgendes: Immer dann, wenn sich die aktuelle Auswahl (Rechtsklick) der itemsListView ändert, öffnet sich die AppBar.
Den Quellcode dieses Projekts gibt es auf http://www.wissen-kompakt.at/codefest/DBSample.zip zum Download!


Los gehts!

Dieses Tutorial ist nur ein Einstiegspunkt für weitere eigene Entwicklungen. Die Möglichkeiten, diese App zu erweitern sind unbegrenzt und reichen zB von einem FilePicker, um statt dem User-Platzhalter-Icon Fotos von Benutzern zu speichern, bis hin zu automatischer Datensynchronisation, um auf allen Geräten stets den gleichen Datenstand zu haben.

Nur empfehlen kann man abschließend die umfangreichen Dokumentationen und Codebeispiele auf msdn.microsoft.com, die einen tieferen Einblick in die Materie bieten.

codefest.at [MS]: Windows Azure SDK 2.0 for .NET

Ganz frisch ist das Windows Azure SDK 2.0 für .NET, siehe auch Announcing the release of Windows Azure SDK 2.0 for .NET in ScottGu´s Blog.

In diesem Update sind viele neue Features enthalten, so etwa wurde das Visual Studio Tooling für Website Publishing, Verwaltung und Diagnose erneuert, das Handling von Cloud Services wurde verbessert und ist nun schneller, es bietet Unterstützung für Storage Client 2.0 und – etwas, was mich sehr freut – es gibt Support für Storage Tables Services im Visual Studio Server Explorer, in Service Bus können Messages nun angesehen (browsing) werden und es gibt erweiterte PowerShell Unterstützung um Web Sites, Cloud Services und VMs zu automatisieren.

Am einfachsten erfolgt die Installation über den Web Platform Installer.
Direkt folgt der Web-Installer für VS2012 über http://go.microsoft.com/fwlink/?LinkID=296343,
für VS 2010 SP1 über http://go.microsoft.com/fwlink/?LinkID=296344.

azure-sdk-2-wpi-install

Im SDK sind folgende Komponenten enthalten:

azure-sdk-2-installed-modules

Nach wenigen Minuten ist das Setup durchgelaufen.

azure-sdk-2-finished

Das Azure SDK for .NET 2.0 kann auch über http://www.windowsazure.com/en-us/develop/net/ bezogen werden und ist als Open Source Projekt auf https://github.com/WindowsAzure/azure-sdk-for-net verfügbar.

Einzeln sind die Module von http://www.microsoft.com/de-de/download/details.aspx?id=38797 downloadbar.

Die Neuerungen im Detail beschreibt ScottGu schön in seinem Blogpost.

Viel Spaß mit dem neuen Azure SDK und beim Ausprobieren der neuen Funktionen!

ppedv Team Blog: CDN mit ASP.NET Scriptmanager

Performance, Performance hallt es durch die Hallen. Wenn man sich allerdings mit Fiddler die Details von Websites und Services ansieht wird man eher Waste, Waste, Waste rufen. Mich wundert es das die Grünen nicht schon lange eine Steuer auf Prozessortakte oder DSL Bits erheben wollen. Verbraucht alles Energieund erzeugt CO2.

Die beiden einfachsten Maßnahmen für einen Web Developer sind httpcompression und CDN (Content Delivery Network).  Bei CDN wird ein Konzept der Shared Ressources gefahren. Eine Resource die zwei Websites brauchen wird geteilt und so nur einmal in den Browser Cache geladen. Wenn man dazu eine öffentliche URL nimmt und alle Menschen dies tun reduziert das nochmals Rechenleistung, eventuell Bandbreite durch Caching. Solche CND Dienste bieten Google und Microsoft. Wenn die Website also nun die sehr verbreitete JQuery Java Script Library verwendet wird sie von einem CDN Server geladen. Dies geschieht meist ein wenig schneller, weil diese Server sehr gut angebunden sind. Wesentlich relevanter ist aber wenn der Benutzer eine andere Website aufruft die ebenfalls Jquery, logischerweise mit der gleichen CDN Referenz, verwendet. Dann wird gar nichts geladen, die Scripte kommen aus dem Browser Cache.

In ASP.NET gibt es den ScriptManager der das Management übernimmt. Zunächst wird eine mini JS Datei erzeugt mit dem Namen hannes.js.

   1:  window.Hannes = (function( ) {
   2:   
   3:      return "hannes";
   4:      })

Visual Studio kann auch die minimierte Versionen erzeugen und vor allem aktuell halten. Rechtclick auf js, Webtools, minifiy JS.

image

Wenn man nun in hannes.js eine Code Änderung vornimmt, wird die min Datei automatisch geändert.

Um diese Dateien einzubinden wird das ASP.NET Scriptmanager Control eingefügt. In der Praxis vermutlich in die Masterpage.

   1:  <asp:ScriptManager ID="ScriptManager1" runat="server" EnableCdn="true" 
EnableCdnFallback="true"
   2:               AjaxFrameworkMode="Disabled">
   3:              <Scripts>
   4:                  <asp:ScriptReference Name="hannes" />
   5:   
   6:              </Scripts>
   7:          </asp:ScriptManager>
   8:   
   9:          <div id="hannesdiv">
  10:          </div>
  11:          <script>
  12:              document.getElementById("hannesdiv").innerText = window.Hannes();
  13:          </script>

Mit dem Attribut AjaxFrameworksMode wird verhindert das einige Microsoft Scripte (Stichwort Webbundle) geladen werden, die wir hier nicht brauchen. Relevant sind die beiden anderen Attribute mit CDN.

Wie im Code zu sehen ist wird das Script per Namen und nicht per Dateinamen referenziert (was auch möglich ist für klassisches JavaScript einbinden).

Die Script Referenz Hannes muss als Ressourcemapping definiert werden. Dazu erfinden wir ein eigenes CDN auf einem unser WebServerzu Demozwecken. Es werden Referenzen zur Debugversion  (web.config debug=true), lokalen Fallback Version und zum ppedv CDN definiert. Der Ausdruck LoadSuccessExpression wird später verwendet um den Fallback im Browser zu realisieren (Achtung Case Sensitiv)

   1:   Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   2:          Dim Mapping = ScriptManager.ScriptResourceMapping
   3:          Mapping.AddDefinition("hannes", New ScriptResourceDefinition With
   4:          {
   5:              .Path = "~/Scripts/hannes.min.js",
   6:              .DebugPath = "~/Scripts/hannes.js",
   7:              .CdnPath = "http://www.ppedv.at/scripts/hannes.min.js",
   8:              .CdnDebugPath = "http://www.ppedv.at/scripts/hannes.js",
   9:              .CdnSupportsSecureConnection = True,
  10:                  .LoadSuccessExpression = "window.Hannes"
  11:          })
  12:   
  13:      End Sub

Im Praxistest wird der Request von meinem lokalen Computer auf den IIS Express durchgeführt. Im ersten Versuch mit Wlan im zweiten ohne Internet Verbindung.

image

Der Fallback greift dann auf das lokale Script zurück, das hier kleiner erscheint. Der Grund ist, das am ppedv.at IIS 8 offensichtlich HTTP Compression für die Extension JS (noch) nicht aktiviert ist.

Im Browser HTML Quellcode kann man dann erkennen wie das funktioniert und sieht den alten Bekannten aus LoadSuccessExpression wieder.

   1:  <script src="http://www.ppedv.at/scripts/hannes.js" type="text/javascript"></script>
   2:  <script type="text/javascript">
   3:  //<![CDATA[
   4:  (window.Hannes)||document.write('<script type="text/javascript" src="Scripts/hannes.js"><\/script>');//]]>
   5:  </script>

Im echten Web Projekt wird man dann allerdings häufiger Script Referenzen auf Jquery und co finden. Einige Bundles hat Microsoft schon vorkonfiguriert.

Code-Inside Blog: Tools & Vorgehen für Entwicklung rund um OpenXml oder wie erstelle ich Office Dokumente mit .NET?

image.png

Durch meine Tätigkeit bei der  OneOffixx AG habe ich recht tiefe Einblicke in die Erstellung von Microsoft Office Dokumente mit .NET bekommen. Da das Problem “Office Dokumente per Code” zu erstellen recht verbreitet ist, schreib ich mal Empfehlungen für die ersten Schritte.

Must Have Tools

Ganz klar sollte man das Office in der jeweiligen Version installiert haben – zum Teil unterscheiden sich die Versionen. Für die meisten Fälle sollte es aber klappen, aber lieber nachprüfen bevor der Kunde sich ärgert ;) .
Wichtiger Hinweis: OpenXML benötigt keine Office Installation. Man kann es bedenkenlos z.B. auf einem Webserver nutzen.

Das OpenXML SDK und das OpenXML SDK Productivity Tool for Microsoft Office. Die aktuellste Version ist die 2.5, welches es hier zum Download gibt – wobei man erst das SDK installieren muss und danach die Tools.

Visual Studio wäre natürlich von Vorteil ;)

Ein guten XML Viewer – Notepad ist leicht nervig. Ich nutze Nodepad++ mit den XML Tools Plugin.

OpenXML ist… kompliziert…

image

Microsofts XML Spezifikation liegt “gefühlt” sehr nah an der Ur-Implementierung im binären Format – es finden sich daher oft sehr interessante Konstrukte in XML Form wieder.

Das Bild stammt zudem von dieser Seite, welche den Standard “nicht so gern hat” – ohne Wertung von meiner Seite ;)

Da der Umgang in komplexeren Dokumenten nicht so einfach wie hier dargestellt ist empfehle ich jeden folgendes Vorgehen…

 

 

 

 

 

 

 

Vorgehen: Wunsch-Dokument erstellen – OpenXML Productivity Tool – Reflect Code FTW!

Am einfachsten ist es sich sein Wunsch-Dokument in Word/Powerpoint/Excel zu erstellen (bzw. ein bestehendes in das Tool laden) und über das Productivity Tool sich den Code dazu anzeigen lassen.

image

Der erzeugte Code ist zwar “kryptisch”, funktioniert aber (im Sinne von Copy/Paste in ein neues Projekt) und nun kann man sich Stück für Stück den Code refactoren. Das Tool kann neben “Reflect Code” auch ein Diff zwischen zwei Open XML Dateien erzeugen, zum Debugging äusserst hilfreich!

Andere Herangehensweise: Das Zip mal öffnen…

Um die Struktur genauer zu verstehen ist es auch von Vorteil die docx/pptx/xlsx Datei in .zip umzubenennen und die einzelnen XML Files genauer anzuschauen:

image

Wo liegt denn die DocumentFormat.OpenXml.dll und was brauch ich noch?

Die .NET Assembly wird mit dem SDK installiert:

C:\Program Files (x86)\Open XML SDK\V2.5\lib

Das Open XML SDK setzt auf den Namespace System.IO.Packaging auf, daher benötigt man noch die WindowsBase.dll.

Das wäre es eigentlich auch schon…

Durchbeissen und Frust-Resistenzen aufbauen ;)

Happy Coding!

Thomas Schissler: Probleme beim Deploy einer neuen VM im TFS Lab Management bzw. SCVMM aus einem Template

Wenn das Deployment einer neuen VM im TFS Lab Management bzw. im SCVMM aus einem Template ewig dauert, kann möglicherweise ein Problem mit dem Product Key vorliegen. Wenn man sich im SCVMM oder Hyper-V Manager auf die VM verbindet, sieht man, dass dort eine Fehlermeldung angezeigt wird:

Windows could not parse or process the unattend answer file for pass [specialize].  The settings specified in the answer file cannot be applied.

Wenn man den Fehler bestätigt, dann bootet der Rechner neu, bringt aber wieder den selben Fehler. Bei mir hat sich herausgestellt, dass ich einen ungültigen Product key verwendet habe. Nachdem ich den Produkt Key im Template korrigiert habe, hat das Deployment einwandfrei funktioniert.

Sascha Dittmann: Windows Azure Mobile Services - CRUD für Windows Store Apps

Windows Azure Mobile Services - CRUD für Windows Store AppsNachdem letzte Woche die Mobile Services Quick Start Apps des Management Portals offiziell auf das neue SDK umgestellt wurden, konnte ich auch meine Demo Apps für dieser Blog Post Serie entsprechend anpassen.
Wenn auch deshalb etwas verzögert, kann es endlich losgehen!
Beginnen möchte mit der zentralen Datenspeicherung aus Sicht der Windows Store Apps...

Let's Talk about Mobile Services

Als durchgängige Demo dieser Mobile Services Serie sollen einfache Nachrichten-Apps dienen, denen ich den Namen "Let's Talk" gegeben habe.

Dabei sollen - soweit möglich - alle Features der Windows Azure Mobile Services vorgestellt, aber auch gängige Problemstellungen adressiert werden.

Windows Azure Mobile Services - Let's Talk

 

Die Windows Store App

Für die Windows Store Variante der "Let's Talk"-App starte ich mit einer Split App Vorlage und entferne alle unnötigen Dateien:

Visual Studio 2012 - Windows Store App Auswahl

Anschließend wird das Mobile Services SDK via NuGet hinzugefügt.

Da seit letzter Woche bereits die Pre-Release Version in den Quick Start Apps verwendet wird, und sich diese erheblich von der Stable Version unterscheidet, sollte bei NuGet der "Pre" Parameter verwendet werden:

NuGet - WindowsAzure.MobileServices

 

Model

Zum persistieren der Nachrichten wird die Model-Klasse Message hinzugefügt.

Diese besteht zu Beginn nur aus den Eigenschaften, die persistiert werden sollen.

Außerdem wird die Klasse mit dem DataTable-Attribut sowie die Eigenschaften mit dem JsonProperty-Attribut, dekoriert. 

Dies gewährleistet die korrekte JavaScript-Notation für die JSON-Serialisierung:

[DataTable("messages")]
public class Message
{
  [JsonProperty("id")]
  public int Id { get; set; }

  [JsonProperty("body")]
  public string Body { get; set; }

  [JsonProperty("createdAt")]
  public DateTime CreatedAt { get; set; }
}

 

Anschließend wird diese um die Basis-Klasse BindableBase und weitere Eigenschaften erweitert, die mit JsonIgnore dekoriert werden.

Durch diese Basis-Klasse und die veränderten Setter-Methoden, kann die Message-Klasse jetzt problemlos an eine View gebunden werden.

Das JsonIgnore-Attribut verhindert außerdem die Serialisierung der zusätzlichen Eigenschaften, die deshalb nicht in der Mobile Services Datenbank persistiert werden.

[DataTable("messages")]
public class Message : BindableBase
{
  private int _id;
  [JsonProperty("id")]
  public int Id
  {
    get { return _id; }
    set { SetProperty(ref _id, value); }
  }

  private string _body = String.Empty;
  [JsonProperty("body")]
  public string Body
  {
    get { return _body; }
    set { SetProperty(ref _body, value); }
  }

  private string _userImageUrl = "Assets/portrait.png";
  [JsonIgnore]
  public string UserImageUrl
  {
    get { return _userImageUrl; }
    set
    {
      _userImage = null;
      SetProperty(ref _userImageUrl, value);
      OnPropertyChanged("UserImage");
    }
  }

  private ImageSource _userImage;
  [JsonIgnore]
  public ImageSource UserImage
  {
    get
    {
      if (_userImage == null && _userImageUrl != null)
      {
        _userImage = new BitmapImage(new Uri(App.BaseUri, _userImageUrl));
      }
      return _userImage;
    }
    set
    {
      _userImageUrl = null;
      SetProperty(ref _userImage, value);
    }
  }

  private DateTime _createdAt = DateTime.Now;
  [JsonProperty("createdAt")]
  public DateTime CreatedAt
  {
    get { return _createdAt; }
    set { SetProperty(ref _createdAt, value); }
  }
}

 

View und ViewModel

Neben einer einfachen View (MainPage.xaml) kommt dann noch ein ViewModel auf Basis folgender Schnittstelle hinzu:

public interface IMainPageViewModel
{
  ObservableCollection<Message> Messages { get; }
  String MessageText { get; set; }
  Message SelectedMessage { get; set; }

  DelegateCommand SendMessageCommand { get; }
  DelegateCommand DeleteMessageCommand { get; }
  DelegateCommand RefreshCommand { get; }
}

 

Die wichtigen Elemente der Implementierung dieser Schnittstelle sind:

  • Ein Objekt der MobileServiceClient-Klasse, um mit den Windows Azure Mobile Services interagieren zu können
  • Ein Objekt der MobileServiceTable-Klasse zum laden und persistieren der Message-Objekte
  • Methoden zum Laden, Hinzufügen und Löschen der Message-Objekte

Zum Erstellen des MobileServiceClient-Objektes wird die URL zum Dienst und der Application Key benötigt.

Beides kann u.a. aus den Quick Start Apps herauskopiert werden:

Windows Azure Mobile Services - Connect your Windows Store App

Um ein typisiertes MobileServiceTable-Objekt zu erstellen, kann das MobileServiceClient-Objekt verwendet werden:

IMobileServiceTable _messagesTable = 
  _mobileServiceClient.GetTable<message>();

 

Damit können anschließend Daten hinzugefügt, ...

var message = new Message
{
  Body = MessageText,
  CreatedAt = DateTime.Now,
};

await _messagesTable.InsertAsync(message);

 

... geladen, ...

var messages = await _messagesTable
  .OrderByDescending(m => m.CreatedAt)
  .Take(MaxMessageCount)
  .ToListAsync();

 

... geändert, ...

await _messagesTable.UpdateAsync(message);

 

... oder gelöscht werden.

await _messagesTable.DeleteAsync(message);

 

Tabellen im Management Portal

Um die Nachrichten dann auch speichern zu können, muss auch eine Tabelle im Windows Azure Management Portal angelegt werden.

Dazu navigiert man in den Data Bereich des entsprechenden Mobile Service und klickt auf Add a Table:

Windows Azure Mobile Services - Add First Table

Im Dialog gibt man anschließend den Namen der Tabelle ein (Auf die Rechte werde ich in einem späteren Blog Post im Detail eingehen):

Windows Azure Mobile Services - Add First Table Dialog

 

Für weitere Details zu den Tabellen, kann man auf den Pfeil hinter dem Tabellennamen klicken:

Windows Azure Mobile Services - Open Table Details

Diese zeigen am Anfang natürlich keine Daten an:

Windows Azure Mobile Services - Show Table Data - No Data

Sobald allerdings Daten vorhanden sind, können diese online durchstöbert werden:

Windows Azure Mobile Services - Show Table with Data

 

Wie geht es weiter?

Im kommenden Teil dieser Serie werde ich auf die Validierung von Daten mittels Tabellenskripten eingehen.

 


Weitere Informationen Beispielanwendung:

Weitere Informationen:

friends header

bloggers headline

links header

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