woensdag 16 april 2014

TypeScript

Het stadium waarin we statische webpagina's maakten, hebben we reeds ver achter ons gelaten. Tegenwoordig moet het allemaal nog interactiever en gelikter. Om responsive webpagina's te maken gebruiken we Ajax en steeds meer functionaliteiten laten we de client, dus in de browser, uitvoeren. Van oudsher is JavaScript hiervoor de taal naar keuze. Een tijdje is JavaScript een beetje in onbruik geraakt toen alles op de server gegenereerd moest worden. Omdat de servers het erg druk kregen en de clients steeds meer rekenkracht bezaten, ging men al snel wat taken naar de browser verleggen. Dit heeft voor een opmerkelijke comeback van JavaScript gezorgd. 

Tegenwoordig wordt JavaScript ook als programmeertaal gebruikt voor applicaties (Windows Store Applicaties) en servertoepassingen (Node.js).
Het probleem met JavaScript is echter dat het een erg lastige taal is. Bijkomend nadeel is dat JavaScript van origine niet object georiënteerd is waardoor gestructureerde applicaties lastig zijn. Met veel kunst- en vliegwerk is wel wat object georiënteerde code te bakken, maar het komt de leesbaarheid in het algemeen niet ten goede. Met TypeScript is een serieuze poging ondernomen om meer structuur en leesbaarheid aan te brengen in onze JavaScript code. In het codevoorbeeld hieronder volgt een voorbeeld van een traditioneel stukje JavaScript waarin een module MyModule wordt gemaakt met de class Person. De class Person heeft fields firstName en lastName en een methode introduce()

var MyModule = (function (my) {
    my.Person = function (first, last) {
        this.firstName = first;
        this.lastName = last;
    }
    my.Person.prototype.introduce = function () {
        alert("Hello! I am" + this.firstName + " " + this.lastName);
    }
    return my;
})(MyModule || {});

var p = new MyModule.Person("Patrick""Schmidt");
p.introduce();
Dit is dus een zeer eenvoudig voorbeeld, maar voor menigeen al abracadabra. Hetzelfde stukje ziet er in TypeScript als volgt uit:

module MyModule {
    export class Person {
        firstName: string;
        lastName: string;

        constructor(first: string, last: string) {
            this.firstName = first;
            this.lastName = last;
        }

        introduce() {
            alert("Hello! I am" + this.firstName + " " + this.lastName);
        }
    }
}

var p = new MyModule.Person("Patrick""Schmidt");
p.introduce();
In het stukje code zien we meteen een aantal keywords terug, zoals module en class. Merk ook op dat TypeScript strong typed is. Iets dat JavaScript helemaal niet is. De declaratie van variabelen, waarin de type-aanduiding achter de variabele staat, doet sterk denken aan Pascal. Dat mag geen wonder heten als je weet dat niemand minder dan Anders Hejlsberg (de maker van Turbo Pascal) een drijvende kracht achter TypeScript is. Zijn achtergrond zal echter niet de reden voor deze notatie zijn. TypeScript en JavaScript kunnen namelijk door elkaar heen gebruikt worden en dan kan een C#-achtige manier van variabelen declareren uiterst verwarrend werken. Het keyword export geeft aan dat de class Person buiten de module te gebruiken is. Dit is vergelijkbaar met het public maken van een class in een assembly.

Het grote probleem is dat een browser van dit stukje code totaal geen chocolade kan maken. Die begrijpt alleen maar JavaScript. Vandaar dat TypeScript gecompileerd moet worden. Dat kan aan de commandline gebeuren met behulp van het tsc.exe commando waarmee JavaScript gegenereerd wordt dat in de webapplicatie gebruikt kan worden, maar er zijn ook client side compilers te verkrijgen die het in de browser doen.

Tijd om eens een wat lastiger scenario te bekijken. Zoals eerder vermeld, is JavaScript niet object georiënteerd en overerving is dus niet mogelijk, maar met wat geknutsel is daar nog wel een mouw aan te passen. Er bestaan vele manieren om overerving in JavaScript te realiseren. Een populaire manier is prototype chaining waarvan hieronder een voorbeeld gegeven is.

var MyModule = (function (my) {
    my.Person = function (first, last) {
        this.firstName = first;
        this.lastName = last;
    }
    my.Person.prototype.introduce = function () {
        alert("Hello! I am " + this.firstName + " " + this.lastName);
    }

    my.Employee = function (first, last, jobtitle) {
        my.Person.prototype.constructor.call(this, first, last);
        this.jobTitle = jobtitle;
    }
    // Prototype chaining
    my.Employee.prototype = new my.Person();
    my.Employee.prototype.constructor = my.Employee;

    my.Employee.prototype.introduce = function () {
        alert("Hello! I am " + this.firstName + " " + this.lastName +
     " and I'm " + this.jobTitle);
    }

    return my;
})(MyModule || {});

var p = new MyModule.Employee("Patrick""Schmidt""developer");
p.introduce();
Dit ziet er allemaal nogal onsmakelijk uit, maar voor een geoefend JavaScripter nog steeds vrij eenvoudig. Eens kijken hoe dit er in TypeScript uit gaat zien.

module MyModule {
    export class Person {
        firstName: string;
        lastName: string;

        constructor(first: string, last: string) {
            this.firstName = first;
            this.lastName = last;
        }

        introduce() {
            alert("Hello! I am" + this.firstName + " " + this.lastName);
        }
    }

    export class Employee extends Person {
        jobTitle: string;

        constructor(first: string, last: string, jobTitle: string) {
            super(first, last);
            this.jobTitle = jobTitle;
        }

        introduce() {
            alert("Hello! I am " + this.firstName + " " + this.lastName +
                " and I'm " + this.jobTitle);
        }
    }
}

var p = new MyModule.Employee("Patrick""Schmidt""developer");
p.introduce();

