Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is an MVP ASP.NET and is currently employed as .NET Software Engineer at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP.
More about me More about me
Send mail E-mail me


Microsoft Most Valuable Professional - MVP - ASP.NET

Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn RealDolmen - Rock-solid passion for ICT
I'm a speaker at TechDays Belgium and TechDays Finland

Search

Latest Twitter

    Follow me on Twitter...

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    Introducing RealDolmenBlogs.com

    RealDolmenBlogs.com Here’s something I would like to share with you. A few months ago, our company (RealDolmen) started a new website, RealDolmenBlogs.com. This site syndicates content from employee blogs, people with lots of experience in their range of topics. These guys have lots of knowledge to share, but sometimes their blog does not have a lot of attention from, well, you. Since we would really love to share employee knowledge, RealDolmenBlogs.com was born.

    The following topics are covered:

    • .NET
    • Application Lifecycle Management
    • Architecture
    • ASP.NET
    • Biztalk
    • PHP
    • Sharepoint
    • Silverlight
    • Visual Studio

    Make sure to subscribe to the syndicated RSS feed and have quality content delivered to your RSS reader.

    The technical side

    Since I do not like to do blog posts on topic that do not have a technical touch, considered that the first few lines of text of this post are pure marketing in a sense, here’s the technical bit.

    RealDolmenBlogs.com is built on Windows Azure and SQL Azure. As a company we believe there is value in cloud computing, in this case we chose for cloud computing due to the fact that the setup costs for the website were very small (pay-per-use) and that we can easily scale-up the website if needed.

    The software behind the site is a customized version of BlogEngine.NET. It has been extended with a syndication feature, pulling content from employee blogs with a little help of the Argotic syndication framework. Running BlogEngine.NET on Windows Azure is not that hard, especially when you are using SQL Azure as well: the only thing to modify is the connection string to your database and you are done. Well… that is if you don’t care about images and attachments. We had to do some modifications to how BlogEngine.NET handles file uploads and made sure everything is now stored safe and sound in Windows Azure blob storage.

    That being said: enjoy the content that my colleagues are sharing, posts are definitely worth a read!


    Creating an external facing Azure Worker Role endpoint

    Internet facing Azure Worker Role When Windows Azure was first released, only Web Roles were able to have an externally facing endpoint. Since PDC 2009, Worker Roles can now also have an external facing endpoint, allowing for a custom application server to be hosted in a Worker Role. Another option would be to run your own WCF service and have it hosted in a Worker Role. Features like load balancing, multiple instances of the Worker are all available. Let’s see how you can create a simple TCP service that can display the current date and time.

    Here’s what I want to see when I connect to my Azure Worker Role using telnet (“telnet efwr.cloudapp.net 1234”):

    Telnet Azure Worker Role

    Let’s go ahead and build this thing. Example code can be downloaded here: EchoCloud.zip (9.92 kb)

    kick it on DotNetKicks.com

    Configuring the external endpoint

    Fire up your Visual Studio and create a new Cloud Service, named EchoCloud, with one Worker Role (named EchoWorker). After you complete this, you should have a Windows Azure solution containing one Worker Role. Right-click the worker role and select Properties. Browse to the Endpoints tab and add a new endpoint, like so:

    Configuring an external endpoint on a Windows Azure Worker Role

    This new endpoint (named EchoEndpoint) listens on an external TCP port with port number 1234. Note that you can also make this an internal endpoint, which is an endpoint that can only be reached within your Windows Azure solution and not from an external PC. This can be useful if you wan to host a custom application server in your project and make it available for other Web and Worker Roles in your solution.

    Building the worker role

    As you know, a Worker Role (in the WorkerRole.cs file in your newly created solution) consists of 3 methods that can be implemented: OnStart, Run and OnStop. There’s also an event handler RoleEnvironmentChanging available. The method names sort of speak for themselves, but allow me to explain quickly:

    • OnStart() is executed when the Worker Role is starting. Initializations and some checks can be done here.
    • Run() is the method which contains the actual Worker Role logic. The cool stuff goes in here :-)
    • OnStop() can be used to do things that should be done when the Worker Role is stopped.
    • RoleEnvironmentChanging() is the event handler that gets called when the environment changes: configuration changed, extra instances fired, … are possible triggers for this.

    Our stuff will go in the Run() method. We’ll be creating a new TcpListener which will sit and accept connections. Whenever a connection is available, it will be dispatched on a second thread that will be communicating with the client. Let’s see how we can start the TcpListener:

    public class WorkerRole : RoleEntryPoint
    {
        private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

        public override void Run()
        {
            TcpListener listener = null;
            try
            {
                listener = new TcpListener(
                    RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["EchoEndpoint"].IPEndpoint);
                listener.ExclusiveAddressUse = false;
                listener.Start();
            }
            catch (SocketException)
            {
                Trace.Write("Echo server could not start.", "Error");
                return;
            }

            while (true)
            {
                IAsyncResult result = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
                connectionWaitHandle.WaitOne();
            }
        }
    }

    First thing to notice is that the TcpListener is initialized using the IPEndpoint from the current Worker Role instance:

    listener = new TcpListener(
                    RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["EchoEndpoint"].IPEndpoint);

    We could have started the TcpListener using a static configuration telling it to listen on TCP port 1234, but that would be difficult for the Windows Azure platform. Instead, we start the TcpListener using the current IPEndpoint configuration that we set earlier in this blog post. This allows the application to run on the Windows Azure production environment, as well as on the development environment available from the Windows Azure SDK. Here’s how it would work if we had multiple Worker Roles hosting this application:

    Multiple worker roles running a custom TCP server 

    Second thing we are doing is starting the infinite loop that accepts connections and dispatches the connection to the HandleAsyncConnection method that will sit on another thread. This allows for having multiple connections into one Worker Role. Let’s have a look at the HandleAsyncConnection method:

    private void HandleAsyncConnection(IAsyncResult result)
    {
        // Accept connection
        TcpListener listener = (TcpListener)result.AsyncState;
        TcpClient client = listener.EndAcceptTcpClient(result);
        connectionWaitHandle.Set();

        // Accepted connection
        Guid clientId = Guid.NewGuid();
        Trace.WriteLine("Accepted connection with ID " + clientId.ToString(), "Information");

        // Setup reader/writer
        NetworkStream netStream = client.GetStream();
        StreamReader reader = new StreamReader(netStream);
        StreamWriter writer = new StreamWriter(netStream);
        writer.AutoFlush = true;

        // Show application
        string input = string.Empty;
        while (input != "9")
        {
            // Show menu
            writer.WriteLine("…");

            input = reader.ReadLine();
            writer.WriteLine();

            // Do something
            if (input == "1")
            {
                writer.WriteLine("Current date: " + DateTime.Now.ToShortDateString());
            }
            else if (input == "2")
            {
                writer.WriteLine("Current time: " + DateTime.Now.ToShortTimeString());
            }

            writer.WriteLine();
        }

        // Done!
        client.Close();
    }

    Code speaks for itself, no? One thing that you may find awkward is the connectionWaitHandle.Set();. In the previous code sample, we did connectionWaitHandle.WaitOne();. This means that we are not accepting any new connection until the current one is up and running. connectionWaitHandle.Set(); signals the original thread to start accepting new connections again.

    Running the worker role

    When running the application using the development fabric, you can fire up multiple instances. I fired up 4 Worker Roles that provide the simple TCP service that we just created. This means that my application will be load balanced, and every incoming connection will be distributed over these 4 Worker Role instances. Nifty!

    Here’s a screenshot of my development fabric with two Worker Roles that I crashed intentionally. The service is still available, thanks to the fabric controller dispatching connections only to available Worker Role instances.

    Development fabric with crashed worker roles

    Example code

    Example code can be downloaded here: EchoCloud.zip (9.92 kb)

    Just a quick note: the approach described here can also be used to run a custom WCF host that has other bindings than for example basicHttpBinding.

    kick it on DotNetKicks.com 


    Categories: Azure | C# | General | ICT | Internet | Scalability | Webfarm

    A view from the cloud (or: locate your ASP.NET MVC views on Windows Azure Blob Storage)

    Hosting and deploying ASP.NET MVC applications on Windows Azure works like a charm. However, if you have been reading my blog for a while, you might have seen that I don’t like the fact that my ASP.NET MVC views are stored in the deployed package as well… Why? If I want to change some text or I made a typo, I would have to re-deploy my entire application for this. Takes a while, application is down during deployment, … And all of that for a typo…

    Luckily, Windows Azure also provides blob storage, on which you can host any blob of data (or any file, if you don’t like saying “blob”). These blobs can easily be managed with a tool like Azure Blob Storage Explorer. Now let’s see if we can abuse blob storage for storing the views of an ASP.NET MVC web application, making it easier to modify the text and stuff. We’ll do this by creating a new VirtualPathProvider.

    Note that this approach can also be used to create a CMS based on ASP.NET MVC and Windows Azure.

    kick it on DotNetKicks.com

    Putting our views in the cloud

    Of course, we need a new ASP.NET MVC web application. You can prepare this for Azure, but that’s not really needed for testing purposes. Download and run Azure Blob Storage Explorer, and put all views in a blob storage container. Make sure to incldue the full virtual path in the blob’s name, like so:

    Azure Blob Storage Explorer

    Note I did not upload every view to blob storage. In the approach we’ll take, you do not need to put every view in there: we’ll support mixed-mode where some views are deployed and some others are in blob storage.

    Creating a VirtualPathProvider

    You may or may not know the concept of ASP.NET VirtualPathProviders. Therefore, allow me to quickly explain quickly: ASP.NET 2.0 introduced the concept of VirtualPathProviders, where you can create a virtual filesystem that can be sued by your application. A VirtualPathProvider has to be registered before ASP.NET will make use of it. After registering, ASP.NET will automatically iterate all VirtualPathProviders to check whether it can provide the contents of a specific virtual file or not. In ASP.NET MVC for example, the VirtualPathProviderViewEngine (default) will use this concept to look for its views. Ideal, since we do not have to plug the ASP.NET MVC view engine when we create our BlobStorageVirtualPathProvider!

    A VirtualPathProvider contains some methods that are used to determine if it can serve a specific virtual file. We’ll only be implementing FileExists() and GetFile(), but there are also methods like DirectoryExists() and GetDirectory(). I suppose you’ll know what all this methods are doing by looking at the name…

    In order for our BlobStorageVirtualPathProvider class to access Windows Azure Blob Storage, we need to reference the StorageClient project you can find in the Windows Azure SDK. Next, our class will have to inherit from VirtualPathProvider and need some fields holding useful information:

    public class BlobStorageVirtualPathProvider : VirtualPathProvider
    {
        protected readonly StorageAccountInfo accountInfo;
        protected readonly BlobContainer container;
        protected BlobStorage blobStorage;

        // ...

        public BlobStorageVirtualPathProvider(StorageAccountInfo storageAccountInfo, string containerName)
        {
            accountInfo = storageAccountInfo;
            BlobStorage blobStorage = BlobStorage.Create(accountInfo);
            container = blobStorage.GetBlobContainer(containerName);
        }

        // ...

    }

    Allright! We can now hold everyhting that is needed for accessing Windows Azure Blob Storage: the account info (including credentials) and a BlobContainer holding our views. Our constructor accepts these things and makes sure verything is prepared for accessing blob storage.

    Next, we’ll have to make sure we can serve a file, by adding FileExists() and GetFile() method overrides:

    public override bool FileExists(string virtualPath)
    {
        // Check if the file exists on blob storage
        string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
        if (container.DoesBlobExist(cleanVirtualPath))
        {
            return true;
        }
        else
        {
            return Previous.FileExists(virtualPath);
        }
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        // Check if the file exists on blob storage
        string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
        if (container.DoesBlobExist(cleanVirtualPath))
        {
            return new BlobStorageVirtualFile(virtualPath, this);
        }
        else
        {
            return Previous.GetFile(virtualPath);
        }
    }

    These methods simply check the BlobContainer for the existance of a virtualFile path passed in.  GetFile() returns a new BlobStorageVirtualPath instance. This class provides all functionality for really returning the file’s contents, in its Open() method:

    public override System.IO.Stream Open()
    {
        string cleanVirtualPath = this.VirtualPath.Replace("~", "").Substring(1);
        BlobContents contents = new BlobContents(new MemoryStream());
        parent.BlobContainer.GetBlob(cleanVirtualPath, contents, true);
        contents.AsStream.Seek(0, SeekOrigin.Begin);
        return contents.AsStream;
    }

    We’ve just made it possible to download a blob from Windows Azure Blob Storage into a MemoryStream and pass this on to ASP.NET for further action.

    Here’s the full BlobStorageVirtualPathProvider class:

    public class BlobStorageVirtualPathProvider : VirtualPathProvider
    {
        protected readonly StorageAccountInfo accountInfo;
        protected readonly BlobContainer container;

        public BlobContainer BlobContainer
        {
            get { return container; }
        }

        public BlobStorageVirtualPathProvider(StorageAccountInfo storageAccountInfo, string containerName)
        {
            accountInfo = storageAccountInfo;
            BlobStorage blobStorage = BlobStorage.Create(accountInfo);
            container = blobStorage.GetBlobContainer(containerName);
        }

        public override bool FileExists(string virtualPath)
        {
            // Check if the file exists on blob storage
            string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
            if (container.DoesBlobExist(cleanVirtualPath))
            {
                return true;
            }
            else
            {
                return Previous.FileExists(virtualPath);
            }
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            // Check if the file exists on blob storage
            string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
            if (container.DoesBlobExist(cleanVirtualPath))
            {
                return new BlobStorageVirtualFile(virtualPath, this);
            }
            else
            {
                return Previous.GetFile(virtualPath);
            }
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            return null;
        }
    }

    And here’s BlobStorageVirtualFile:

    public class BlobStorageVirtualFile : VirtualFile
    {
        protected readonly BlobStorageVirtualPathProvider parent;

        public BlobStorageVirtualFile(string virtualPath, BlobStorageVirtualPathProvider parentProvider) : base(virtualPath)
        {
            parent = parentProvider;
        }

        public override System.IO.Stream Open()
        {
            string cleanVirtualPath = this.VirtualPath.Replace("~", "").Substring(1);
            BlobContents contents = new BlobContents(new MemoryStream());
            parent.BlobContainer.GetBlob(cleanVirtualPath, contents, true);
            contents.AsStream.Seek(0, SeekOrigin.Begin);
            return contents.AsStream;
        }
    }

    Registering BlobStorageVirtualPathProvider with ASP.NET

    We’re not completely ready yet. We still have to tell ASP.NET that it can possibly get virtual files using the BlobStorageVirtualPathProvider. We’ll do this in the Application_Start event in Global.asax.cs:

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

        // Register the virtual path provider with ASP.NET
        System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new BlobStorageVirtualPathProvider(
            new StorageAccountInfo(
                new Uri("http://blob.core.windows.net"),
                false,
                "your_storage_account_name_here",
                "your_storage_account_key_here"),
                "your_container_name_here"));
    }

    Add your own Azure storage account name, key and the container name that you’ve put your views in and you are set! Development storage will work as well as long as you enter the required info.

    Running the example code

    Download the sample code here: MvcViewInTheCloud.zip (58.72 kb)

    Some instructions for running the sample code:

    • Upload all views from the ____Views folder to a blob container (as described earlier in this post)
    • Change your Azure credetials in Application_Start

    kick it on DotNetKicks.com


    Categories: ASP.NET | Azure | C# | Fun | General | ICT | Internet | MVC | Webfarm

    Back to the future! Exploring ASP.NET MVC Futures

    Back to the future!For those of you who did not know yet: next to the ASP.NET MVC 1.0 version and its source code, there’s also an interesting assembly available if you can not wait for next versions of the ASP.NET MVC framework: the MVC Futures assembly. In this blog post, I’ll provide you with a quick overview of what is available in this assembly and how you can already benefit from… “the future”.

    kick it on DotNetKicks.com 

    First things first: where to get this thing? You can download the assembly from the CodePlex releases page. Afterwards, reference this assembly in your ASP.NET MVC web application. Also add some things to the Web.config file of your application:

    <?xml version="1.0"?>
    <configuration>
        <!-- ... -->
        <system.web>
            <!-- ... -->

            <pages>
                <controls>
                    <!-- ... -->
                    <add tagPrefix="mvc" namespace="Microsoft.Web.Mvc.Controls" assembly="Microsoft.Web.Mvc"/>
                </controls>
                <namespaces>
                    <!-- ... -->
                    <add namespace="Microsoft.Web.Mvc"/>
                    <add namespace="Microsoft.Web.Mvc.Controls"/>
                </namespaces>
            </pages>

            <!-- ... -->
        </system.web>
        <!-- ... -->
    </configuration>

    You are now ready to go! Buckle up and start your De Lorean DMC-12…

    Donut caching (a.k.a. substitution)

    If you have never heard of the term “donut caching” or “substitution”, now is a good time to read a previous blog post of mine. Afterwards, return here. If you don’t want to click that link: fine! Here’s in short: “With donut caching, most of the page is cached, except for some regions which are able to be substituted with other content.”

    You’ll be needing an OutputCache-enabled action method in a controller:

    [OutputCache(Duration = 10, VaryByParam = "*")]
    public ActionResult DonutCaching()
    {
        ViewData["lastCached"] = DateTime.Now.ToString();

        return View();
    }

    Next: a view. Add the following lines of code to a view:

    <p>
        This page was last cached on: <%=Html.Encode(ViewData["lastCached"])%><br />
        Here's some "donut content" that is uncached: <%=Html.Substitute( c => DateTime.Now.ToString() )%>
    </p>

    There you go: when running this application, you will see one DateTime printed in a cached way (refreshed once a minute), and one DateTime printed on every page load thanks to the substitution HtmlHelper extension. This extension method accepts a HttpContext instance which you can also use to enhance the output.

    Now before you run away and use his in your projects: PLEASE, do not do write lots of code in your View. Instead, put the real code somewhere else so your view does not get cluttered and your code is re-usable. In an ideal world, this donut caching would go hand in hand with our next topic…

    Render action methods inside a view

    You heard me! We will be rendering an action method in a view. Yes, that breaks the model-view-controller design pattern a bit, but it gives you a lot of added value while developing applications! Look at this like “partial controllers”, where you only had partial views in the past. If you have been following all ASP.NET MVC previews before, this feature already existed once but has been moved to the futures assembly.

    Add some action methods to a Controller:

    public ActionResult SomeAction()
    {
        return View();
    }

    public ActionResult CurrentTime()
    {
        ViewData["currentTime"] = DateTime.Now.ToString();

        return View();
    }

    This indeed is not much logic, but here’s the point: the SomeAction action method will render a view. That view will then render the CurrentTime action method, which will also render a (partial) view. Both views are combined and voila: a HTTP response which was generated by 2 action methods that were combined.

    Here’s how you can render an action method from within a view:

    <% Html.RenderAction("CurrentTime"); %>

    There’s also lambdas to perform more complex actions!

    <% Html.RenderAction<HomeController>(c => c.CurrentTime()); %>

    What most people miss: controls

    Lots of people are missing something when first working with the ASP.NET MVC framework: “Where are all the controls? Why don’t all ASP.NET Webforms controls work?” My answer would normally be: “You don’t need them.”, but I now also have an alternative: “Use the futures assembly!”

    Here’s a sample controller action method:

    public ActionResult Controls()
    {
        ViewData["someData"] = new[] {
            new {
                Id = 1,
                Name = "Maarten"
            },
            new {
                Id = 2,
                Name = "Bill"
            }
        };

        return View();
    }

    The view:

    <p>
        TextBox: <mvc:TextBox Name="someTextBox" runat="server" /><br />
        Password: <mvc:Password Name="somePassword" runat="server" />
    </p>
    <p>
        Repeater:
        <ul>
        <mvc:Repeater Name="someData" runat="server">
            <EmptyDataTemplate>
                <li>No data is available.</li>
            </EmptyDataTemplate>
            <ItemTemplate>
                <li><%# Eval("Name") %></li>
            </ItemTemplate>
        </mvc:Repeater>
        </ul>
    </p>

    As you can see: these controls all work quite easy. The "Name property accepts the key in the ViewData dictionary and will render the value from there. In the repeater control, you can even work with “good old” Eval: <%# Eval("Name") %>.

    Extra HtmlHelper extension methods

    Not going in too much detail here: there are lots of new HtmlHelper extension methods. The ones I especially like are those that allow you to create a hyperlink to an action method using lambdas:

    <%=Html.ActionLink<HomeController>(c => c.ShowProducts("Books"), "Show books")%>

    Here’s a list of new HtmlHelper extension methods:

    • ActionLink – with lambdas
    • RouteLink – with lambdas
    • Substitute (see earlier in this post)
    • JavaScriptStringEncode
    • HiddenFor, TextFor, DropDownListFor, … – like Hidden, Text, … but with lambdas
    • Button
    • SubmitButton
    • Image
    • Mailto
    • RadioButtonList

    More model binders

    Another thing I will only cover briefly: there are lots of new ModelBinders included! Model binders actually allow you to easily map input from a HTML form to parameters in an action method. That being said, here are the new kids on the block:

    • FileCollectionModelBinder – useful for HTTP posts that contain uploaded files
    • LinqBinaryModelBinder
    • ByteArrayModelBinder

    When you want to use these, do not forget to register them with ModelBinders.Binders in your Global.asax.

    More ActionFilters and ResultFilters

    Action filters and result filters are used to intercept calls to an action method or view rendering, providing a hook right before and after that occurs. This way, you can still modify some variables in the request or response prior to, for example, executing an action method. Here’s what is new:

    • AcceptAjaxAttribute – The action method is only valid for AJAX requests. It allows you to have different action methods for regular requests and AJAX requests.
    • ContentTypeAttribute – Sets the content type of the HTTP response
    • RequireSslAttribute – Requires SSL for the action method to execute. Allows you to have a different action method for non-SSL and SSL requests.
    • SkipBindingAttribute – Skips executing model binders for an action method.

    Asynchronous controllers

    This is a big one, but it is described perfectly in a Word document that can be found on the MVC Futures assembly release page. In short:

    The AsyncController is an experimental class to allow developers to write asynchronous action methods. The usage scenario for this is for action methods that have to make long-running requests, such as going out over the network or to a database, and don’t want to block the web server from performing useful work while the request is ongoing.

    In general, the pattern is that the web server schedules Thread A to handle some incoming request, and Thread A is responsible for everything up to launching the action method, then Thread A goes back to the available pool to service another request. When the asynchronous operation has completed, the web server retrieves a Thread B (which might be the same as Thread A) from the thread pool to process the remainder of the request, including rendering the response. The diagram below illustrates this point.

    Asynchronous controllers

    Sweet! Should speed up your ASP.NET MVC web application when it has to handle much requests.

    Conclusion

    I hope you now know what the future for ASP.NET MVC holds. It’s not sure all of this will ever make it into a release, but you are able to use all this stuff from the futures assembly. If you are too tired to scroll to the top of this post after reading it, here’s the link to the futures assembly again: MVC Futures assembly

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | CodePlex | General | ICT | Internet | MVC | Webfarm

    Accessing Windows Azure Blob Storage from PHP

    Pfew! A week of Microsoft TechDays here in Belgium with lots of talks on new Microsoft stuff, Azure included. You may know I already experimented with Windows Azure and ASP.NET MVC. Earlier this week, I thought of doing the same with Windows Azure and PHP...

    What the ...?

    imageAt Microsoft PDC 2008, the Azure Services Platform was announced in the opening keynote. Azure is the name for Microsoft’s Software + Services platform, an operating system in the cloud providing services for hosting, management, scalable storage with support for simple blobs, tables, and queues, as well as a management infrastructure for provisioning and geo-distribution of cloud-based services, and a development platform for the Azure Services layer.

    You can currently download the Windows Azure SDK from www.azure.com and play with it on your local computer. Make sure to sign-up at the Azure site: you might get lucky and receive a key to test the real thing.

    And what does PHP have to do with this?

    As a reader of my blog, this should not be a question. I'm on the thin line between the Microsoft development environment (.NET) and PHP development environment, and I really like bridging the two together (think PHPExcel, PHPLinq). And cheap, distributed hosting of data (be it file or databases) is always interesting to use, especially in web applications where you may store anything your users upload. I have created a Zend Framework Proposal for this, let's hope this blog post ends as a contribution to the Zend Framework.

    Show me the good stuff!

    Will do! Currently, I have only implemented Azure blob storage in PHP, so that's what the following code snippets will be using. Enough blahblah now, here's how you connect with Azure:

    $storage = new Zend_Azure_Storage_Blob();

    This actually sets up a connection with the local Azure storage service from the Windows Azure SDK. You can, however, also pass in an account name and shared key from the real, cloud hosted Azure, too. Next: I want to create a storage container. A storage container is a logical group in which I can store any data. Let's name the container "azuretest":

    $storage->createContainer('azuretest');

    Easy? Yup! Azure now has created some space on their distributed storage for my files to be dumped in. Speaking of which: let's upload a file!

    $storage->putBlob('azuretest', 'images/WindowsAzure.gif', './WindowsAzure.gif');

    There we go. I've uploaded my local WindowsAzure.gif file to the azuretest container and named the file "images/WindowsAzure.gif'". Don't be confused: it is NOT stored in the images/ folder (there's no such thing on Azure), this is really the full filename. But don't worry, you can mimic a regular filesystem with folders, for example by retrieving all files that are prefixed with "images/":

    $storage->listBlobs('azuretest', '/', 'images/');

    Piece of cake!

    I wanna play!

    Sure, who doesn't? Here's a preview of the classes I've been creating: Zend_Azure_CTP.zip (11.51 kb)

    Now let's hope my Zend Framework Proposal gets accepted so this can be a part of the Zend Framework. In the meantime, I'll continue with this and also implement Azure table storage: cheap, distributed database features in the cloud.

    kick it on DotNetKicks.com


    ASP.NET Session State Partitioning using State Server Load Balancing

    It seems like amount of posts on ASP.NET's Session State keeps growing. Here's the list:

    Yesterday's post on Session State Partitioning used a round-robin method for partitioning session state over different state server machines. The solution I presented actually works, but can still lead to performance bottlenecks.

    Let's say you have a web farm running multiple applications, all using the same pool of state server machines. When having multiple sessions in each application, the situation where one state server handles much more sessions than another state server could occur. For that reason, ASP.NET supports real load balancing of all session state servers.

    Download example

    Want an instant example? Download it here.
    Want to know what's behind all this? Please, continue reading.

    What we want to achieve...

    Here's a scenario: We have different applications running on a web farm. These applications all share the same pool of session state servers. Whenever a session is started, we want to store it on the least-busy state server.

    1. Performance counters

    To fetch information on the current amount of sessions a state server is storing, we'll use the performance counters ASP.NET state server provides. Here's a code snippet:

    if (PerformanceCounterCategory.CounterExists("State Server Sessions Active", "ASP.NET", "STATESERVER1")) {
        PerformanceCounter pc = new PerformanceCounter("ASP.NET", "State Server Sessions Active", "", "STATESERVER1");
        float currentLoad = pc.NextValue();
    }

    2. Creating a custom session id

    Somehow, ASP.NET will have to know on which server a specific session is stored. To do this, let's say we make the first character of the session id the state server id from the following IList:

    IList<StateServer> stateServers = new List<StateServer>();

    // Id 0, example session id would be 0ywbtzez3eqxut45ukyzq3qp
    stateServers.Add(new StateServer("tcpip=10.0.0.1:42424", "sessionserver1"));

    // Id 1, example session id would be 1ywbtzez3eqxut45ukyzq3qp
    stateServers.Add(new StateServer("tcpip=10.0.0.2:42424", "sessionserver2"));

    Next thing we'll have to do is storing these list id's in the session id. For that, we will implement a custom System.Web.SessionState.SessionIDManager class. This class simply creates a regular session id, locates the least-busy state server instance and assign the session to that machine:

    using System;
    using System.Diagnostics;


    public class SessionIdManager : System.Web.SessionState.SessionIDManager
    {
        public override string CreateSessionID(System.Web.HttpContext context)
        {
            // Generate a "regular" session id
            string sessionId = base.CreateSessionID(context);

            // Find the least busy state server
            StateServer leastBusyServer = null;
            float leastBusyValue = 0;
            foreach (StateServer stateServer in StateServers.List)
            {
                // Fetch first state server
                if (leastBusyServer == null) leastBusyServer = stateServer;

                // Fetch server's performance counter
                if (PerformanceCounterCategory.CounterExists("State Server Sessions Active", "ASP.NET", stateServer.ServerName))
                {
                    PerformanceCounter pc = new PerformanceCounter("ASP.NET", "State Server Sessions Active", "", stateServer.ServerName);
                    if (pc.NextValue() < leastBusyValue || leastBusyValue == 0)
                    {
                        leastBusyServer = stateServer;
                        leastBusyValue = pc.NextValue();
                    }
                }
            }

            // Modify session id to contain the server's id
            // We will change the first character in the string to be the server's id in the
            // state server list. Notice that this is only for demonstration purposes! (not secure!)
            sessionId = StateServers.List.IndexOf(leastBusyServer).ToString() + sessionId.Substring(1);

            // Return
            return sessionId;
        }
    }

    The class we created will have to be registered in web.config. Here's how:

    <configuration>
      <system.web>
        <!-- ... -->
        <sessionState mode="StateServer"
                    partitionResolverType="PartitionResolver"
                    sessionIDManagerType="SessionIdManager" />
        <!-- ... -->
      </system.web>
    </configuration>

    You notice our custom SessionIdManager class is now registered to be the sessionIDManager. The PartitionResolver I blogged about is also present in a modified version.

    3. Using the correct state server for a specific session id

    In the previous code listing, we assigned a session to a specific server. Now for ASP.NET to read session state from the correct server, we still have to use the PartitionResolver class:

    using System;


    public class PartitionResolver : System.Web.IPartitionResolver
    {

        #region IPartitionResolver Members

        public void Initialize()
        {
            // No need for this!
        }

        public string ResolvePartition(object key)
        {
            // Accept incoming session identifier
            // which looks similar like "2ywbtzez3eqxut45ukyzq3qp"
            string sessionId = key as string;

            // Since we defined the first character in sessionId to contain the
            // state server's list id, strip it off!
            int stateServerId = int.Parse(sessionId.Substring(0, 1));

            // Return the server's connection string
            return StateServers.List[stateServerId].ConnectionString;
        }

        #endregion

    }

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | ICT | Internet | Software | Webfarm | XML

    ASP.NET Session State Partitioning

    After my previous blog post on ASP.NET Session State, someone asked me if I knew anything about ASP.NET Session State Partitioning. Since this is a little known feature of ASP.NET, here's a little background and a short how-to.

    When scaling out an ASP.NET application's session state to a dedicated session server (SQL server or the ASP.NET state server), you might encounter a new problem: what if this dedicated session server can't cope with a large amount of sessions? One option might be to create a SQL server cluster for storing session state. A cheaper way is to implement a custom partitioning algorithm which redirects session X to state server A and session Y to state server B. In short, partitioning provides a means to divide session information on multiple session state servers, which all handle "their" part of the total amount of sessions.

    Download example 

    Want an instant example? Download it here.
    Want to know what's behind all this? Please, continue reading.

    1. Set up ASP.NET session mode

    Follow all steps in my previous blog post to set up the ASP.NET state service / SQL state server database and the necessary web.config setup. We'll customise this afterwards.

    2.   Create your own session state partitioning class

    The "magic" of this el-cheapo solution to multiple session servers will be your own session state partitioning class. Here's an example:

    using System;

    public class PartitionResolver : System.Web.IPartitionResolver
    {

        #region Private members

        private String[] partitions;

        #endregion

        #region IPartitionResolver Members

        public void Initialize()
        {
            // Create an array containing
            // all partition connection strings
            //
            // Note that this could also be an array
            // of SQL server connection strings!
            partitions = new String[] {      
                "tcpip=10.0.0.1:42424",   
                "tcpip=10.0.0.2:42424",       
                "tcpip=10.0.0.3:42424"
            };
        }

        public string ResolvePartition(object key)
        {
            // Accept incoming session identifier
            // which looks similar like "2ywbtzez3eqxut45ukyzq3qp"
            string sessionId = key as string;

            // Create your own manner to divide session id's
            // across available partitions or simply use this one!
            int partitionID = Math.Abs(sessionId.GetHashCode()) % partitions.Length;
            return partitions[partitionID];
        }

        #endregion
    }

    Basically, you just have to implement the interface System.Web.IPartitionResolver, which is the contract ASP.NET uses to determine the session state server's connection string. The ResolvePartition method is called with the current session id in it, and allows you to return the connection string that should be used for that specific session id.

    3. Update your web.config

    Most probably, you'll have a web.config which looks like this:

    <configuration>
      <system.web>
        <!-- ... -->
        <sessionState
            mode="StateServer"
            stateConnectionString="tcpip=your_server_ip:42424" />
        <!-- ... -->
      </system.web>
    </configuration>

    In order for ASP.NET to use our custom class, modify web.config into:

    <configuration>
      <system.web>
        <!-- ... -->
        <sessionState
            mode="StateServer"
            partitionResolverType="PartitionResolver" />
        <!-- ... -->
      </system.web>
    </configuration>

    You may have noticed that the stateConnectionString attribute was replaced by a partitionResolverType attribute. From now on, ASP.NET will use the class specified in the partitionResolverType attribute for distributing sessions across state servers.

    UPDATE 2008-01-24: Also check out my blog post on Session State Partitioning using load balancing!

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | ICT | Internet | Software | Webfarm | XML

    ASP.NET load balancing and ASP.NET state server (aspnet_state)

    At one of our clients, we used to have only one server for ASP.NET applications (including web services). Since this machine is actually business-critical and load is constantly growing, the need for a second machine is higher than ever.

    This morning I was asked to set up a simple demo of a load-balanced ASP.NET environment. I already did this in PHP a couple of times, but in ASP.NET, this question was totally new to me. Things should not be very different, I thought. And this thought proved right!

    A bit later, we had a load balancer in front of 2 web server machines. We got everything configured, fired up our webbrowser and saw a different page on each refresh (stating the server's hostname). Load balancing mission succeeded!

    Next thing: session state. In our PHP environment, we chose to centralize all session data in a database. ASP.NET provides the same functionality, but we chose to use the ASP.NET state server for this demo. This proved to be a difficult yourney... But we managed to get things running! Here's how.

    1. Set up the ASP.NET state service

    Pick a server which will serve as the session state server. Fire up the services control panel (services.msc). Select the "ASP.NET State Service" item and make it start automatically. Great! Our state service is running.

    Caveat 1: state server will not listen on any public IP address. So fire up your registry editor, change the following key and restart the ASP.NET state service:

    HKLM\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnections

    Eventually change the port on which the state server will be listening:

    HKLM\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\Port (default: 42424)

    Caveat 2: after changing the AllowRemoteConnections directive, make sure the server's port 42424 is NOT open for the Internet, just for your web servers!

    2. Make both ASP.NET servers use the state server

    Every Web.config file contains a nice configuration directive named "sessionState". So open up your Web.config, and make it look like this:

    <?xml version="1.0"?>
    <configuration>
        <system.web>
            <!-- ... -->
            <sessionState
                mode="StateServer"
                stateConnectionString="tcpip=your_server_ip:42424"
                cookieless="false"
                timeout="20" />
            <!-- ... -->
        </system.web>
    </configuration>

    3. So you think you are finished...

    ...but that's not the case! Our load balancer did a great job, but both servers where returning different session data. We decided to take a look at the session ID in our cookie: it was the same for both machines. Strange!

    Some research proved that it was ASP.NET's <machineKey> configuration which was the issue. Both web servers should have the same <machineKey> configuration. Let's edit Web.config one more time:

    <?xml version="1.0"?>
    <configuration>
        <system.web>
            <machineKey
              validationKey="1234567890123456789012345678901234567890AAAAAAAAAA"
              decryptionKey="123456789012345678901234567890123456789012345678"
              validation="SHA1"
              decryption="Auto"
            />
            <!-- ... -->
            <sessionState
                mode="StateServer"
                stateConnectionString="tcpip=your_server_ip:42424"
                cookieless="false"
                timeout="20" />
            <!-- ... -->
        </system.web>
    </configuration>

    (more on the machineKey element on MSDN)

    Also check MS KB 325056, this was an issue we did not meet, but it might save your day.

    4. Great success!

    Our solution now works! Only problem left is that we have a new single point of failure (SPOF): the ASP.NET state service. But we might just set up 2 of those and fail over both session service machines.

    UPDATE 2008-01-23: Also check out my blog post on Session State Partitioning!

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | ICT | Internet | Webfarm | XML