Sonntag, 31. Januar 2010

Dallas oder Denver Clan?

Unter dem Codenamen “Dallas” hat Microsoft ein neues Produkt vorgestellt, welches einem ermöglicht auf statistische Daten zuzugreifen. Diese Daten werden in einem Microsoft Data Center zentral von unterschiedlichen Anbietern (z.B. Behörden, Firmen) zur Verfügung gestellt und können dann über die Azure Plattform von Entwicklern gelesen werden. Die Abrechnung des Zugriffs erfolgt zentral über die Windows Azure Bezahlservices(Live-Plattform).
In der jetzigen CTP-Phase kann man über Microsoft Connect einen Invitation Code beantragen, womit man dann über seinen Live-Zugang diesen Dienst registrieren kann. Registrierung erfolgt über https://www.sqlazureservices.com/
Zur Zeit werden u.a. die Datendienste von
  • Data.Gov (Kriminalstatistik von den USA)
  • InfoUSA Business Analytics U.S., U.K. and Canada (Geschäftsdaten aus den USA und Kanada)
  • NASA Mars Exploration Rover Mission Images (Bilder von der Mars Expedition – ziemlich cool)
  • UNESCO UIS Data (Statistische Daten zu Ausbildung, Wirtschaft, Technik)
Dallas Ressourcen
Ein beispielhafter Zugriff auf diese Daten ist dann recht einfach und sieht so aus:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Dallas.Services;

namespace ConsumingDallasData
{
    class Program
    {
        static void Main(string[] args)
        {
            // Specify the account key and unique user ID to use for the query
            string accountKey = "";
            string uniqueUserId = "";
            // Create a service proxy with which to execute the query. Note that the 
            // service proxy requires the
            // account key and unique user ID
            FAO3510Service service = new FAO3510Service(accountKey, new Guid(uniqueUserId));

            List results = service.Invoke(null, null);

            // Set up a header row for the results
            Console.WriteLine("{0,13}{1,24}{2,18}{3,7}{4,10}", "Series Code", "Country or Area Code", "Country or Area", "Year", "Value");

            // Iterate through the result set
            foreach (FAO3510Item item in results)
            {
                Console.WriteLine("{0,13}{1,24}{2,18}{3,7}{4,10}", item.SeriesCode, item.CountryOrAreaCode, item.CountryOrArea, item.Year, item.Value);
            }

            Console.ReadLine();

        }
    }
}

Die Service-Proxy-Klasse bekommt man über https://www.sqlazureservices.com/Subscriptions.aspx generiert. Die Abfrage der Daten kann auch über eine REST-konforme Query (z.B. Bild der Mars Mission) erfolgen:

// REST Call

            // Establish a Web Request to the Dallas Dataset Url
            string url = "https://api.sqlazureservices.com/NasaService.svc/MER/Images/1F128724129RSD0211P1003L0MZ?$format=raw";
            WebRequest request = WebRequest.Create(url);
            // Specify the request headers containing our account key and unique user ID
            request.Headers.Add("$accountKey", accountKey);
            request.Headers.Add("$uniqueUserID", uniqueUserId);
            // Get the response
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            // Write the status of the response to the Console
            Console.WriteLine(response.StatusDescription);
            // Wait for input from the user
            Console.ReadLine();
            // Get the stream containing content returned by the server.
            Stream dataStream = response.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            // save as file
            const int BUFFER_SIZE = 1024 * 1024;
            using (FileStream f = new FileStream(@"C:\one.png", FileMode.OpenOrCreate))
            {
                    var bytes = new byte[BUFFER_SIZE];
                    while (true)
                    {
                        var n = dataStream.Read(bytes, 0, BUFFER_SIZE);
                        if (n == 0)
                        {
                            break;
                        }
                        f.Write(bytes, 0, n);
                    }
                    f.Flush();
                    f.Close();
                }


            // Cleanup the streams and the response.
            response.Close();

Donnerstag, 28. Januar 2010

Clean, cleaner, cleanest Code

Wer sich mit clean-code-development beschäftigt (und das sollte jeder gute Entwickler) findet auf der clean-code-development-Seite nicht nur nützliche Tips, sondern auch jede Menge Tools zur Code-Diagnose.

Windows Azure Training Kit

Beschäftige mich seit mehreren Tagen mit dem Windows Azure Training Kit.
>hier besorgen

Das braucht man noch für Vista SP 1:
- Windows Azure Software Development Kit
- KB967631 - Update for Visual Studio 2008 SP1 Debugger
- Update: Das FastCGI-Modul