Dit ziet er al veel beter uit. Het keyword extends geeft aan dat Employee erft van Person en de aanroep super() redirect first en last naar de constructor van Person (base() in C#). 

Interfaces vormen een belangrijk concept in een taal om componenten van elkaar te ontkoppelen. In typescript gaat dat als volgt:

module MyModule {

    export interface IWork {
        doSomeWork(workType: string) :number;
    }

    export class Person implements IWork
    {
        firstName: string;
        lastName: string;

        constructor(first: string, last: string) {
            this.firstName = first;
            this.lastName = last;
        }

        doSomeWork(workType: string) {
            alert(this.firstName + " is " + workType);
            return 2000;
        }
    }
}

var p = new MyModule.Person("Patrick""Schmidt");
p.doSomeWork("developing");

De interface IWork heeft een methode die een variabele van type string verwacht en een getal terug geeft. De class Person implementeert de interface middels het keyword implements. In het gegenereerde JavaScript is niets terug te vinden van dat interface. Het is dan ook alleen aanwezig voor de leesbaarheid en een ogenschijnlijke ontkoppeling. Daarnaast kunnen interfaces goed gebruikt worden voor anonieme objecten in JavaScript. Denk hierbij aan JSON objecten die een client via het netwerk ontvangt. Middels een interface kunnen de members van dit anonieme object beschreven worden.

Tot zover wat voorbeelden van TypeScript. De taal biedt nog vele andere concepten, zoals generics, statics en lambda expressions, maar daarvoor verwijs ik naar de website van TypeScript.

TypeScript heeft de toekomst. Zeker omdat niet de minste namen, zoals Hejlsberg en Gamma, een bijdrage leveren. Daarnaast is er een explosieve toename van definities voor oa jQuery, node.je en angular.js waar te nemen. Alles wijst er op dat TypeScript een hoge vlucht gaat nemen. Het zou zomaar kunnen dat we in de toekomst nog alleen maar TypeScript hoeven te kennen.

dinsdag 22 oktober 2013

Import bacpac

Sinds een tijdje kent Windows Sql Azure een soort van backup mogelijkheid. Het komt erop neer dat Windows Azure een dump van de database maakt. Deze dump wordt opgeslagen in een backup package (bacpac) die je vervolgens overal naartoe kun slepen. Zo'n bacpac importeren is kinderlijk eenvoudig. In SqlServer kies je de optie "Import Data-tier Application" en in Azure kies je bij de databases de optie "Import". In beide gevallen moet je een bacpac opgeven en de zaak gaat verder vanzelf. 
Helaas is de praktijk weerbarstig. Recentelijk had ik een dump van de database nodig om te testen en wie schets mijn verbazing? De import werkt niet. Ik kreeg de volgende foutmelding:

Error SQL72045: Script execution error.  The executed script:
DECLARE @c AS INT = 1;

WHILE @c = 1
    BEGIN
        DELETE TOP (1000)
               [Core].[Brand];
        IF @@rowcount < 1000
            SET @c = 0;

    END

Op zich wazig want deze code kon ik in geen enkel script terugvinden. Kennelijk is dit iets dat de import-utility uitvoert. Na enig zoekwerk kwam ik erachter dat de importactie triggers uitvoert en één trigger veroorzaakte daarbij een probleem. Tja, daar zit je dan met je bacpac. 
Na enig onderzoek bleek zo'n bacpac gewoon een zip-bestand te zijn. Even de extensie veranderen naar .zip en je kunt hem uitpakken. In dit pakket vind je een aantal bestanden. De .BCP-bestanden zijn bulkcopy bestanden en bevatten de data. Daarnaast heb je nog een aantal xml-bestanden, waaronder model.xml en Origin.xml. In model.xml zit de definitie van jouw database en dus ook de definitie van de triggers. Als je de probleemtrigger er nu eens gewoon uit haalt en hem later handmatig toevoegt? Het is het proberen waard. Het bestand weer zippen en opnieuw proberen te importeren. Helaas! Nu gaat het meteen mis. Mijn wijziging heeft ervoor gezorgd dat de checksum van de package niet meer klopt. Die checksum vind je in Origin.xml. Het fragment in kwestie staat hieronder.


<Checksums>   
     <Checksum Uri="/model.xml">E64500DB5070F3FF8F639D2A2570824976B3746DEAC8914E9B82652FD3696173</Checksum>
</Checksums>

Kennelijk is de checksum alleen op model.xml toegepast hetgeen de zaak aanzienlijk vereenvoudigt en zo te zien is er een 256 bits algoritme toegepast. Nou, hoeveel kunnen dat er zijn? Laten we eens het SHA-256 algoritme uitproberen. Hieronder de listing hoe je dat in C# uitwerkt.


static void Main(string[] args)
{
    SHA256Managed sha256 = new SHA256Managed();
    byte[] hash;
    using (FileStream stream = File.OpenRead("model.xml"))
    {
        hash = sha256.ComputeHash(stream);
    }
    StringBuilder outputString = new StringBuilder();
    foreach (byte b in hash)
    {
        outputString.AppendFormat("{0:x2}", b);
    }
    Console.WriteLine(outputString.ToString().ToUpper());
    Console.ReadLine();
}
Nadat de bestaande hash was vervangen voor de gegenereerde hash en de bestanden weer gezipped waren, werkte het meteen. Overigens hoef je de .zip extensie niet eens terug te veranderen in bacpac. De "Import Data-tier Application" tool blijkt het allemaal prima te begrijpen.
Natuurlijk nog wel even de verwijderde elementen toevoegen aan de geïmporteerde database en de hele zaak draait weer als voorheen.

zaterdag 14 september 2013

Distributed Cache Service

Commerciële websites moeten razensnel zijn. Een eindgebruiker heeft nu eenmaal geen zin om lang te wachten. Bovendien komt het de ranking in search engines niet ten goede als de website traag reageert. Je kunt er zelfs strafpunten voor krijgen. Er is dus veel aan gelegen dat de reactietijd snel blijft. Er zijn een aantal strategieën die je hiervoor kunt inzetten:
  1. Zorg ervoor dat je niet teveel html naar de client stuurt. Browsers moeten dat allemaal interpreteren en renderen. Kost dus tijd.
  2. Zorg voor voldoende machinecapaciteit. De pagina's worden vaak op de server gegenereerd. Dat kost processorkracht en geheugen. Je kunt natuurlijk een supercomputer aanschaffen, maar dat kost handenvol geld en op een gegeven moment zit je toch aan het hardwareplafond. Ga dus voor een schaalbare oplossing. Veel computers tesamen zijn altijd krachtiger dan de snelste machine. Clouddiensten voorzien in deze behoefte en bieden de mogelijkheid om snel op en af te schalen. Azure kan dit zelfs automatisch op basis van processorgebruik. 
  3. Zorg ervoor dat eenmaal gegenereerde pagina's in het geheugen van de computer bewaard worden (caching), zodat de volgende bezoeker uit de cache kan tappen.
Caching is in ieder geval een handige truc om de website snel te houden. Van belang is wel wat je gaat cachen. Ga je de hele pagina cachen, ga je alleen data cachen of een hybride vorm? Welke strategie je ook kiest, in een gedistribueerde omgeving als Windows Azure is dit niet zo eenvoudig omdat jouw website op meerdere machines draait. Je krijgt dus te maken met duplicate caches. Hoewel geheugen vrij goedkoop is, blijft het natuurlijk wel zonde. Afgezien nog van de tijdsverschillen die ontstaan tussen de verschillende gecachte objecten.

In Windows Azure zijn op dit moment een tweetal mogelijkheden voorhanden (zie blog Caching in Windows Azure):
  1. Shared Cache. Met deze optie staat iedere machine zo'n 30% van zijn geheugen af voor de totale cache. Nadeel is wel dat dit ten koste gaat van de kostbare werkgeheugen van de website. Bovendien werkt het niet echt goed. Met name de eerste keren wil het nog wel eens misgaan. Bovendien wordt deze dienst over een jaar stop gezet.
  2. Dedicated Cache. Hierbij maak je een extra cloud service aan die louter en alleen dienst doet als leverancier van geheugen. Voor zo'n 2,5GB geheugen (een aanzienlijk deel gaat op aan het OS) kost deze oplossing toch al gauw €120,- per maand. 
Sinds een week is er een nieuwe oplossing: Distributed Cache Service. Deze is nog in de preview en zal de huidige cache-oplossingen vervangen. Reden genoeg om deze nieuwe functionaliteit in Windows Azure nader te onderzoeken.

Omdat de Distributed Cache Service geld kost, moet de creditcardhouder eerst een aanvraag doen om deze service te kunnen gebruiken. Daarna kunnen de co-administrators ermee aan de slag. Vanuit de Windows Azure Portal kan nu de cache aangemaakt worden via een nieuw menu-item "Cache" in het linker menu (afbeelding 1).


Afbeelding 1. Het menu-item "Cache" dat zichtbaar wordt wanneer de cachedients geactiveerd is. Van hieruit verloopt alles hetzelfde als bij de andere services: Klink de grote "+" links onderin beeld.
Vervolgens klik je weer op de grote "+" links onderin beeld waardoor je in het configuratiescherm van afbeelding 2 komt. In dit scherm geef je een unieke endpoint naam op. Dit endpoint is het aanspreekpunt van de cache. Hiermee communiceer je met de cache. Daarnaast geef je op in welke regio de cache komt te draaien. Selecteer een cache dicht in de buurt van jouw website. Daarna geef je op welke abonnement je wilt. Je kunt kiezen uit drie vormen:
  1. Basic. De goedkoopste. Hier begin je met 128MB en schaal je in stappen van 128MB op tot 1GB. Je krijgt een default cache aangeleverd en daarmee moet je het maar doen.
  2. Standard. Deze loopt vanaf 1GB geheugen en schaalt in stappen van 1GB op tot een maximum van 10GB. Bij deze optie kun je maximaal tien cachepotten (named caches) aanmaken. Daarnaast kun je inhaken op bepaalde cachegebeurtenissen.
  3. Premium. De duurste vorm en start met 5GB en loopt in stappen van 5GB op tot 150GB. Ook hier kun je maximaal tien cachepotten aanmaken. Hierbij krijg je ook cache replicatie waarmee de beschikbaarheid enorm toeneemt.
Tenslotte geef je op hoeveel fracties van 1GB je als cache wilt gebruiken. Let op dat iedere fractie geld kost.


Afbeelding 2. Configuratie van de cache.
Nadat de cache en het endpoint zijn aangemaakt, kun je het cachegedrag vastleggen. Dit doe je door op het zojuist aangemaakte endpoint te klikken en dan de "Configure" tab te selecteren (afbeelding 3). Vanaf de Standard en Premium abonnementen kun je cachepotten (named caches) aanmaken. De default krijg je standaard aangeleverd waarin je alleen het cachegedrag kunt wijzigen:
  • Name. De naam van de cachepot. Hiernaar zul je in de code verwijzen als je deze cache wilt aanspreken.
  • Expiry Policy. Hier heb je de keuze uit sliding en absolute. Kies sliding als je de cache met een bepaalde duur (Time) wilt verlengen telkens als hij wordt geraadpleegd. Wanneer de cache na een bepaalde tijd hoe dan ook moet vervallen kies je Absolute.
  • Time. Hierbij geef je op hoe lang de levensduur van de cache is.
  • Notifications. Wanneer er zaken gebeuren op de cache, kun je daarvoor een notificatie ontvangen.
  • Eviction. Hierbij geef je op of deze cache opgeruimd mag worden wanneer er een tekort aan geheugen dreigt te ontstaan.
Afbeelding 3. Named Cache configureren.

Natuurlijk is ook de handige scale optie aanwezig waarmee je snel kunnen opschalen wanneer het drukker wordt en een Monitor functie (Afbeelding 4) waarmee we de cache in de gaten kunnen houden. Hierbij is in eerste instantie de "Cache Miss %" interessant om in de gaten te houden. Deze counter geeft aan hoe vaak een cacheaanvraag niet slaagt. Die moet dus zo laag mogelijk blijven.

Afbeelding 4. De monitor functionaliteit in Windows Azure Cache.
In de Azure Portal zijn we nu wel klaar. Tijd om in de code te duiken. Allereest haal je via NuGet de laatste versie van Windows Azure Cache op (versie 2.1.0.0 op het moment van dit schrijven). Vervolgens configureer je de cache in de web.config zodat deze gebruikt maakt van de zojuist aangemaakte cache. Hiervoor specificeer je het adres van het endpoint en geef je de key (te vinden in de Azure Portal bij de cache (Manage Keys)). In het configuratie fragment zie je hoe dat eruit ziet. Bij "identifier" geef je het endpoint adres op en bij "authorizationinfo" de access key.

<dataCacheClients>
  <dataCacheClient name="default">
    <autoDiscover isEnabled="true" identifier="pastest.cache.windows.net" />
    <securityProperties mode="Message" sslEnabled="false">
      <messageSecurity authorizationInfo="YWNzOmh0dHBzOi8vcGFzdGVzdDQ1NzUtY2FjaGUuYWNjZXNzY29ud==" />
    </securityProperties>
  </dataCacheClient>
</dataCacheClients>

Om nu de output cache in te stellen, activeer je het volgende fragment in de web.config


<caching>
   <outputCache defaultProvider="AFCacheOutputCacheProvider">
       <providers>
          <add name="AFCacheOutputCacheProvider" type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, Microsoft.Web.DistributedCache" cacheName="default" dataCacheClientName="default" applicationName="AFCacheOutputCache" />
       </providers>
   </outputCache>
</caching>

De rest is precies zoals je gewend bent te doen: Decoreer controller classen of actions met het OutputCacheAttribute.

In sommige situaties wil je niet de hele pagina cachen maar alleen de data die de pagina gebruikt. Denk hierbij aan een in-memory dataset waarin productdata wordt opgeslagen zodat er snel en eenvoudig gefilterd kan worden op bijvoorbeeld productspecificaties. Hiervoor kun je de DataCache class uit het Windows Azure Cache package gebruiken. In het codefragment hieronder zie je hoe dat gaat.

public class HomeController : Controller
{
    private DataCache cache = new DataCache("test");

    public ActionResult Index()
    {
        object co = cache.Get("time");
        if (co == null)
        {
            co = DateTime.Now;
            cache.Put("time", co);
        }
        ViewBag.TheDate = co;
        ViewBag.RoleID = RoleEnvironment.CurrentRoleInstance.Id;
        return View();
    }

    private void OnDataCacheNotificationCallback(
        string cacheName,
        string regionName,
        string key,
        DataCacheItemVersion version,
        DataCacheOperations cacheOperation,
        DataCacheNotificationDescriptor nd)
    {
        ViewBag.Name = cacheName;
        ViewBag.Region = regionName;
        ViewBag.Key = key;
        ViewBag.Version = version;
        ViewBag.Operation = cacheOperation;
    }

    public HomeController()
    {
        DataCacheNotificationDescriptor desc = cache.AddCacheLevelCallback(
            DataCacheOperations.AddItem | DataCacheOperations.RemoveItem,
            OnDataCacheNotificationCallback);
    }
}

In de action "Index" zie je hoe je data aan de cache kunt toevoegen en weer uitlezen. Vooralsnog is er geen rekening gehouden met concurrency, maar aan het locking mechanisme is verder niets veranderd (zie blog Caching in Windows Azure).
De rest van de code laat zien hoe je gebruik maakt van het notificatie mechanisme in Windows Azure Cache (Wel eerst aanzetten in de Azure Portal (afbeelding 3)).

Het gaat allemaal erg snel met Windows Azure. De ene nieuwe functionaliteit volgt de andere rap op. Distributed Cache in Windows Azure is wederom een mooie aanwinst. Eindelijk zijn we af van die brakke gedistribueerde oplossingen waarbij we een deel van het werkgeheugen van de site moesten afstaan aan de cache of een complete omgeving op moesten zetten voor het geheugen.

dinsdag 6 augustus 2013

Visual Studio in Azure

Wie aan Windows Azure denkt, denkt in eerste instantie aan schaalbare hostingvormen waarin je een webapplicaties kunt draaien en nagenoeg onbegrenste opslagmogelijkheden hebt. Windows Azure heeft echter veel meer te bieden. In eerdere blogs heb je al kennis kunnen maken met Cloud Services, Windows Azure Sql Database, Access Control Service, Windows Azure Service Bus en gedistribueerde cache.
Het basisprincipe blijft dat je een virtuele omgeving draait in één van de datacentra van Microsoft. Zo'n virtuele omgeving is niets anders dan een enorm bestand dat een compleet besturingssysteem bevat. Het is alsof je jouw harde schijf met Windows en alles erop en eraan in een computer van Microsoft plugt. Zo'n omgeving kun je direct uit de bibliotheek van Windows Azure trekken, maar je kunt ook jouw eigen omgeving samenstellen en deze in Windows Azure hangen. Dit gaat via Windows Azure Virtual Machines.

In het kader van "de schoorsteen moet ook roken" heeft Microsoft ook hierin nogal wat werk uit handen genomen. Zo kun je complete basisomgevingen uit de bibliotheek trekken waarop reeds geïnstalleerde producten staan en deze naar believen uitbreiden. Natuurlijk met een prijs. We gaan eens bekijken hoe dat in zijn werk gaat.

Alleereerst log je in op de Azure Portaal. Van daaruit ga je naar de sectie "Virtual Machines" (afbeelding 1). Van hieruit is het allemaal vrij vanzelfsprekend. Klik op "Create A Virtual Machine" hetgeen leidt naar het scherm in afbeelding  2.


Afbeelding 1. De "Virtual Machines" groep.
Afbeelding 2. Selecteerd "from gallery" om een omgeving te selecteren met een specifieke toepassing.
Met de optie "Quick Create" kun je snel een omgeving opzetten en met "From Gallery" kun je hetzelfde bewerkstelligen, maar dan met iets meer werk. We kiezen "From Gallery" en komen bij de wizard in afbeelding 3.


Afbeelding 3. De voorgefabriceerde omgevingen.
Uit dit lijstje selecteer je welke applicatie je op de omgeving wilt hebben. Zoals je ziet, is er een grote hoeveelheid omgevingen met daarop geïnstalleerde toepassingen. Zo zijn er omgevingen met SqlServer (2008 t/m 2014 in alle soorten en maten), BizTalk servers, SharePoint Servers en zowaar een aantal Linux distributies (waarom ook niet), zoals SUSE, Ubuntu en CentOS. De omgeving met Visual Studio Ultimate 2013 trok echter mijn aandacht omdat zo'n Ultimate editie knetterduur (meer dat 10.000,-) is. Vervolgens moet je de omgeving configureren (afbeelding 4). 


Afbeelding 4. Vrij riante omgeving. Specificeer hier ook de credentials die je nodig hebt om in te loggen op de omgeving.
Voor deze omgeving wordt "Large" aanbevolen, dus 4 processoren en 7 GB ram. OK, dat gaat al in de papieren lopen. Zo'n omgeving kost toch al gauw €200,- per maand. Als je de omgeving, na gebruik, netjes uitzet, kun je de kosten reduceren to €0,27 per uur. Dat valt dan weer mee, maar reken je niet rijk. Dit zijn slechts de hostingskosten. De licentiekosten, die op dit moment nog onbekend zijn, komen hier nog bij.
Daarna moet je aangeven in welke cloud service de omgeving komt te draaien (afbeelding 5). Let op! Dit is geen machine. Het is een cluster van omgevingen waarbinnen meerdere virtuele machines kunnen draaien. Handig voor load balancers. Daarnaast zul je nog het datacentrum, waarin de machine komt te draaien, moeten opgeven (region), de storage account waarin de VHD (het bestand dat de harde schijf met daarop de omgeving representeert) wordt opgeslagen. Eventueel kun je nog een Availability Set opgeven. Hiermee ben je niet zo afhankelijk van hinderlijke storingen in het datacentrum.


Afbeelding 5. Configuratie van de service, region, storage en availability.
Tenslotte nog wat endpoints opgeven om te kunnen communiceren met de omgeving. Een remote desktop endpoint en een endpoint om via PowerShel met de omgeving te kunnen interacteren zijn hierbij wel handig. Vandaar dat deze standaard al zijn ingevuld (afbeeldig 6). 


Afbeelding 6. Endpoints definieren.
In nog geen 10 minuten wordt nu een omgeving met Visual Studio Ultimate 2013 in elkaar gedraaid. Wanneer dit gelukt is, kun je aan de slag. In de Windows Azure Portal kun je de zojuist aangemaakte omgeving bewonderen en bedienden (afbeelding 7).


Afbeelding 7. De omgeving is in gereedheid.
Onderin het scherm vind je een aantal bedieningsfuncties:
  1. Connect. Hiermee leg je een remote desktop verbinding met de omgeving. Het downloadt een .rdp bestand dat je kunt activeren waarmee de remote desktop sessie start.
  2. Restart. Om de omgeving te herstarten (reboot)
  3. Shut Down. Om de omgeving uit te zetten. Belangrijk omdat hiermee de kosten stoppen.
  4. Attach. Hiermee kun je een extra vhd aan jouw omgeving hangen. Het komt erop neer dat je een extra "harde schijf" aan jouw omgeving hangt.
  5. Detach Disk. Verwijder de extra harde schijf weer.
  6. Capture. Maak een copie van de huidige image die je vervolgens weer als een basistemplate inzet.
  7. Delete. Verwijder de virtual machine. (Verwijdert niet de .vhd blob in de store!)
Wanneer je de "Connect" knop kiest, wordt de remote desktop verbinding tot stand gebracht en kom je op de virtuele omgeving (afbeelding 8). Van hieruit kun je dan Visual Studio starten (afbeelding 9).


Afbeelding 8. Server 2012 met Visual Studio Ultimate 2013.
Afbeelding 9. Visual Studio draaiende vanuit de cloudomgeving.
Visual Studio op een virtuele omgeving lijkt mij een interessante optie in Windows Azure. Temeer daar Visual Studio Ultimate erg duur is. Tot dusver betaal je nog de hostingskosten (€0,27 per uur), maar daarbij zullen nog de licentiekosten bij komen (geen idee wat die gaan worden). Je hebt dan wel de mogelijkheid om waar dan ook op jouw ontwikkelomgeving te kunnen werken, mits er een internet verbinding is, natuurlijk. Het trekt ook niet zo'n zware wissel op de gewenste hardware die bij iedere Visual Studio release veeleisender lijkt te worden. Voor de Microsoft trainingen zou dit wel eens een handige oplossing kunnen zijn in plaats van die zware omgevingen die nu worden aangeboden. Ik zie het nog wel een keer gebeurden dat de MOC-trainingen op deze manier worden aangeboden. 

donderdag 1 augustus 2013

Windows Azure Sql Database backup

Een heet hangijzer in Windows Azure Sql Database was de beperking om backups te maken van jouw database in de cloud. Er waren allerlei kunstgrepen nodig om toch maar een geldige kopie van de database te krijgen. In een eerdere blog heb ik een aantal van die kunstgrepen beschreven. De beste oplossing was om een kopie van de database te maken en deze naar een backup package (bacpac) te exporteren. Sinds een week is het mogelijk om dit proces door Windows Azure te laten uitvoeren.

Om een backup te maken van de database, ga je eerst naar de Portal van Windows Azure. Van daaruit ga je naar de database groep en selecteer je de database die je wilt exporteren. In het menu van de database is nu een tab erbij gekomen: Configuration. Je komt dan uit op het venster van afbeelding 1.

Afbeelding 1. Het exportscherm om de Windows Azure Sql Database te exporteren.
De inhoud van dit venster spreekt redelijk voor zich. De "Export Status" zet je op automatic. Vervolgens specificeer je een storage account waarin de backup package (bacpac) wordt opgeslagen. Daarnaast zul je moeten aangeven om de hoeveel dagen deze export moet worden uitgevoerd en hoe laat. Dit is even een lastig gegoochel met de UTC tijd. In Nederland moet je één of twee uur van de huidige tijd aftrekken afhankelijk van de winter- of zomertijd. Bij Retention geef je aan  hoe lang je de bacpac wilt bewaren. Ofschoon schijfruimte in overvloed aanwezig is, is het niet gratis. Met deze automatische weggooiactie voorkom je onverwachte kosten. Zorg wel dat je ten minste één bacpac bewaard. Dat kun je bewerkstelligen door de checkbox "Always keep at least one export" aan te vinken. Tenslotte specificeer je de loginnaam en het wachtwoord voor de database server. De automated export zal namelijk een tijdelijke kopie van de database op de server maken waarvan de bacpac wordt gegenereerd. Vergeet niet op de "Save" knop onderin beeld te klikken. 
Let ook even op de setting "Allowed Services" in afbeelding 2. Je vindt hem bij de configuratie van de database server (waar je ook de toegestane ip-adressen opgeeft). Zorg dat die op "Yes" staat, anders kan de automated export geen verbinding maken met de server.


Afbeelding 2. Zorg ervoor dat Windows Azure Services op "Yes" staat.

Wanneer de export geslaagd is, zie je in de storage de volgende container staan (afbeelding 3) met daarin de gegenereerde bacpac


Afbeelding 3. De door de Automated Export aangemaakte container waarin de bacpac staat.

Als eenmaal zo'n bacpac aanwezig is, kun je vrij eenvoudig een database hiervan maken. Ga hiervoor naar de "Databases" in de Azure Portal en selecteer "Import" (onderin beeld). Het leidt tot het importvenster uit afbeelding 4.


Afbeelding 4. Een oude bekende. Het importvenster om bacpacs te importeren.
Hier selecteer je de bacpac, naam van de database en de database server, waarop hij komt te draaien. Vergeet niet de "Advanced Settings" te selecteren als je meer wilt dan die standaard 1GB Web database.

Het is ook mogelijk om de bacpac op een on premise SQL Server te importeren. In Sql Server Managment Studio activeer het het contextmenu op de "databases" node en selecteer je "Import Data-tier application...". Je wordt dan door de wizard uit afbeelding 5 geleid (introductiescherm achterwege gelaten).


Afbeelding 5. De import van de bacpac in SSMS.
Aanvankelijk gaf deze import de volgende fout:

Internal Error.  The internal target platform type SqlAzureDatabaseSchemaProvider does not support schema file version '2.5'.

Dit probleem werd verholpen door de laatste versie van SQL Server Data Tools te installeren.

Automated Export is wederom een welkome aanwinst in Windows Azure. Je kunt nu eenvoudig, op gezette tijden, een backup van de database maken. Hij is vrij lomp in die zin dat het alles of niets is, maar het is in ieder geval een begin. Een groot nadeel vind ik het afhandelen van triggers in de database. In tenminste één geval bleek de import niet te slagen door een lastige trigger. Omdat een bacpac eigenlijk gewoon een .zip bestand is, kun je nog wel wat morrelen aan de inhoud, maar het zou beter zijn als de activering van triggers bij import optioneel zou zijn.
Voor het besteproduct is de huidige oplossing echter redelijk werkbaar.

dinsdag 16 juli 2013

SignalR in ASP.NET.

Websites worden steeds moderner. Waar we het vroeger (begin jaren 90) nog moesten doen met een homepage, waarop wat persoonlijke informatie stond en een rubriekje "Mijn favoriete links" (Het enige interessante op die pagina's omdat search engines niet of nauwelijks bestonden), worden nu complete applicaties via de webbrowser aangeboden. Deze ontwikkeling ging bepaald niet over rozen. De webarchitectuur was zo gebouwd dat alle initiatief bij de client (webbrowser) lag. De client deed de requests en de server (webserver) reageerde alleen op die requests. Het was uit den boze dat een webserver op eigen houtje contact ging opnemen met een webbrowser (waarschijnlijk zou je continu verveeld worden met commerciële websites waar je niet om gevraagd hebt). Toch kan het voor applicaties belangrijk zijn dat zij op de hoogte worden gehouden van de laatste wijzigingen. Denk bijvoorbeeld aan een applicatie die de aandelenkoersen laat zien of een nieuwsapplicatie die steeds het laatste nieuws wil laten zien (real-time informatie). Met de huidige webarchitectuur is dat eigenlijk niet mogelijk. Gelukkig zijn er slimme mensen die hierop iets bedacht hebben. Hier volgen een paar technieken:

  1. Polling. De browser doet herhaaldelijk, na een x aantal seconden, een request naar de webserver. Dit kan de webbrowser zelf doen of je gebruikt het XmlHttpRequest object (een onzichtbaar minibrowsertje in de webbrowser, het kloppende hart achter de Ajax technologie). Hierbij is alleen de kans groot dat er requests naar een webserver worden gestuurd, terwijl de webserver helemaal geen wijzigingen te bieden heeft.
  2. Pushlets. Met deze techiek wordt de webbrowser eigenlijk aan het lijntje gehouden. De browser doet een request naar de webserver die een response stuurt, maar de webserver zal de response nooit afsluiten. De webbrowser blijft dus continu laden. De webserver kan nu data naar de webbrowser sturen wanneer het hem uitkomt. Nadeel is de gebrekkige controle over de verbinding en je hebt de webbrowser beroofd van een verbinding hetgeen significante vertragingen kan opleveren omdat webbrowsers steeds maar twee verbindingen tegelijk naar de webserver open mogen hebben.
  3. Long Polling. De webbrowser stuurt een request naar de webserver, maar die reageert pas als hij nieuwe data heeft (opzettelijk laat reageren). Dit pakketje wordt dan naar de webbrowser gestuurd waarna het hele spel opnieuw begint.
  4. WebSockets. Nieuw in html5. Met WebSockets worden alle hierboven genoemde kunstgrepen naar de eeuwige internetvelden verwezen. Met WebSockets kan een duplexverbinding tussen webbrowser en webserver worden opgezet. Als die duplexverbinding eenmaal is opgezet, kan de webserver op ieder moment data naar de webbrowser sturen en visa versa. Nadeel is wel dat je een moderne browser moet hebben die WebSockets ondersteunt (Zie caniuse voor ondersteuning)
WebSockets is met afstand de meest gewenste oplossing, maar je zult maken krijgen met webbrowsers die WebSockets niet ondersteunen. Voor die clients zul je de oudere technieken moeten toepassen. Hier is SignalR nu heel handig in.


SignalR (R = Realtime) is een toolkit waarmee men real-time webapplicaties kan maken. Het is op zich niet nieuw. SignalR was al een tijdje via Nuget te krijgen en met de Visual Studio 2012.2 update waren ook de templates beschikbaar. De kracht van SignalR zit hem in het gegeven dat het helemaal gebouwd is om snelheid en support. In de basis zal SignalR gebruik maken van WebSockets, maar als die niet voorhanden zijn, zal SignalR moeiteloos omschakelen naar Comet technieken, zoals pushlets en long polling.

Hoogste tijd om SignalR eens in de praktijk te testen. Hiervoor heb ik in Visual Studio 2013 Preview eerst een leeg MVC-project aangemaakt. De volgende stap is een SignalR Hub class toevoegen aan het project. Dit kan het best via het contextmenu/Add New Item (afbeelding 1). 

Afbeelding 1. De SignalR template.

De template zal ook de nodige referenties leggen en wat Javascripts toevoegen. De (gemodificeerde) genereerde class zie je hieronder.

public class MySignalRHub : Hub
{
    public void Verstuur(string message)
    {
        Clients.All.straalUit(message);
    }
}
MySignalHub is een class die erft van de class Hub, een class uit de SignalR bibliotheek. De Hub class is eigenlijk de service waar alle commando's binnenkomen. De Verstuur methode bevat een dynamische aanroep (straalUit) op de SignalR property Clients.All. Het aparte van deze methode is dat hij niet bestaat. Je kunt hem dus noemen zoals je wilt en argumenten specificeren die je wilt. Geloof het of niet, de service is nu gereed. Nu moeten we alleen nog een url voor de service specificeren. Dat doe je in de Global.asax, in de Application_Start methode via de extensie MapHubs die standaard de route "/signalr" aanmaakt.

protected void Application_Start()
{
    RouteTable.Routes.MapHubs();

    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}
Aan de servicekant ben je nu helemaal klaar. Helaas bleek in de preview van Visual Studio 2013 de extensie MapHubs onvindbaar. Na het verwijderen van SignalR en opnieuw toevoegen in Nuget, bleek dat probleem opgelost.

Het clientgedeelte is niet veel lastiger. Je voegt eerst de volgende javascripts toe

<script src="~/Scripts/jquery-1.6.4.min.js"></script>
<script src="~/Scripts/jquery.signalR-1.1.2.min.js"></script>
<script src="/signalr/hubs"></script>
De laatste referentie naar "/signalr/hubs" zal een javascript opleveren dat een aantal handige objecten bevat. Die objecten zijn gegenereerd op basis van jouw Hub class en verdient daardoor dan ook de naam Hub-proxy. Hieronder staat de rest van de client implementatie waarbij #message een textbox is, #send een button en #values een leeg <ul> element.

<script type="text/javascript">
    $(function ()
    {
        var proxy = $.connection.mySignalRHub;
        proxy.client.straalUit = function (message)
        {
            $('<li/>').appendTo("#values").text(message);
        };

        $.connection.hub.start().done(function ()
        {
            $('#send').click(function ()
            {
                proxy.server.verstuur($('#message').val());
                $('#message').val('');
            });
        });
    });
</script>
De variabele "proxy" is een instantie van de gegenereerde Hub-proxy mySignalRHub (die niet geheel toevallig ook de naam van de Hub draagt). Merk op dat de methodenamen uit de Hub-class ook netjes zijn overgenomen. Voor de client is dit alles wat je hoeft te doen. 

SignalR is een prachtig tool om real-time webapplicaties te bouwen. Het neemt een heleboel complexiteiten uit handen. Door te erfen van de Hub-class, kunnen we vrij eenvoudig services maken die, naast het onderhouden van de verbindingen, ook nog eens de aangemelde webbrowsers bijhoudt. Als alternatief voor de Hub-class kun je ook erfen van de PersistantConnection class, die basaler is dan de Hub class, maar wel meer controle geeft.
Wanneer het op schaalbaarheid aankomt, laat SignalR zich niet onbetuigd. Met evenveel gemak kan SignalR inhaken op Windows Azure Service Bus (bijvoorbeeld via Topic/Subscription) waardoor het geheel ook in Windows Azure goed draait (hoe dat moet, zie je in deze deze blog).

Ik kan niet anders zeggen dat de makers van SignalR een erg mooi product hebben afgeleverd. Ooit heb ik een multi-user game geschreven op basis van WebSockets. Als ik toen van SignalR had geweten, had mij dat veel tijd en moeite gescheeld.

Meer informatie over SignalR:

woensdag 10 juli 2013

Less - Dynamic Stylesheets in ASP.NET MVC 5

Een paar weken geleden is de eerste preview van Visual Studio 2013 uitgekomen. Over een aantal verbeteringen heb ik in mijn vorige blog al geschreven. In deze preview kunnen we ook kennis maken met ASP.NET MVC 5. Deze versie ondersteunt een aantal handige tools, zoals Twitter Bootstrap, SignalR, CoffeeScript en Less. Over Less wil ik het in deze blog hebben.
Al tijden gebruiken webontwikkelaars Cascading StyleSheets (css) voor het uiterlijk van webpagina's. Je hebt html dat aangeeft wat er op de pagina komt te staan en css dat verantwoordelijk is hoe de inhoud van de pagina eruit komt te zien. Hierbij moet je denken aan kleuren, lettertypes, afmetingen en allerlei gelikte effecten. Het grote nadeel van css is dat het vrij statisch is. In de praktijk resulteert dat in veel dubbele code. Natuurlijk kan een handig css-schrijver veel van deze problemen omzeilen, maar helaas is niet iedereen een ster in css. Met Less kunnen je als het ware css programmeren. Hieronder een voorbeeld dat het nut van Less duidelijk maakt.

.style1
{
    background-color:#7F34D3;
}

.style2
{
    color:#7F34D3;
}

.style3
{
    border: 0.2rem solid #7F34D3;
}

Natuurlijk is dit een nogal absurd voorbeeld, maar het komt vaak voor dat kleurcodes her en der in stylesheets opduiken. Ga die later dan maar eens aanpassen. Bovendien zegt #7F34D3 natuurlijk helemaal niets.
Met Less zou hetzelfde script er als volgt uitzien.

@paars#7F34D3;

.style1
{
    background-color:@paars;
}

.style2
{
    color:@paars;
}

.style3
{
    border: 0.2rem solid @paars;
}

Het eerste dat opvalt, is het statement @paars. Dit is in Less een variabele. Achter de ":" staat dan de waarde van die variabele. Merk op dat de variabele @paars nu overal gebruikt kan worden hetgeen de leesbaarheid en het hergebruik aanzienlijk bevordert.

Natuurlijk begrijpt een browser helemaal niets van dat gebrabbel. Vandaar dat er een compiler aanwezig moet zijn die dit alles vertaalt naar echt css. Deze compiler heb je in twee varianten: Een JavaScript versie voor de client en eentje voor op de server. Om de serverversie te gebruiken, moeten we eerst een compiler downloaden. Dat kan het eenvoudigst via nuget. De benodigde compiler voor .NET heet dotless. Nuget zal ook de benodigde referenties (dotless.Core) leggen en de web.config in orde maken. Hieronder zie je de wijzigingen die nuget maakt (andere zaken zijn eruit gelaten).

<configuration>
  <configSections>
    <section name="dotless" type="dotless.Core.configuration.DotlessConfigurationSectionHandler, dotless.Core" />
  </configSections>
  <system.web>
    <httpHandlers>
      <add path="*.less" verb="GET" type="dotless.Core.LessCssHttpHandler, dotless.Core" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <handlers>
      <add name="dotless" path="*.less" verb="GET" type="dotless.Core.LessCssHttpHandler,dotless.Core" resourceType="File" preCondition="" />
    </handlers>
  </system.webServer>
  <dotless minifyCss="false" cache="true" web="false" 
               handleWebCompression="false" />
</configuration>

Belangrijk hierbij zijn de httpHandlers waarbij de extensie .less wordt gekoppeld aan de compiler. Wanneer er een request met een .less extensie binnenkomt, zal het .less-bestand gecompileerd worden en het resultaat (puur css) wordt naar de client gestuurd. Bij het dotless element kun je verder nog aangeven of het script gecomprimeerd en/of gecached moet worden. Het attribuut handleWebCompression is nodig omdat het anders niet werkt in Visual Studio 2013.

De infrastructuur is nu in orde. Tijd om Less te gebruiken. Aan het webproject voegen we een "LESS Style Sheet" toe via het contextmenu "Add New Item" (afbeelding 1).


Afbeelding 1. Een Less bestand toevoegen.
Laten we eens het eerdere Less-script in een webpagina hangen. Dit gaat op dezelfde manier als bij normale css-bestanden, alleen verwijs je nu naar het .less-bestand.


<link href="~/Content/test.less" rel="stylesheet" />

In afbeelding 2 is het resultaat te zien.


Afbeelding 2. Less in action.
Een ander krachtig concept in Less is Mixings. Mixings kun je het best vergelijken met functies. Het is een verzameling css-eigenschappen die je in andere css-definities aanroept. 

@paars : #7F34D3;

.style1
{
    color:@paars;
}

.style2 (@radius, @color: @paars)
{
    border.2rem solid @color;
    border-radius@radius
}

.style3
{
    .style1;
    .style2(10%);
    opacity:.5;
}
.style1 en .style2 zijn functies (mixins). In .style2 zie je ook het gebruik van parameters (@radius en @color), met @color een optionele parameter. In .style3 worden .style1 en .style2 aangeroepen. Het uiteindelijke resultaat hiervan is hieronder weergegeven.


.style1
{
    background-color#7f34d3;
}

.style2
{
    color#7f34d3;
}

.style3
{
    color#7f34d3;
    border0.2rem solid #7f34d3;
    border-radius10%;
    opacity.5;
}
Less beschikt ook over een aantal operatoren, zoals "+", "-", "*" en "/". Daarbij wordt eventueel gepeuter met eenheden uit handen genomen. Hieronder zie je een aantal voorbeelden.

@screen_width400px;
@box_height@screen_width/4;
@green:#0f0;
@red:#f00;

#container
{
    height@box_height;
}

    #container .small
    {
        float:left;
        min-width: (@screen_width/4);
        background-color:@green;
    }

    #container .medium
    {
        float:left;
        min-width: (2 * (@screen_width/4));
        background-color:@red;
    }

Wanneer dit script door de less-compiler wordt getrokken, leidt dat tot het volgende css:

#container {
  height100px;
}
#container .small {
  floatleft;
  min-width100px;
  background-colorlime;
}
#container .medium {
  floatleft;
  min-width200px;
  background-colorred;
}

