Windows Azure Websites and Storage

Windows Azure Websites zijn erg handig om snel een website in de lucht te brengen. Je kunt daarbij kiezen uit een gallery van producten. Deze gallery bestaat uit Blogs (WordPress ea), Content management systemen (DotNetNuke ea), Wiki’s etc. En als je door deze lijst heen loopt, dan zie je dat ze niet allemaal .NET based zijn. Sommige producten hebben SQL Server database nodig en sommige MySQL. Ook dat is geen probleem beide is mogelijk. Met een paar simpele klikken heb je zo een website in de lucht.

eval1

Maar als je een reeds bestaande website hebt, dan kun je die ook hosten op Windows Azure websites. Ook dan ben je met iets meer klikken up en running. Moet je in je website dan nog rekening houden met het hosten op Windows Azure? Nope, helemaal niet. Aan je website hoef je niets aan te passen en deze kan zo naar Windows Azure. En updates aan de website kun je dan gewoon deployen oftewel publishen zoals je dat ook op een ‘eigen’ webserver zou doen.

eval7

Oke, maar ik wil gebruik maken van Windows Azure storage of Windows Azure Service bus. Dat kan dan zeker niet? Jazeker wel, geen probleem. Uiteraard moet je in je applicatie dan wel iets aanpassen om volledig gebruik te maken van deze diensten.

Ik heb dat zelf gebruikt voor de server kant van mijn nieuwe Windows 8 en Windows Phone 8 applicatie. Met deze applicaties kun je de sessies van de SDN events evalueren en je waarde oordeel geven.

eval4eval5

