Wie soll man eigentlich Profi in der Anwendung der Prinzipien und Praktiken von Clean Code Developer werden? Durch Übung :-) Und zwar zunächst einmal durch Übung an Übungen, d.h. nicht am Produktionscode des Tagesgeschäftes.
Woher aber solche Übungen nehmen? Es gibt einige Übungsvorschläge, die sog. Code Katas. Doch die sind meist sehr, sehr überschaubar. Es sind vor allem Übungen im Entwickeln
ich kann schon mal ankündigen, dass wir im Oktober wieder eine Visual Studio Evolution planen. Dort werden wir an einem Tag die aktuellsten Neuerungen zu Visual Studio, .NET und der Windows Plattform zeigen. Wir haben uns schon einiges ausgedacht. Wir halten Euch auf dem laufenden, sobald wir die Details für das Event haben.
Ich selbst werde bis zum 1. September einen verdienten Sabbatical machen und wichtige Dinge in Angriff nehmen
, mein Team wird Euch während dieser Zeit aber weiterhin aktuelle Infos über meinen Blog bereitstellen.
Letzten Dienstag habe ich im wöchentlichen Unterrichtsblock der Clean Code Developer School (ccd-school.de) “TDD as if you meant it” anhand der Kata WordWrap vorgestellt. Dann wollten die Teilnehmer es selbst probieren. Als Aufgabe habe ich die Kata ToDictionary vorgeschlagen. Leider führte die dann nicht in so geradliniger Weise zu “Refactoring-Druck”, wie ich es mir erhofft hatte. Es wollten
Visual Studio 2012 ist super. Es nimmt dem Webdeveloper viel Arbeit ab, indem standardmäßig der integrierte Webserver IISExpress verwendet wird. Beim Erstellen einer App generiert VS eine URL mit http://localhost und einer zufälligen Portnummer aus dem Pool. Soweit so gut. Nur was tun, wenn ein Webprojekt mit einer https-URL kommt – und sich IISExpress partout weigert, diese Adresse zu finden?
Mir ist es so ergangen. Man öffnet nichts ahnend ein Projekt aus dem TFS und Visual Studio beschwert sich schon beim Öffnen: “Configuring Web https://… for ASP.NET 4.5 failed. You must manually configure this site for ASP.NET 4.5 in order for the site to run correctly.”. Die Solution öffnet brav, nur ist sie nicht lauffähig.

Nein, bitte nicht! Manuell Konfigurieren ist zwar leicht möglich (siehe Scott Hanselman´s Blog: Working with SSL at Development Time is easier with IISExpress und am Blogbeitrag Ende), aber…das kann doch nicht sein, oder?
Die Properties des Webprojekts zeigen die URL und die SSL URL, in diesem Beispiel https://localhost:44303:

Wenn man nun die WebApp startet, beschwert sich Visual Studio sofort:

Klar, das Verhalten erscheint mit der Fehlermeldung beim Öffnen der WebApp logisch. Nur, wie bringe ich IISExpress dazu, mit HTTPS zu arbeiten?
Grundsätzlich entspricht IISExpress dem “großen” IIS, jedoch nur als lokaler “persönlicher” (und integrierter) Webserver. Seit Visual Studio 2010 SP1 kann IISExpress SSL verwenden (der Vorgänger Cassini konnte das noch nicht) und auf localhost Ports größer 44300 verwenden. So können Webseiten mit SSL getestet werden (jedoch nicht mit dem Standard-Port 443).
Visual Studio - und auch die freie WebMatrix - bringen eigene self-signed certificates mit. IISExpress kann somit problemlos mit HTTPS umgehen und kümmert sich automatisch um alle erforderlichen Konfigurationen. Das kann man leicht ausprobieren, wenn man ein neues Webprojekt anlegt und dort den Schalter SSL Enabled = True setzt und die https-URL in den Project Properties einträgt und startet.
Hier die Probe mit einem nigel-nagel-neuen Web:

Run zum Testen, danach SSL Enabled auf True setzen. Damit wird automatisch die SSL URL eingetragen. Beim Starten folgt natürlich noch http://localhost:49791/. Das können wir leicht ändern, indem wir einfach die https-Adresse in den Project-Eigenschaften hinterlegen: https://localhost:44301/

…und das Web mit F5 starten: VS öffnet den Browser mit der https-Adresse. Der Benutzer muss natürlich dem ausgestellten Zertifikat vertrauen und die Verwendung für diese Session zulassen:

Beim “Laden dieser Website fortsetzen” folgt dann die App. Natürlich traut der Browser dem selbst ausgestellten Zertifikat nicht – aber für unsere Development-Zwecke ist diese Lösung perfekt.

Soweit so gut – IISExpress mit HTTPS funktioniert einwandfrei mit neuen WebApps. Zurück zu unserem Projekt das nicht funktioniert…
Zuerst bemüht man zumeist die Suchmaschine seiner Wahl um herauszufinden, was das Problem ist.
Die Lösung ist aber zum Glück wirklich … einfach!
So sieht die Konfiguration zuvor aus:

Wir stellen SSL Enabled auf False: Das klappt natürlich nicht, denn die SSL-Adresse ist ja im Project hinterlegt:

Also vor dem Umstellen die http-Adresse eintragen, Projekt speichern und dann SSL Enabled = False setzen.
Nun das Projekt testweise starten – es sollte alles (mit http) klappen.
Nun wird SSL Enabled wieder auf True gesetzt.

und die (neue) SSL URL wieder in den Project Properties hinterlegt:

…und das Web zum Testen neu gestartet – diesmal mit funktionierendem https.
Eine Alternative hierzu ist, die Bindings manuell einzutragen und zwar im Pfad C:\Users\<Kontoname>\Documents\IISExpress\config. Hier liegen drei IISExpress .config-Dateien:

In applicationhost.config merkt sich IISExpress die Projekte und deren Websettings für das Hosting. Natürlich können die Bindings für die Webprojekte auch hier manuell angepasst werden:

…bzw. Webprojekt-Bindings auch bereinigt werden, was manchmal auch ganz gut ist. 
Und natürlich kann auch die .csproj Datei direkt bearbeitet werden, wo die Projekt-Adressen gespeichert sind:
<IISExpressSSLPort>44303</IISExpressSSLPort>
<IISUrl>https://localhost:44303/</IISUrl>