In Less heb je de beschikking over guards. Guards kun je zien als condities, zoals je die ook in if/else instructies tegenkomt. Hiervoor wordt het speciale sleutelwoord "when" gebruikt. Uiteraard kunnen meerdere condities gespecificeerd worden. Voor een "OR" gebruik je dan de komma "," en voor de "AND" het sleutelwoord "and". Ook "NOT" wordt ondersteund. Hieronder volgt een less-script dat laat zien hoe guards werken.

@screen_width400px;
@green:#0f0;
@red:#f00;

.container (@width) when (@width > 100) and (@width < 600)
{
    color:@green;
}
.container (@width) when (@width =< 100), (@width >= 600)
{
    color:@red;
}

#block1
{
    .container(800px);
}
#block2
{
    .container(500px);
}

Dit script resulteert in het volgende css:

#block1 {
  background-colorred;
}
#block2 {
  background-colorlime;
}
Natuurlijk biedt Less nog veel meer functionaliteiten. Zo kun je namespaces definiëren waarin je mixins plaatst, er is een grote set aan voorgedefinieerde functies en je kunt zelfs javascriptfuncties door Less laten uitvoeren, hoewel dat sterk afgeraden wordt. Meer hierover op de website van Less.

Less is een sterk tooltje waarmee css wordt gegenereerd. Alles wat je in less kunt, zou je natuurlijk ook zonder less kunnen doen. De kracht van Less zit echter in het hergebruik binnen css en de structurering van de code die in css erg gecompliceerd kan zijn. Bovendien kunnen less-scripts opgenomen worden in bundles, een techniek in ASP.NET waarmee meerdere scripts tot één groot script wordt gebundeld, daarmee kostbare round trips besparend. Kortom, een aanrader.