Het gaat hier niet om enorm veel data. Ik heb events en event hebben sessies en een sessie heeft een evaluatie. Er zijn ook geen hele moeilijke relaties tussen tabellen. Dus typisch zo’n gevalletje voor Windows Azure storage tables. Ook vanuit kosten oogpunt niet onbelangrijk. Zoals gezegd, het gaan niet om veel data. Stel even 3 events maal maximaal 20 sessies maal 150 bezoekers, dat blijft heel erg ruim onder de 100 Mb van de kleinste Windows Azure SQL Database. Het prijsverschil tussen storage tables en SQL tabellen is dan best groot. (NB Ik realiseer mij dat we soms SQL server functionaliteit gewoon nodig hebben, maar ik denk ook wel dat we vaak te gauw grijpen naar dit middel.

Deze data ontsluit ik voor de applicaties via een WebApi. Zodat de apps via een simpele REST interface de get en posts kunnen doen en JSON terug krijgen. En deze REST services zijn onderdeel van mijn Windows Azure Website.

Maar kan dat dan zomaar? Jazeker. Alles wat je nodig hebt, zijn deze twee NuGet packages.

eval2

En deze code. De connectionstring naar de Windows Azure storage staat dan in de Web.config.

eval3

De rest van je code is zoals je altijd met Windows Azure storage tables omgaat.

En mijn groeipad? Windows Azure Websites kun je ook scalen (meerdere instanties) en/of zwaardere machines van maken.

eval6

Stel je voor dat er straks toch een achtergrond proces bij komt, bijvoorbeeld om BI op de ingevoerde data te doen. Dan zou ik daar een WorkerRole voor nodig kunnen hebben. Dan kan ik de Windows Azure Website zo ombouwen tot een Cloud Service. De setting van de storage zal dan verplaatsen van de web.config naar de Cloud Service configuration. Verder hoeft er in principe weinig te gebeuren aan de Web Role. Uiteraard zal ik de Worker Role dan moeten uitwerken.

Handig he, Windows Azure. Het groeit met je mee, je kunt klein beginnen en groeien naar immense hoogte.

Using 32 bit (Legacy) DLL on Windows Azure

Op Windows Azure is (bijna) alles mogelijk. Zo ben je niet beperkt tot alleen applicaties op basis van .NET. Maar ook Java, PHP, NodeJS en nog veel meer talen en taaltjes zijn heel goed bruikbaar op het Windows Azure platform, Windows Azure Websites en Windows Azure Virtual Machine.

Windows Azure is in de basis een 64 bits Windows 2008 server park. Maar ook dan ben je niet beperkt tot het gebruik van alleen 64 bits programma’s of dll’s. Dit is erg prettig, want zo hoef je ‘legacy’ software niet perse te verherbouwen. Of deze legacy nu geschreven is een Microsoft taal of anders maakt dan ook weer niet zoveel uit.

Zo hebben wij voor een klant een Windows Azure Proof of Concept uitgevoerd, waarbij we te maken hadden met een 32 bits C++ dll met een soort memory leak. Het resultaat moest wel in de Cloud kunnen draaien en dan ook nog eens netjes schaalbaar zijn.

legacydll

Hoe hebben we dat aangepakt?

Laten we eerst eens kijken naar de C++ dll. Zoals gezegd dit component heeft een soort memory leak. Vooraf nog even de dll was ooit bedoeld en gebruikt in een stand alone desktop applicaties. De dll is niet echt bedoeld om in een gedistribueerde omgeving te werken. Als het component door 2 websites gelijktijdig aangeroepen werd, dan werd het resultaat van beide berekeningen vermengd met elkaar. De dll heeft een stukje shared memory, dat niet per proces uniek is en daardoor vindt de vermenging plaats. In .NET is dit relatief simpel op te lossen. Door gebruik te maken van een Mutex.

 1: public int Calculate32Mutex()

 2: {

 3:     int result = 0;

 4:

 5:     mutex.WaitOne();

 6:     try

 7:     {

 8:         result = Calculate32(); // calls the actual 32bit dll function

 9:     }

 10:     finally

 11:     {

 12:         mutex.ReleaseMutex();

 13:     }

 14:

 15:     return result;

 16: }

Door het gebruik van de Mutex moet iedere aanroep wachten tot de vorige aanroep klaar is. Dat is vervelend als je een behoorlijke load verwacht. Maar we gaan het op Windows Azure gaan hosten. Daar kunnen we mooi schalen en op deze manier de load aan.

Blijft nog wel het 32 bits probleem. Hiervoor zijn 2 oplossingen.

  1. We kunnen de DLL hosten in een 32 bits Console applicatie.
  2. We kunnen de app pool van IIS in 32 bits mode zetten.

Laten we beide bekijken.

Oplossing 1: Het hosten van de DLL in een 32 bits Console applicatie.

We maken een Console applicatie en geven bij de Build opties aan dat het Platform target x86 is. In de main van deze Console applicatie zetten we dan deze code.

 1: static void Main(string[] args)

 2: {

 3:     Uri address = new Uri("net.pipe://localhost/CalculatorService");

 4:

 5:     NetNamedPipeBinding binding = new NetNamedPipeBinding();

 6:     binding.ReceiveTimeout = TimeSpan.MaxValue;

 7:

 8:     using (ServiceHost host = new ServiceHost(typeof(CalculatorDll)))

 9:     {

 10:         var ff = host.AddServiceEndpoint(typeof(ICalcService), binding, address);

 11:         ServiceMetadataBehavior metadata = new ServiceMetadataBehavior();

 12:

 13:         host.Description.Behaviors.Add(metadata);

 14:         host.Description.Behaviors.OfType<ServiceDebugBehavior>()

 15:             .First().IncludeExceptionDetailInFaults = true;

 16:

 17:         Binding mexBinding = MetadataExchangeBindings.CreateMexNamedPipeBinding();

 18:         Uri mexAddress = new Uri("net.pipe://localhost/CalculatorService/Mex");

 19:         host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexAddress);

 20:

 21:         host.Open();

 22:

 23:         Console.WriteLine("The receiver is ready");

 24:         Console.ReadLine();

 25:     }

 26: }