Wenn http- und https-Port gleich sind, beschwert sich Visual Studio. In diesem Fall einfach unterschiedliche Ports verwenden.
Die Lösung ist also einfach – aber zu Beginn gar nicht so naheliegend:
Wenn das Binding-Problem besteht, zuerst SSL wie oben ausschalten und danach wieder einschalten!
Dann sollte es mit https auch mit bestehenden (und hartnäckigen Projekten) klappen.
Nachdem bereist im März das erste PU für SharePoint 2013 erschienen ist, folgt nun das April 2013 CU.
Für das April 2013 CU muss zwingend das März 2013 PU auf dem SharePoint 2013 installiert sein. Informationen was dabei beachtet werden muss, was es für Varianten gibt und wo diese heruntergeladen werden können, findet ihr hier:
März 2013 PU
http://blogs.technet.com/b/steve_chen/archive/2013/03/22/3560441.aspx
April 2013 CU
http://blogs.technet.com/b/stefan_gossner/archive/2013/04/27/april-2013-cu-for-sharepoint-2013-has-been-released.aspx
Es wird empfohlen diese Updates zuvor auf einer Testumgebung einzuspielen, bevor es auf den produktiven SharePoint geht. Ich persönlich kann nur sagen, dass bei mir die Updates geklappt haben und ich bisher noch keine Probleme oder neue Fehler feststellen konnte. Aber das ist sicherlich nur eine Frage der Zeit
In einem älteren Blogeintrag auf codefest hatte Kollege Binder in einer umfangreichen Auflistung diverser Frameworks für Windows 8 auch das Video App Framework von Thomas Mutzl vorgestellt, mit dem sehr schnell und einfach eigene Video-Apps erstellt werden können. Ein Teil des Frameworks ermöglicht es, Youtube-Videos per RSS abzurufen und in der App abzuspielen.
Downloaden lässt sich das Framework unter dieser Adresse (Reiter “Source Code”, Spalte “Download”). Nach dem Öffnen finden sich mit einem Klick auf “Verweise” zahlreiche nicht gefundene Referenzen, was durch ein gelbes Warndreieck angezeigt wird.
Selbst wer bereits früher die hier benötigten libraries gedownloaded hat, könnte beim Compilieren Fehlermeldungen erhalten. Grund dafür ist, dass Google für Youtube gerne seine Schnittstellen ändert, was eine Anpassung zahlreicher Drittapplikationen notwendig macht. Um einen Gutteil der notwendigen Pakete automatisch zu installieren, können wir mit der rechten Maustaste auf den Ordner “Verweise” und danach auf “NuGet-Pakete verwalten” klicken.
Im sich nun öffnenden Fenster klicken wir auf “Wiederherstellen” um den Vorgang abzuschließen.
Um ein Update der bereits installierten Pakete durchzuführen, wählen wir im Menü “Tools” > “Erweiterungen und Updates”
Hier können wir entweder selbst nach Paketen suchen, die uns noch fehlen (zB den Smooth Streaming Client") oder im Feld “Updates” alle Pakete aktualisieren, falls wir bereits ältere Versionen davon besitzen.
Im letzten Schritt unseres refreshes laden wir noch die aktuelle Version des Microsoft Player Frameworks herunter und installieren es durch einen Doppelklick auf die .vsix-Datei.
Nun sollten alle Verweise korrekt aufgelöst werden und unsere App ist bereit, weiter angepasst zu werden. Es existiert eine Schritt-für-Schritt-Anleitung als Aufgabenliste, die wir mit einem Klick auf “Ansicht” > “Aufgabenliste” öffnen können.
Hier müssen wir nur noch “Benutzeraufgaben” auf “Kommentar” umschalten, um alle To-Do’s angezeigt zu bekommen. Mit einem Klick auf ein To-Do springt man automatisch an die entsprechende Stelle im Code.
Eines der wichtigsten Anpassungen ist natürlich das Einfügen der RSS-URI, der auf jenen Youtube-Channel verlinkt, der in unserer App angezeigt werden soll. Die entsprechende Variable befindet sich in der MainViewModel.cs
Um nun die benötigte RSS-Adresse zu erhalten, navigieren wir zu einem Youtube-Channel unserer Wahl und klicken in der - zuvor durch einen Rechtsklick auf die obere Leiste aktivierten - Menüleiste auf “Extras” > “Feedsuche” > “RSS”. Es öffnet sich eine neue Seite, deren URI wir kopieren und als string “RssUri” speichern.
Abschließend können wir noch Aussehen und Layout der App anpassen und danach steht einem Upload in den Storenichts mehr im Wege!
Im siebten Teil meiner Entity Framework Webcast Serie widme ich mich dem Thema Testing. Zunächst nehmen wir uns die fertigen Queries vor, welche sich auch gut ohne Datenbank testen lassen. Schließlich will nicht jeder zum Testen einer Abfrage immer eine entsprechende Datenbank hochfahren und die Daten dafür erzeugen.
Danach stellen wir in einem Mini-Business-Pseudo-Layer ein Szenario nach, welches uns dedizierte Daten für die weitere Verarbeitung liefert, sodass das Testen der Geschäftslogik ebenfalls ohne Datenbank erfolgen kann.
Als BDD Framework für die Unit Tests verwende ich Machine.Specifications und als Mocking Framework kommt FakeItEasy zum Einsatz.
Hier noch die zwei Code Beispiele:
Beispiel 1: Testen der Query
1: [Subject(typeof(GetAddressByCity))]
2: public class When_addresses_contains_exactly_one_matching_entry
3: {
4: static GetAddressByCity Sut;
5: static List<Address> Addresses;
6: static Address Actual;
7: static Address TestCity;
8:
9: Establish context = () =>
10: {
11: TestCity = new Address {City = "test city"};
12: Addresses = new List<Address>
13: {
14: new Address {City = "Karlsruhe"},
15: TestCity
16: };
17: Sut = new GetAddressByCity("test city");
18: };
19:
20: Because of = () =>
21: {
22: Actual = Sut.Execute(Addresses.AsQueryable());
23: };
24:
25: It should_return_exactly_this_address = () =>
26: Actual.ShouldEqual(TestCity);
27: }
Beispiel 2: Testen von Geschäftslogik
1: class EmployeeBusinessLogicSpecs
2: {
3: [Subject(typeof(EmployeeBusinessLogic))]
4: class When_hire_date_is_unknown
5: {
6: static IUnitOfWork Uow;
7: static EmployeeBusinessLogic Sut;
8: static Employee DummyEmployee;
9:
10: Establish context = () =>
11: {
12: DummyEmployee = new Employee {EmployeeID = 1,
13: FirstName = "Uli", LastName = "Armbruster"};
14:
15: Uow = A.Fake<IUnitOfWork>();
16:
17: A
18: .CallTo(() => Uow.ExecuteQuery(
19: A<GetEmployeeById>
20: .That
21: .Matches(q => q.EmployeeId == DummyEmployee.EmployeeID)
22: ))
23: .Returns(DummyEmployee);
24:
25: Sut = new EmployeeBusinessLogic(Uow);
26: };
27:
28: Because of = () => Sut.EnsureValidHireDate(DummyEmployee.EmployeeID);
29:
30: It should_update_it = () => DummyEmployee.HireDate.ShouldNotBeNull();
31:
32: It should_save_the_changed_hire_date = () => A
33: .CallTo(() => Uow.Commit())
34: .MustHaveHappened(Repeated.Exactly.Once);
35: }
36: }
Weitere Quellen:
Das nächste Treffen der .NET Developer Group Braunschweig findet am 29.05.2013 statt.
Karsten Samaschke wird einen Vortrag über Windows Phone 8 halten.
Windows
Phone 8: Unentdeckte Welten
Wir schreiben das Jahr 2013, und dies sind die Informationen zu Microsofts Telefonbetriebssystem.
Karsten Samaschke spricht in diesem lockeren Talk über Windows Phone 8, wie man damit
entwickelt, was es kann und was dabei mal überhaupt nicht geht. Mit euch zusammen
erkunden wir die unentdeckten Weiten dieses Systems, sprechen über Features, Geschichte,
Optionen und das liebe Geld. Beam me up, Stevie! ??
Weitere Infos unter http://www.dotnet-braunschweig.de
Um eine Versionsnummer zu vergeben, muss man sich für ein System entscheiden – bloß für welches? Jahreszahlen oder klassische Versionsnummern? Ohne oder mit Nachkommastellen? SemVer definiert einen einheitlichen und leicht verständlichen Standard.
In einem Note in meinem Blog wurde es ja auch erwähnt, das Update 2 zu Visual Studio 2012 eine Regression hat. Mit Update 1 konnte man wieder Programme bauen, die auch auf Windows XP laufen. Update 2 machte dies wieder zunichte. Jetzt ist ein RC für Update 3 verfügbar gemacht worden mit dem dieser Fehler behoben wurde.
Hier die Ankündigung im C++ Blog:
http://blogs.msdn.com/b/vcblog/archive/2013/05/07/fix-visual-studio-2012-update-2-breaks-windows-xp-targeting-with-atl-and-or-statically-linking-mfc.aspx
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)
Das HTML Menü Steuerelement steckt voller Magie. Es kann wie von Geisterhand auf und zuklappen, berücksichtigt die Rechte des angemeldeten Benutzers und kann sogar über einen Sitemapprovider Datengebunden werden. Aber Magier schlagen auch mal über die Strenge wenn sie von Ihren Fähigkeiten zu überzeugt sind und streben die totale Vernichtung an. So lernt man das jedenfalls aus Harry Potter. Der ach so nette Tom Riddle mutiert zu Voldemort, dem rachsüchtigen dunklen Magier der vor nichts zurückschreckt.
Nun bin ich kein fanatischer Verfechter von der Reinheit des Blutes und gebe auch Muggle Zauberern ihre Chance.
Ein Menü Control erzeugt Serverseitig HTML Code, samt CSS und Zauberscript. Als Startpunkt wird die Navigation der mobilen ppedv Kurs Anwendung verwendet. Zwar könnte man mit einer einfach UL LI Liste das Ziel einfacher erreichen, aber der Erkenntniswert würde fehlen. Also los geht's mit “Zaubern mit Menu”
1: <form id="form1" runat="server" data-role="page">
2: <div data-role="content">
3:
4: <div>
5: <asp:Menu ID="div1" runat="server"
6: data-role="navbar">
7: <Items>
8: <asp:MenuItem NavigateUrl="~/S/2,12,14,19" Text="Windows & .NET" />
9: <asp:MenuItem NavigateUrl="~/S/3,7" Text="Architektur&Dev" />
10: <asp:MenuItem NavigateUrl="~/S/11" Text="Web Development" />
11: <asp:MenuItem NavigateUrl="~/S/13,18,22" Text="SharePoint" />
12: <asp:MenuItem NavigateUrl="~/S/5,6,20" Text="Server Administration" />
13: <asp:MenuItem NavigateUrl="~/S/9,7" Text="Office u.a." />
14: <asp:MenuItem NavigateUrl="~/S/4,21" Text="SQL & BI" />
15: <asp:MenuItem NavigateUrl="~/kontakt" Text="Kontakt" />
16: </Items>
17: </asp:Menu>
18: </div>
19:
20: </div>
21: </form>
Vor der vierte Folge (also bis ASP.NET 3.5) wurde daraus gar furchterbarer HTML Code, der sich dabei der dunklen Künste von HTML Tables bediente.
Wer diese dunklen Zeiten wieder heraufbeschwören möchte, kann dich dunkle Kammer von Webconfig aufsuchen und dort folgenden Zauberspruch murmeln
1: <pages controlRenderingCompatibilityVersion="3.5" >
Seit der Stein der Weisen zurück nach Redmond gekehrt ist, serviert auch das Menu Control reines DIV, UL und LI, allerdings noch mit allerlei wundersamer Zutaten.
1: <form method="post" action="WebForm24.aspx" id="form1" data-role="page">
2: <div class="aspNetHidden">
3: <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="2hB6MZYCbAUooxZUPVYswq
5ZiGyg0TutsRjTuqwqOWRyoGlxBHvPvMBmA7xs3dMHYdKdBZDFZgcT75zNssO11aaJ3fOdCsoYUd3eQBY1x7c=" />
4: </div>
5:
6:
7: <script src="/WebResource.axd?d=fqV81KWLWhVg-lLAb4IT6z7dNzU96UkgnAUvd3TznA7r7jmBA8d3Ppk0
-TpQJTuNUNdLcYMr6iHiLhrQ1-FE8y8o-CmqZlIAp78DXeQ-4cw1&t=634897471112455790" type="text/javascript">
</script>
8: <div data-role="content">
9:
10: <div>
11: <a href="#div1_SkipLink" style="position:absolute;left:-10000px;
top:auto;width:1px;height:1px;overflow:hidden;">Navigationslinks überspringen</a>
<div data-role="navbar" id="div1">
12: <ul class="level1">
13: <li><a class="level1" href="S/2,12,14,19">Windows & .NET</a></li><li>
<a class="level1" href="S/3,7">Architektur&Dev</a></li><li><a class="level1" href="S/11">Web Development</a>
</li><li><a class="level1" href="S/13,18,22">SharePoint</a></li><li>
<a class="level1" href="S/5,6,20">Server Administration</a></li><li><a class="level1" href="S/9,7">
Office u.a.</a></li><li><a class="level1" href="S/4,21">SQL & BI</a></li><li>
<a class="level1" href="kontakt">Kontakt</a></li>
14: </ul>
15: </div><a id="div1_SkipLink"></a>
16: </div>
17:
18: </div>
19:
20: <script type='text/javascript'>new Sys.WebForms.Menu({ element: 'div1',
disappearAfter: 500, orientation: 'vertical', tabIndex: 0, disabled: false });</script></form>
Fügt man nun noch ein wenig Jquery Mobile Kraut hinzu, erscheint ein Fenster (Aparecium).

