Posts mit dem Label Windows Azure werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Windows Azure werden angezeigt. Alle Posts anzeigen

Montag, 16. Mai 2011

Windows Phone 7: Update for Windows Azure Toolkit

Microsoft has now released the third update of the Windows Azure Toolkit for Windows Phone in less than two months – shows that they are hard working on good Windows Azure support for Windows Phone.

One of the new features is the support for Windows Azure Access Control Services.

More details here: Update to Windows Azure Toolkit for Windows Phone 7 « Michael S. Collier's Blog

Freitag, 3. Dezember 2010

Traps of Windows Azure Development

My personal traps of Windows Azure development for this week are:

  • Problems with long project names (longer 248) for the temporary name of my delivery package for running at the Windows Azure emulator
    • Use _CSRUN_STATE_DIRECTORY as environment variable to shorten the path
  • Remove PlatformTarget from an existing Web project file to avoid compile error
  • Strange CommunicationObjectFaultedException error if you use a Source Safe tool and your web.config is read only
  • If you use assemblies that are not content of a normal Windows Server 2008 SP2 installation (for example RIA Services), you have to set the properties “Copy Local” to true of the assemblies involved – otherwise you get a never ending “busy” state of your web role at Windows Azure Management Tools

Windows Azure: CommunicationObjectFaultedException

If your web.config is read only you get maybe the following strange error message in a Windows Azure project at runtime. It costs my half a day to find out, that this has nothing to do with my web service configuration or web service usage.

image

Mittwoch, 1. Dezember 2010

Hosting Silverlight Application with RIA Services as Cloud Service

We have an existing web project (Silverlight 4, WCF RIA Services) that we wanted to bring to the cloud using Windows Azure.  We added a new project, Windows Azure Cloud Service and added a new Web Role.  After this you can connect your existing web project to this web role. The isolated web project compiles fine, but our new solution brings the following compile error:

    “Error      1             The "CreateRiaClientFilesTask" task failed unexpectedly.System.Web.HttpException (0x80004005): Could not load file or assembly 'msshrtmi' or one of its dependencies. An attempt was made to load a program with an incorrect format. ---> System.Configuration.ConfigurationErrorsException: Could not load file or assembly 'msshrtmi' or one of its dependencies. An attempt was made to load a program with an incorrect format. ---> System.BadImageFormatException: Could not load file or assembly 'msshrtmi' or one of its dependencies. An attempt was made to load a program with an incorrect format.”

Strange, what happens and what can we do?

The solution is very easy, but hard to find out: You have to unload your .web project (which hosts the Silverlight application) and edit it the project file.  If you now remove the tags

    <PlatformTarget>AnyCPU</PlatformTarget>
from the project file, your solution can be compiled !

Samstag, 10. April 2010

Facts of the week

Da ich mich zur Zeit intensiv mit den Themen Cloud Computing mit Windows Azure und Silverlight Business Applications beschäftige, möchte an dieser Stelle mit einem “facts of the week” (wenn möglich wöchentlich) einige Erkenntnisse bzw. Wissenwertes bloggen. Kann sein, das die Informationen nicht immer ganz strukturiert sind, aber ich werde immer versuchen, das entsprechende Themengebiet kurz zu umreißen.

Also let’s start:

Kein Browser-Fenster starten, beim Debuggen einer Windows Azure-Anwendung in der DevFabric.
Configuration der Rolle->Startup action Launch Browser for Http Endpoint nicht ankreuzen

Windows Azure: Lokaler Speicher einer Instanz (nicht der Storage von Windows Azure)

· The local storage is not shared between instances

Tracen von Windows Azure Anwendungen

Windows Azure nutzt den Storage zur Ablage von allen möglichen Logs (IIS, Windows,…siehe unten….) und den Trace.WriteLine Informationen. Hierzu ist notwendig:

Web.Config (alle gewünschten Listener hinzufügen)

<system.diagnostics> 
<trace autoflush="false" indentsize="4"> 
<listeners> 
<add name="AzureDiagnostics" 
type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> 
</listeners> 
</trace> 
</system.diagnostics>

Trace.WriteLine("Hier ist ein KRITISCHER Log-Eintrag", "Critical");
Trace.WriteLine("Hier ist eine INFORMATION für das Log", "Information");

Beim Zugriff auf den Azure Storage, von wo aus die Logs dann auf dem üblichen Weg (Storage API oder Webservices) ausgelesen werden können, können die Logs nach Datentyp, Level und Zeitraum gefiltert werden. Die folgende Tabelle gibt einen Überblick über die möglichen Informationsquellen für die Anwendungsüberwachung und Analyse.

Datenquelle

Standardkonfiguration

Konfiguration

Format

Trace Logs

aktiviert, lokal gespeichert