Met behulp van een named net pipe wordt de service beschikbaar. De methode op deze service bevat dan een call naar de functie in de 32 bits dll.

 1: [DllImport("Win32Project1.dll", SetLastError = true)]

 2: public static extern Int32 Calculate(Int32 delay);

 3:

 4: public int RekenDllExample()

 5: {

 6:     return Calculate(2000);

 7: }

Om dit geheel te kunnen schalen heb ik er voor gekozen om deze achter een ‘normale’ WCF service te hangen. Als je hem rechtstreeks in de Website wil gebruiken, dan kan dat natuurlijk ook. Maar dan wordt het schalen erg beperkt.

Op de WCF service moet dan een koppeling met deze Named Net pipe gemaakt worden. Het handigst is dat te doen in de Global.asax en wel in de Application_BeginRequest methode. Daar heb ik twee methodes: een om de DllHost te starten en een om de koppeling te maken.

 1: string dllHostPath = @"Redist\DllHostx86.exe";

 2: private const int ClientInitTimeOut = 20; // in seconds

 3:

 4: protected void Application_BeginRequest(object sender, EventArgs e)

 5: {

 6:     // Make sure that our dll host is running

 7:     EnsureDllHostRunning();

 8:

 9:     // Make sure the client is connected

 10:     EnsureCalcServiceClientConnected();

 11: }

 12:

 13: private void EnsureDllHostRunning()

 14: {

 15:     Process[] p = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(dllHostPath));

 16:     if (p.Length == 0)

 17:     {

 18:         Application["CalcServiceClient"] = null;

 19:         ProcessStartInfo psi = new ProcessStartInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dllHostPath).ToString());

 20:         Process dllHost = Process.Start(psi);

 21:     }

 22: }

 1: private void EnsureCalcServiceClientConnected()

 2: {

 3:     CalcServiceClient client;

 4:     client = (CalcServiceClient)Application["CalcServiceClient"];

 5:     if (client == null || client.State != System.ServiceModel.CommunicationState.Opened)

 6:     {

 7:         client = GetCalcServiceClient();

 8:         Application["CalcServiceClient"] = client;

 9:     }

 10: }

 11:

 12: private CalcServiceClient GetCalcServiceClient()

 13: {

 14:     CalcServiceClient serv = null;

 15:

 16:     int retryCount = 0;

 17:     bool connected = false;

 18:     while (retryCount < ClientInitTimeOut * 10)

 19:     {

 20:         try

 21:         {

 22:             EndpointAddress address =

 23:                 new EndpointAddress("net.pipe://localhost/CalculatorService");

 24:             NetNamedPipeBinding binding = new NetNamedPipeBinding();

 25:             binding.ReceiveTimeout = TimeSpan.MaxValue;

 26:

 27:             serv = new CalcServiceClient(binding, address);

 28:             serv.Open();

 29:             if (serv.State == System.ServiceModel.CommunicationState.Opened)

 30:             {

 31:                 connected = true;

 32:                 break;

 33:             }

 34:         }

 35:         catch (Exception e)

 36:         {

 37:         }

 38:

 39:         retryCount++;

 40:         System.Threading.Thread.Sleep(100);

 41:     }

 42:

 43:     if (!connected)

 44:     {

 45:         throw new TimeoutException(

 46:             "Couldn't connect to the calculator service.");

 47:     }

 48:

 49:     return serv;

 50: }

In je project moet je dan ook een Service reference leggen naar de DllHost Console applicatie. Dit is relatief eenvoudig. Je start de Console applicatie op en kies voor Add Service Reference. Hierna zijn er in de Web.config endpoint gegevens toegevoegd. Dit endpoint is net.pipe://localhost/CalculatorService. Maak je geen zorgen over Localhost, want de DllHost applicatie en de WCF service die uiteindelijk het endpoint aanroept, draaien in dezelfde instance. Daarmee is localhost altijd waar, ook in de Cloud.

Verder moet je dan een Folder aan je solution toevoegen waarin je de DllHost console app en de 32 bits dll hebt zitten. Vergeet dan niet om de property ‘Copy to Output Directory’ dan te zetten op ‘Copy Always’ or ‘Copy if newer’.