Allerdings hat der dunkle Lord hier noch seine Finger im Spiel. Die Breite der Menuitems ist begrenzt. Um diesen Fluch aufzuheben, muss man einen Finite Incantatem (Gegenzauber) sprechen. Damit hebt man allerdings nur die Wirkung auf, das Sys.WebForms.Menu aus Zeile 20 bleibt.
1: </asp:Menu>
2: <script type="text/javascript"> Sys.WebForms.Menu = "";</script>
Um die Schönheit und Reinheit des HTML zu verbessern braucht es noch Zutaten derer Vier.
1: EnableViewState="false" IncludeStyleBlock="false" ClientIDMode="Static" SkipLinkText=""
Auf der Fiddler Karte erscheint so der direkte und damit optimale Weg.

Letztendlich gibt es ein Happy End aber es ist das letzte Kapitel noch nicht geschrieben. Wir warten sehnsüchtig auf die Zauberer aus Redmond.
1: <script src="/WebResource.axd?d=fqV81KWLWhVg-lLAb4IT6z7dNzU96UkgnAUvd3TznA7r7jm
BA8d3Ppk0-TpQJTuNUNdLcYMr6iHiLhrQ1-FE8y8o-CmqZlIAp78DXeQ-4cw1&t=634897471112455790"
type="text/javascript"></script>
2: <div data-role="content">
3:
4: <div>
5: <div data-role="navbar" id="div2">
6: <ul class="level1">
7: <li><a class="level1" href="S/2,12,14,19">Windows & .NET</a></li>
8: <li><a class="level1" href="S/3,7">Architektur&Dev</a></li>
9: <li><a class="level1" href="S/11">Web Development</a></li>
10: <li><a class="level1" href="S/13,18,22">SharePoint</a></li>
11: <li><a class="level1" href="S/5,6,20">Server Administration</a></li>
12: <li><a class="level1" href="S/9,7">Office u.a.</a></li>
13: <li><a class="level1" href="S/4,21">SQL & BI</a></li>
14: <li><a class="level1" href="kontakt">Kontakt</a></li>
15: </ul>
16: </div>
17: </div>
18:
19: </div>
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
- Create test plan properties: Select Test Configurations, Test Case Title, Area, Iteration, State, Automation Status, Assigned To, Assign Build To Test Plan, Determine Changes Between Builds
- Configure test settings: Create test settings, Data and Diagnostics, Roles
- Define configurations: Creating configuration variables, Default configurations, Creating a new configuration, Setting configuration state, Delete a test configuration
- Create Test Suites: Organizing Test Cases Using Test Suites (Query-based, Requirement-based and Static Test Suites), Hierarchy of Test Suites, Copy Test Suites, Managing Test Suites and Test Cases, TCM
- Configure Test Suites: Assign a Tester, Change the order of test cases, Select default configuration
Manage Test Cases
- Create Test Cases: Creating Manual Test Cases, Creating Automated Tests, Test Case History, Links and Attachements, Tested Work Items and Test Case States
- Create Test Steps: Adding parameters to a Manual Test Case, Adding parameters to Shared Steps, Run Multiple Iterations of Test with parameters, Add attachement to test step
- Define parameters: Add, Rename and Delete parameters
- Manage Shared Steps: Create Shared Steps, Copy Shared Steps, Share Common Test Case Steps Using Shared Steps, Create an Action Recording for Shared Steps
Manage Test Execution
- Run Tests: Run tests with options, Create action recordings, Shared steps action recording, Capture a screenshot while running a test, Add a comment while running a test
- Perform Exploratory Testing: Perform Exploratory Testing, Explore Work Item, Create bug, Create test case
- Manage bugs: Dashboards (Agile), Reports (Agile), Dashboards (CMMI), Reports (CMMI), Reports (Scrum), Verify bugs
- Use Lab Center: Create Lab Environments, Creating an SCVMM Environment Using Stored Virtual Machines and Templates, Running Tests in Lab Environments
- Analyze Recommended Tests: Assign Build, Test Impact, Related Work Items
- Perform analysis: Analyze Manual Test Runs, Reporting on Test Progress, View Test Plan Status
- Manage Work Items: Link existing test cases to a requirement
Inhalte der Zertifizierung Software Testing with Visual Studio 2012 (70-497) is a post from: AIT Blog
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
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
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
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
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
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
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.
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.
Dieser Parameter hat 3 mögliche Einstellungen:
-
All – Mit dieser Einstellung werden sowohl der Source Code all auch alle Outputs des
Builds gelöscht (Clean Build). Dies ist die Default-Einstellung
-
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
-
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
Dann stellt man in den Properties die GetOptions auf “Overwrite”
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.
>>
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.

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.
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.

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).

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).