Diagnostics API, Trace Listener

Table

Performance Counters

deaktiviert

Diagnostics API

Table

Windows Event Logs

deaktiviert

Diagnostics API

Table

Infrastruktur-Logs

aktiviert, lokal gespeichert

Diagnostics API

Table

IIS Logs

aktiviert, lokal gespeichert

Diagnostics API, Web.config

Blob

IIS Failed Request Logs

deaktiviert

Diagnostics API, Web.config

Blob

Application Crash Dumps

deaktiviert

Diagnostics API, Crash API

Blob

Beliebige Logs & Dateien

deaktiviert

Diagnostics API

Blob

       

Die wichtigsten Windows Azure Bibliotheken

  • Microsoft.WindowsAzure
    Über die Klassen dieses Namespaces können die Credentials für Windows Azure Storage Accounts verwaltet werden
  • Microsoft.WindowsAzure.ServiceRuntime
    Klassen in diesem Namespace erlauben die Interaktion mit der Windows Azure-Umgebung aus einer Role heraus
  • Microsoft.WindowsAzure.Diagnostics
    Die Klassen aus diesem Namespace werden für die Sammlung von Logging- und Diagnosemeldungen benötigt
  • Microsoft.WindowsAzure.Diagnostics.Management
    Klassen dieses Namespaces können dazu verwendet werden Logging- und Diagnoseinformationen auszulesen
  • Microsoft.WindowsAzure.StorageClient
    Dieser Namespace umfasst die Klassen für den Zugriff auf den Windows Azure Storage Service. Die betreffenden Klassen waren während der CTP-Phase im Namespace Samples enthalten.
  • Microsoft.WindowsAzure.StorageClient.Protocol
    Klassen aus diesem Namespace stellen Wrapper für den Zugriff auf den Windows Azure Storage via REST-Protokoll zur Verfügung.

Windows Azure Version angeben

Spätestens nach Erscheinen der OS-Version 1.1 (Februar 2010) ist es notwendig, die OS-Version zu konfigurieren, die man in der Staging- bzw. Prod-Umgebung auf dem Windows Azure Space benutzt. Dies geschieht in der Windows Azure Service Configuration Datei. Die Eigenschaft osVersion kann dann folgenden Wert haben:

WA-GUEST-OS-M.m_YYYYMM-nn

Where:

WA-GUEST-OS is a fixed string
M.m refers to the major and minor versions
YYYY refers to the year
MM refers to the month

!Wichtig!:
If this attribute is omitted from the configuration file when you deploy your service, the service is deployed to the default version of the operating system; the default version is undefined.

Cross domain calls for Silverlight client

Ein Silverlight Client lässt standardmäßig nur den Aufruf von Webservices aus der Web-Domäne zu, von der der Silverlight-Client herunter geladen wurde. In manchen Fällen möchte man aber zum Beispiel einen Webservice per WCF (SOAP) aufrufen oder einen POX- bzw. REST-konformen Call per WebClient oder HttpRequest machen. Um dies zu ermöglichen, müssen in der aufgerufenen Domäne im Root die zwei Dateien clientaccesspolicy.xml und ggf. auch crossdomain.xml vorhanden sein.

In meinem konkreten Szenario hatte ich ein Windows Azure-Projekt mit mehreren Web-Roles. Da jede Web-Role (bei mir eine Webservice-Role) eine eigene Adresse hat, ist jeder Aufruf vom Silverlight-Client ein Cross Domain Access. Wenn man nun die unten beschriebene Policy-Datei clientaccesspolicy.xml  in das WebService-Projekt im Root anlegt, erlaubt man Silverlight auch auf diesen WebService außerhalb seiner Download-Domäne zuzugreifen.

Die Policy-Datei crossdomain.xml ist eine Alternative, dessen Format ursprünglich von Adobe Flash kommt. Im Unterschied zur clientaccesspolicy.xml muss man in dieser Datei den Zugriff von jeder beliebigen Domäne auf den Webservice erlauben. Macht man dies nicht, wird der Cross domain call von Silverlight nicht akzeptiert.

In der clientaccesspolicy.xml kann man hingegen, den Zugriff auf den Webservice von bestimmten Domänen einschränken (allow-from->domain). Ist also die Verwendung dieser Policy-Datei zu präferieren.

clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>
crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

Bei beiden Dateien müssen, damit diese auch in die Silverlight XAP gepackt werden, die Attribute Content und Copy if newer gesetzt werden.

Donnerstag, 8. April 2010

Silverlight Client with WCF Service hosted on cloud (Windows Azure)

Nach einigen Stunden Config-Debugging möchte ich mal meine wesentlichen Informationen für Einstellungsarbeiten und Patch-/Hotfix-Installation geben, wenn man für folgendes Szenario eine Anwendung entwerfen möchte:

“Ein Silverlight-Client in der Cloud (Windows Azure)” nutzt einen ebenfalls in der Cloud gehosteten Webservice (basicHttpBinding)”

Betriebssystem: Windows 7
Webserver: IIS 7.5
Visual Studio: 2008 (SP1)
.NET: 3.5 (SP1)
CloudService: 1.1 (Feb. 2010)

Damit eine Windows-Azure Anwendung läuft, muss man über einen lauffähigen IIS verfügen. Als Entwickler nimmt man hierfür am besten den lokalen IIS auf dem eigenen Rechner. Für meinen IIS habe ich über die Funktion Control Panel->Programs and Features->Turn Windows features on or off folgende Einstellungen vorgenommen:

image  

Wichtig ist die Aktivierung der “Windows Communication Foundation HTTP Activation” unter Microsoft .NET Framework 3.5.1.

Hotfix für WCF mit .NET Framework 3.5 unter Windows 7 oder Windows Server 2008 R2

Diese Hotfix-Sammlung http://support.microsoft.com/kb/981002/en-us muss installiert werden, damit die WCF Services in der obigen Konfiguration unter Windows Azure ohne Fehlermeldung arbeiten.

In der Web.Config seiner WebRole (von dem Windows Azure-Part des Projekts) muss der betroffene Service mit folgendem Behaviour definiert werden:

<behavior name="LoadBalancedBehavior">
         <serviceMetadata httpGetEnabled="true" />
         <serviceDebug includeExceptionDetailInFaults="true"/>
         <useRequestHeadersForMetadataAddress>
           <defaultPorts>
             <add scheme="http" port="81" />
             <add scheme="https" port="444" />
           </defaultPorts>
         </useRequestHeadersForMetadataAddress>
       </behavior>

Info: Windows Azure Web-Dienste oder Webrollen laufen immer ab Port 81 und werden z.B. als http://127.0.0.1:81/Services/Service1.svc adressiert.

Bei der Generierung der Proxy-Klassen für den Silverlight-Client muss man dazu entweder eine zweite Visual Studio-Instanz aufmachen – damit erkennt Visual Studio den laufenden Service unter der Port 81-Adresse (ansonsten bekommt man die Adresse mit localhost:xxxxx des Cassini-Webservers) – oder man macht nach der Generierung der Proxy-Klassen ein Suchen/Ersetzen des http://localhost:xxxx/Services/Service1.svc durch http://127.0.0.1:81/Services/Service1.svc.

Ein weitere Falle, in die man rein treten kann ist, das der MIME-Type im IIS für .xap nicht definiert ist. Hier hilft dann folgendes:

To ensure solutions containing Silverlight clients work correctly in the development fabric, please ensure that the MIME type for the Silverlight .xap extension is configured correctly in IIS.

1. Open Internet Information Services (IIS) Configuration Manager and select the server to manage (usually the top-level item on the left side)

2. Double-click MIME Types on the right side

3. Add an entry to map the .xap extension to the application/x-silverlight-app MIME type

Um den Silverlight-Client debuggen zu können, kann man überprüfen, ob der ensprechende Haken in der Web-Rolle gesetzt ist:

If for some reason (say if you were doing Javascript debugging "you cannot debug Silverlight code and JavaScript code at the same time." or you didn't select "Enable Silverlight debugging when you created the Silverlight project) you disabled the Silverlight debugger, you can re-enable it on the Web tab of the Web Application project settings (lower right corner):

Mehr Informationen zum Thema Debugging von Windows Azure-Applikationen findet man übrigens hier: http://msdn.microsoft.com/en-us/library/cc838267(VS.95).aspx

Donnerstag, 4. Februar 2010

Windows Azure - Lock Mechanismen

Wenn man sich mit der Architektur von Windows Azure Applikationen beschäftigt kommt man irgendwann zwangsläufig an die Stelle, wo man sich fragt: Wie verhindere ich eigentlich, das auf meine Ressourcen nicht von einem anderen parallelen Worker-Prozess zugegriffen werden.

WORKERROLE RESPONSIBILITIES
  1. Message lesen
  2. Message unsichtbar machen, während der Verarbeitung (automatisches Verhalten !!!).
  3. Task beenden
  4. Message löschen

Also brauchen wir uns bei den Queues darum gar nicht nicht kümmern :-). Es gibt übrigens noch eine zweite Methode PeekMessage, welche die Message für andere Prozesse nicht unsichtbar macht.

Montag, 1. Februar 2010

Windows Azure Storage Explorer

Um den Inhalt des Storage anzeigen zu lassen, zum Beispiel zu Testzwecken, kann man den Windows Azure Storage Explorer von Codeplex verwenden.

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

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