Oplossing 2: We kunnen de app pool van IIS in 32 bits mode zetten

Deze oplossing is het minst ingrijpend. Enige lastige (ik ben geen IT pro meneer) hoe kun je dat doen vanuit een script. Ten slotte kan je alles op een Windows Azure instance zolang je het maar kunt automatiseren. Als het gescript is, dan kun je met een Startup task het script laten uitvoeren en is het helemaal geregeld.

Het commando om dit te doen is:

 1: REM make apppools 32bit

 2: %windir%\system32\inetsrv\appcmd set config

 3:     -section:applicationPools

 4:     -applicationPoolDefaults.enable32BitAppOnWin64:true

Dit commando in een startup.cmd bestand. Plaatsen in het desbetreffende project. In de ServiceDefinition.csdef definiëren we de startup task en we zijn klaar.

 1: <Startup>

 2:   <Task commandLine="startup.cmd" executionContext="elevated" taskType="simple" />

 3: </Startup>

Verder moet je dan een Folder aan je solution toevoegen waarin de 32 bits dll staat. Vergeet dan niet om de property ‘Copy to Output Directory’ dan te zetten op ‘Copy Always’ or ‘Copy if newer’.

Nadeel van de oplossingen:

Als er dynamische configuratie nodig is, dan is de Console applicatie het minst handig. Zoals gezegd het is een Console applicatie met een app.config. Default kan deze niet zomaar uit de Service configuration settings lezen. Bij de andere oplossing kan de Webservice er gewoon wel bij.

Testen

Om de twee oplossingen te testen heb ik een frontend gemaakt. Daarop staan 4 knoppen. De eerste twee knoppen roepen een WCF service aan die gebruik maakt van de Dll Host console applicatie. De laatste twee knoppen roepen een WCF service aan die gebruik maakt van AppPool in 32 bits mode. Er staan labels result, waar een 0 of een 1 of hoger in komt. Als het getal 0 is dan werd de rekenmodule aangeroepen en is er niets gemixt met een andere aanroep. Is het getal groter dan 1 dan is het resultaat gemixt met een andere aanroep. Dit kun je testen door twee browser naast elkaar open te zetten en bij gelijktijdig (er is nog tijd) drukken op de knop zal er een 0 en een 1 verschijnen. Tenzij er meerdere bloglezers op hetzelfde moment aan het testen zijn 😉

Als je dat doet met de Mutex knoppen, dan zal voor beide het resultaat 0 zijn.

http://rekenmoduletest.cloudapp.net

clip_image002

Uiteraard wil je dan weten hoe het met de load zit, daar kom ik in een volgende blogpost op terug. Want uiteraard gaan we dat ook via een Cloud service testen.

Bovenstaand verhaal gaat niet alleen op voor Windows Azure, maar feitelijk voor elke 64 bits server omgeving on premise of bij een andere hosting partij.

Referenties:

Windows Azure SDK for .NET Tools 1.7

Zoals ik in mijn vorige blog post al schreef, hoort bij de Spring aanpassingen van Windows Azure ook een nieuwe SDK. Ik beloofde daarop later terug te komen.

De nieuwe Spring release SDK kun je downloaden op https://www.windowsazure.com/en-us/develop/net/ (English) of https://www.windowsazure.com/nl-nl/develop/net/ (Nederlands). Als je hem daar downloadt, krijg je versie 1.7 van Windows Azure tools for Visual Studio.

Door te klikken op de Install button op deze site, krijg je de keuze voor wel Visual Studio je ze wilt installeren. Dit houdt inderdaad in, dat je verschillende SDK’s voor de twee Visual Studio’s kunt gebruiken. Dat kan erg handig zijn.

clip_image002

Aangezien er voor Visual Studio 2010 nog helemaal geen Windows Azure Visual Studio tools waren, kun je met deze versie nu eindelijk ook Windows Azure applicaties bouwen. Let op de WIF (Windows Identity Foundation) zijn nog niet beschikbaar voor deze versie.