Abbildung 3 – Taskboard des Netfactory Frontend Teams

Abbildung 4 – Taskboard des Netfactory Backend Teams

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
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.

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.

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.
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
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)
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:
Alle Videos stehen auf Channel 9 zum Anschauen und Herunterladen bereit.
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.
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
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.

Zum Buchen & Infos zur Konferenz siehe www.buildwindows.com.
Viel Spaß!
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.

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>

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>

Natürlich gibt es dann keine animierten Transitions mehr.
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:

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
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.
- Zunächst ist in Visual Studio ein neues SharePoint Projekt vom Typ “Site Definition” als Farmsolution zu erstellen.
- 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).
- 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>
-
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).
-
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.
-
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:

-
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ü).
-
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>
-
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:

-
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”.
Anschließend wird die Default.aspx als Startseite der neu erstellten Website aufgerufen basierend auf der eigenen Masterpage bzw. CSS-Datei.

-
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.

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
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

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#”.

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!

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.

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
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:

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:

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.
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)
Windows Authentifizierung ist eine nette Sache – wenn sie funktioniert
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. 
Wer keine Zeit hat sollte sich dennoch anmelden und die Aufzeichnungen später ansehen.

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

Viel Spaß mit den kostenfreien MVA-Sessions!
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.
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:
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.
Lustig finde ich auch die Fehlermeldung “0x800713ec – Asia”
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
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]
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]

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
http://win-8.de/MetroDeactivator/
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!

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,
In 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:

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

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:

Ä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":

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:

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

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:

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.
 |
Beispielanwendung:
Weitere Informationen:
|
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.

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!

Leider liegen beide Dateien im ISAPI Verzeichnis des SharePoint Servers.
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.
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.

Am 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
Bei der "Dotnet Cologne" hat der Dotnet-Doktor diskutiert, auf welche Weise man das ADO.NET Entity Framework in einem Mehrschichtmodell einsetzen kann.
... 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.

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:
- Am Anfang des Prozesses, in dem der Konstruktor des Ausgabestreams mit einer kleineren Kapazität initialisiert wird.
- 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:
clr |
c# |
serialization |
binary
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 [...]
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.
Nichts 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.
 |
Beispielanwendung:
Weitere Informationen:
|
Verwendete Bildquellen:
© Corinna Dumat / PIXELIO
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)