Bei IIS muss man dann noch über Systemstuerung->Programme-> Windows Funktionen ein-/auschalten die Funktionen ASP.NET und CGI in Internetinformationsdienste/WWW-Dienste/Anwendungsentwicklungsfeatures aktivieren.

Ggf. noch das Visual Studio Service Pack 1

Was einem dann auffällt, ist die seltsame Mischung der Sprachen C# / VB.Net (:-() bei dem Demoprojekt Guestbook. Habe deshalb mal den Worker - einer der Rollen innerhalb eines Cloud-Projekts - in C# umgeschrieben:


// Comment 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;
using GuestBook_Data;
using System.Drawing;

namespace GuestBook_WorkerRole
{
    public class WorkerRole : RoleEntryPoint
    {

        private CloudQueue queue;
        private CloudBlobContainer container;

        public override void Run()
        {
            // This is a sample worker implementation. Replace with your logic.
            Trace.TraceInformation("Listening for queue messages...");

            while (true)
            {

                try
                {
                    CloudQueueMessage msg = queue.GetMessage();
                    if (msg != null)
                    {
                        var messageParts = msg.AsString.Split(',');
                        var uri = messageParts[0];
                        var partitionKey = messageParts[1];
                        var rowkey = messageParts[2];
                        Trace.TraceInformation("Processing image in blob '{0}'.", uri);

                        CloudBlockBlob imageBlob = container.GetBlockBlobReference(uri);
                        MemoryStream image = new MemoryStream();
                        imageBlob.DownloadToStream(image);
                        image.Seek(0, SeekOrigin.Begin);

                        String thumbnailUri = String.Concat(Path.GetFileNameWithoutExtension(uri), "_thumb.jpg");
                        CloudBlockBlob thumbnailBlob = container.GetBlockBlobReference(thumbnailUri);
                        thumbnailBlob.UploadFromStream(CreateThumbnail(image));

                        GuestBookEntryDataSource ds = new GuestBookEntryDataSource();
                        ds.UpdateImageThumbnail(partitionKey, rowkey, thumbnailBlob.Uri.AbsoluteUri);

                        queue.DeleteMessage(msg);

                        Trace.TraceInformation("Generated thumbnail in blob '{0}'.", thumbnailBlob.Uri);
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(1000);
                    }
                }
                catch (StorageClientException e)
                {
                    Trace.TraceError("Exception when processing queue item. Message: '{0}'", e.Message);
                    System.Threading.Thread.Sleep(5000);
                }

            }
        }

        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;

            DiagnosticMonitor.Start("DiagnosticsConnectionString");

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += RoleEnvironmentChanging;



            Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
                {
                    configSetter(Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName));
                });


            var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

            var blobStorage = storageAccount.CreateCloudBlobClient();
            container = blobStorage.GetContainerReference("guestbookpics");

            var queueStorage = storageAccount.CreateCloudQueueClient();
            queue = queueStorage.GetQueueReference("guestthumbs");

            Trace.TraceInformation("Creating container and queue...");

            var storageInitialized = false;
            do
            {
                try
                {
                    container.CreateIfNotExist();
                    var permissions = container.GetPermissions();
                    permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                    container.SetPermissions(permissions);

                    queue.CreateIfNotExist();
                    storageInitialized = true;
                }
                catch (StorageClientException e)
                {
                    if (e.ErrorCode == StorageErrorCode.TransportError)
                    {
                        Trace.TraceError("Storage services initialization failure. "
                          + "Check your storage account configuration settings. If unning locally, "
                          + "ensure that the Development Storage service is running. Message: '{0}'", e.Message);
                        System.Threading.Thread.Sleep(5000);
                    }
                    else
                        throw;
                }


            } while (!storageInitialized);


            return base.OnStart();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }

        private Stream CreateThumbnail(Stream input)
        {
            Bitmap orig = new Bitmap(input);
            int width;
            int height;

            if (orig.Width > orig.Height)
            {
                width = 128;
                height = 128 * orig.Height / orig.Width;
            }
            else
            {
                height = 128;
                width = 128 * orig.Width / orig.Height;
            }
            Bitmap thumb = new Bitmap(width, height);

            using (Graphics graphic = Graphics.FromImage(thumb))
            {
                graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                graphic.DrawImage(orig, 0, 0, width, height);
                MemoryStream ms = new MemoryStream();
                thumb.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                ms.Seek(0, SeekOrigin.Begin);
                return ms;
            }
        }
    }
}