Bij Visual Studio 2012 kun je nu kiezen, welke tools je wilt gebruiken. Daarvoor is er een drop down list op het New Windows Azure Cloud Service scherm gekomen.

clip_image004

Wat opvalt als je de tools update geïnstalleerd heb en je opent een ‘oude’ solution, dat er geen foutmeldingen of migration wizard achtig dingen komen. Dat is erg handig, want nu kun je huidige productie projecten gewoon met de ‘oude’ tools onderhouden en is er geen verplichting om te upgraden. Dat bespaart tijd en kosten.

Betekent dat je zelf handmatig moet upgrade dan? Nee. Op de properties page van Windows Azure Cloud Service project zie je het volgende staan.

clip_image006

Als je dan op de button Upgrade klikt, dan krijg je de verwachtte Migration Wizard.

clip_image008

De grootste verschillen zitten in de volgende bestanden.

‘oude’ SDK

clip_image010

‘nieuwe’ SDK

clip_image012

En de properties van het Windows Azure Cloud project staat dan het volgende.

clip_image014

De update van de Tools is wederom een geweldige toevoeging aan de nieuwe Spring release. Erg mooi is het feit, dat beide SDK’s naast elkaar kunnen werken. Dat maakt het eenvoudiger om op een ontwikkelmachine met meerdere SDK’s te kunnen ontwikkelen.

Nog een reden om hernieuwt te kijken naar Windows Azure als je eerder anders besloten hebt.

Post TechDay event Workshop SSDT (SQL Server Data Tools)

Op zaterdag 18 februari 2012 vond in Baarn bij VX Company het SSDT (SQL Server Data Tools) event plaats. Dit event georganiseerd door VX Company en SDN vond plaats de dag na de TechDays! Op deze zaterdag kwam Gert Drapers speciaal over om een Deep Dive sessie te doen over de SQL Server Data Tools. Om de feestvreugde nog verder te verhogen had Gert de beschikking over de allerlaatste build van de tools. Tijdens zijn sessie werd ook erg veel inside informatie gegeven over de tools zelf, maar ook over de manier waarop ontwikkeld werd.

Het was een goed bezocht en uitermate interessant event. De deelnemers gingen weg met veel dingen waar nog eens naar gekeken moest worden en nieuwe inzichten. Vooral de discussie tijden de koffie breaks, lunch en na afloop waren erg gezellig.

Een filmpje is te vinden op het SDN Watch YouTube kanaal!

Bedankt allemaal voor de aanwezigheid en tot een volgende keer.

Welke .NET versie draai ik

Als je wil weten welke versie van het .NET Framework je allemaal geinstalleerd hebt, dan kun je dat doen door in de registry te zoeken en de directories op je disk te controleren. Maar dit is nogal arbeidsintensief en niet geheel foutloos. Via twitter kwam deze link: http://www.asoft.be/prod_netver.html. Met dit tool kun je precies zien welke versies allemaal geinstalleerd zijn.

nettip

Erg handig!

UPDATE: Via Michel Barneveld kreeg ik deze link door: http://blogs.msdn.com/b/astebner/archive/2008/10/13/8999004.aspx. Deze kan kijken of de frameworks ook goed geinstalleerd is.

NB deze tip heb ik ook laten publiceren in ons SDN Magazine nummer 108.

Visual Studio 2010 SP 1 RTM

De eerste service pack voor Visual Studio 2010 is vanaf nu beschikbaar voor MSDNsubscribers. Een download via Windows Update zal beschikbaar komen vanaf 10 maart.

In dit service pack een groot aantal verzoeken van Visual Studio gebruikers zijn ingewilligd. Onder andere betere help support, IntelliTrace support voor 64 bits en Sharepoint, ook zijn de Silverlight 4 tools nu in de Release meegenomen. Voor .NET 3.5 is unit testing support toegevoegd en een nieuwe performance wizard voor Silverlight toegevoegd.

Meer info: http://blogs.msdn.com/b/jasonz/archive/2011/03/08/announcing-visual-studio-2010-service-pack-1.aspx

Had je de Beta van dit Service Pack al geinstalleerd? Geen nood, de RTM versie kun je installeren over de Beta heen. Je hoeft de beta niet te deinstalleren.

SQL Azure – OLEDB en SQL .NET library

Er is een verschil in het gebruik van de verschillende Database Client libraries om te connecten met SQL Azure.

sqlole1

Als je bovenstaande fout krijgt, dan moet je eens naar je connectionstring kijken. Als je bij de UID niet de naam van SQL Azure server hebt toegevoegd, dan krijg je de foutmelding.

Voor de SQL Server Client libraries gaat het goed, maar bij OleDb gaat het fout.

sqlole3

sqlole2

Het is dan ook handiger om altijd de Servernaam op te nemen na de Username.

Windows Phone 7 Apps – Reviews

Als je applicaties voor Windows Phone 7 maakt en ze in de Marketplace zet (http://create.msdn.com), dan hoop je natuurlijk dat andere je appje downloaden en gebruiken. Ook hoop je dan dat ze een review plaatsen *). Aan de hand van die reviews kun je je app dan verbeteren en aanpassen.

Uiteraard kun je via de marketplace en via de Zune software deze reviews lezen, maar er zijn ook een aantal aardige sites.

Een daarvan is www.appsfuze.com. Op deze site zoek je de app en lees je de reviews.

PhoneReview2

Een andere site van Tom Verhoeff (http://wp7reviews.tomverhoeff.com) geeft net iets meer info. Daarvoor heb je wel de GUID van de applicatie nodig. Maar met bovenstaande site kun je deze achterhalen door de download button.

PhoneReview

Hmm, mijn applicatie komt er niet best vanaf. Ik zal toch iets beters moeten verzinnen Winking smile

*) Het plaatsen van een Review is erg simpel. Op je Windows Phone 7 selecteer je de applicatie (dit kan niet op het hoofdscherm maar op het tweede scherm) en drukt met je vinger op de icoon. Na enkele seconden verschijnt er een menu. In dit menu staan de keuzes “pin to start” , “uninstall” en ook “rate and review”. Door het selecteren van deze keuze wordt je naar de Marketplace gestuurd, waar je de rating en je commentaar kwijt kunt.

menu

Have fun!

Azure Tools 1.3 – Tip

Als je versie 1.3 van de Azure Tools geinstalleerd hebt en je opent een bestaande Azure solution, dan zal deze automatisch bijgewerkt worden. Maar door de toevoeging van Full IIS support is er wel een wijziging in het uitvoeren van de configuratie van de Storage.

Na het openen van een van mijn Test projectjes voor Azure, vond automatisch de conversie plaats. Maar na het starten kreeg ik onderstaande foutmelding.

AzureError

Nadat wat Bingen kwam ik er achter dat het lag aan het moment van lezen van de configuratie van de Azure Storage. Deed je dat voorheen nog in de OnStart van je WebRole. Nu is dat moment niet meer juist. De oplossing is om een Global.ASAX toe te voegen aan je WebRole. In de Application_start methode neem je dan de code over van de OnStart. Daarna werkt alles weer.

Bij het maken van een nieuwe Azure Solution wordt deze Global.asax automatisch toegevoegd. De configuratie moet je uiteraard wel zelf doen.

SQL Azure via Azure Portal

In de nieuwe Azure Portal kun je dus ook je SQL Azure objecten beheren. Klik daarvoor op Database in het menu linksonder.

sqla1

Je ziet dan alle databases behorend bij je subscription. In het plaatje heb ik nu geklikt op een database. Op het niveau van servernaam (het vierkanten zwarte blok) kun je de firewall instellingen doen etc.

sqla2

Als je kiest voor manage, dan opent er een nieuw scherm. In dit scherm vind je Project Houston terug. Wel in een betere kleur, de oude was erg donker.

sqla3

sqla4