logo1

logo

Using Windows Azure Web Sites – Hosting a blog with BlogEngine.NET

2 Comments
Posted in Windows Azure

** Update: BlogEngine.NET is now included as part of Windows Azure’s Website App Gallery **

Currently the Gallery only includes version 2.5.0.6 of BlogEngine.NET, which is a couple of versions behind now. If you want to install the latest version then the steps below should still be applicable.

Windows Azure Web Sites is one of the new features in Windows Azure announced by Scott Guthrie on his blog post Meet the New Windows Azure. Azure Web Sites are akin to the shared hosting model, where many sites are hosted under one installation of IIS inside of a single VM. Azure puts a bit of a spin on this concept by allowing scale out of the Web Site to multiple VMs and the ability to reserve entire VMs just for its usage.

WindowsAzure.com describes Azure Web Sites as follows:

Build highly scalable web sites on Windows Azure

Quickly and easily deploy sites to a highly scalable cloud environment that allows you to start small and scale as traffic grows.

Use the languages and open source apps of your choice then deploy with FTP, Git and TFS. Easily integrate Windows Azure services like SQL Database, Caching, CDN and Storage.

This functionality is currently free for up to 10 websites during the technical preview. However, I can’t imagine it being all that expensive once it comes out of preview.

The biggest feature that really stands out IMO is the ability to just use Web Deploy in Visual Studio for deployments. Aside from the new publish profile it’s not necessary to change anything else about the project/solution. All of this drastically reduces the barrier to entry for anyone wanting to get started with Windows Azure.

With that said, we’re going to go through the process of deploying BlogEngine.NET to Windows Azure using the new Web Sites features and see that things are demonstrably easier than what was required in the past. Additionally, this should give us a quick run through of the new management portal for Azure (more on this below).

Here’s an overview of what we’ll need:

  • Windows Azure Account (you can sign up for a 90 day free trial)
  • Visual Studio 2010 SP1 or higher (SP1 is required for the Azure SDK)
  • BlogEngine.NET WAP Project source (detailed below)
  • Windows Azure SDK 1.7 or higher, if using VS 2010 SP1 (links provided below)

Azure Setup

If you don’t already have an Azure account, you’ll need to sign up for one before you can continue. Again they have a 90 day free trial, so there’s no hassle. Once you have your account set up, we’ll need to enable the Web Sites preview, which also enables the preview of the new management portal. This happens to be relatively painless.

AccountA

PreviewFeaturesA

PreviewFeatures2B

PreviewPortalIntroA

After electing to use the preview portal you’ll get a quick guided tour detailing its new features. With the new portal and the Web Sites option enabled, we can finally create an Azure Web Site.

Portal01A

Portal02A

There are several other blog engines in the gallery, unfortunately BlogEngine.NET isn’t one of them. Select Quick Create since we’re going to do a basic/default installation of BlogEngine.NET. If we were backing our BlogEngine.NET install with a Sql Server we’d select Create with Database instead of Quick Create. Note the URL field can be entered as whatever you want it to be.

Portal03

Once finished we should now have a running web site, just with nothing deployed to it yet Winking smile

Portal04

Next up we need to go to the management screen and pull down the publish profile. This tells Visual Studio how to publish to our Azure Web Site.

Portal05

Azure SDK Install

If you’re using Visual Studio 2012 RC, you can skip this step. For those running VS 2010 SP1, you’re going to need to install the Azure SDK 1.7 or greater in order for VS 2010 to use the publish profile. Ultimately this just updates the publish options in VS 2010 to be like that of VS 2012’s.

You can download the SDK from here: https://www.windowsazure.com/en-us/develop/downloads/

I installed the .NET Full version, but Windows SDK only should work fine.

BlogEngine.NET Web Application Project

The default download/install of BlogEngine.NET is an “old school” web site project, which isn’t exactly compatible with Windows Azure (there’s a way, it’s just not easy). Web application projects are compatible with Windows Azure out of the box. Earlier this year the only option for BlogEngine.NET was to manually do the conversion, which wasn’t exactly straight forward. See my blog post: Converting BlogEngine.NET 2.5 to a Web Application for more info.

Luckily enough, when the BlogEngine.NET developers released 2.6 they also released a branch that is already converted to a web application. You can find more information on this post on rtur’s website (listed as coordinator for BlogEngine.NET) :

The WAP version is under a different codeplex repository located here: http://blogengineweb.codeplex.com/. As opposed to downloading the precompiled version we’re going to pull down the source since using the publish profile in Visual Studio requires a functioning build.

Download the source changeset for BlogEngine.NET 2.6 as a WAP from codeplex.

Make sure to extract this to a directory hierarchy that does not have spaces in it. The XCopy post build steps in BlogEngine.NET weren’t set up to work with a directory structure containing spaces.

Open it up in Visual Studio and make sure everything builds. Before we’re able to publish we’ll need to do a little project house cleaning. BlogEngine.NET ‘s WAP project has a handful of files that are missing yet still part of the project. We just have to remove the references to these files, otherwise the publish process will halt on them.

Delete the files from the following locations (should be easy spot with the exclamation marks) as seen below.

BlogEngineCleanup01

Now we’re ready to publish. Right click on BlogEngine.Web and select Publish.

BlogEnginePublish01

This should bring up the publish dialog, which should look like the image below. If it looks different and it doesn’t have a spot to import the publish profile, then the Azure SDK may not have been installed or may need to be reinstalled.

BlogEnginePublish02B

Import the publish profile and all the info necessary to publish to the azure website should be prepopulated.

BlogEnginePublish03

Hit the publish button and check the build output to see if the publish was successful.

BlogEnginePublish04

Navigate to the site url detailed in the build output and you should be good to go.

BlogEnginePublish05

Scaling Considerations

One thing to mention is that although we’ve deployed BlogEngine.NET to Windows Azure Web Sites, that in itself doesn’t make it inherently scalable. If we plan to scale out or have finally gotten to the point where it’s necessary to do so) we’d have to attack a few extra design considerations, which could be an entirely new blog post. I’ll just scratch the surface here of what needs to be considered.

By default BlogEngine.NET stores blog posts and their associated images in the file system. When scaling out both posts and images will need to be centralized and available across multiple hosted instances of BlogEngine.NET. In the simplest sense, this could be accomplished by switching over to Sql Azure for post and image storage, since BlogEngine.NET supports this natively.

Alternatively, you could use Azure’s Blob storage (see Azure Data management for an overview, Blob storage is described at bottom of page) to store the images individually, however this will require an additional BlogFileSystemProvider to be created so BlogEngine.NET can make use of it. Blob storage is made for this type of storage and is significantly cheaper per GB than Sql Azure.

Personally, I like to compress my post images after the fact using OptiPNG, which runs at the command line and processes a directory of png images. In which case, neither Sql Azure nor using Blob storage directly would be all that helpful for me. I might lean towards Azure Drive (also described in Azure Data management), which stores a VHD in Blob storage, but acts like a shared drive. It’s a little clunky to work with but it’s another option to consider depending on your needs.

As a side note, BlogEngine.NET doesn’t make use of session, so there are no changes necessary from that standpoint.

Conclusion

All in all, Azure Web Sites seem very easy to work with. Microsoft did a good job in making this a hassle free experience. The installation of BlogEngine.NET wasn’t that bad, however, I would of preferred for it to already be in the gallery, which would of meant we wouldn’t have had to deal with publishing from Visual Studio at all. It’ll be interesting to see how Azure Web Sites will ultimately be priced. Priced right, this could set a new bar for shared hosting standards and be a good entry point for those looking to get started with Windows Azure.

  • 2 Comments

Converting BlogEngine.NET 2.5 to a Web Application

6 Comments
Posted in .NET | ASP.NET | C# | Open Source

BlogEngine.NET 2.5 is currently distributed as a Web Site Project (WSP).  The project makes use of some of the WSP’s features to be more flexible for non technical end users.  For more technical users, who can recompile as necessary and don’t mind getting their hands dirty, a Web Application Project (WAP) conversion can provide some utility that the WSP can not.  You can find a guide of the pros and cons of each approach on MSDN: Web Application Projects versus Web Site Projects.

Aside from a general preference of WAPs over WSPs my main reasons for converting are as follows:

  • Deploying to Windows Azure is simpler with WAPs (I’ve been toying with the idea of putting this puppy up there, with the recent price drop)
  • A single compiled assembly is easier to manage during deployment
  • Web.config transforms can only be done on WAPs

At the time of this post there are a handful of forums posts, wiki articles and blog posts which somewhat describe the process of conversion (I’ve included links to all of these at the end of the post).  None of them capture all of the steps involved in conversion and the steps that were included weren’t always well detailed as one would like. 

After reviewing all of the available info and performing the conversion several times myself.  Here are the steps I’ve come up with and that I followed for the conversion of this site:

  1. Pull down the BlogEngine.NET source code and open the solution in Visual Studio.
  2. Remove the BlogEngine.Net Website project from the solution.
  3. Navigate to the solution directory in Windows Explorer and rename the Website project’s folder from BlogEngine.NET to BlogEngine.NETOld or something similar.  Leave Windows Explorer open, we’ll be back there again.

    02_RenameFolder
  4. Add an ASP.NET Web Application project called “BlogEngine.NET” to the solution.

    03_NewWebApplicationProject
  5. Remove most of the default files from the new Web Application project, such that it looks like the image below.

    04_DeleteDefaultFiles
  6. In Windows Explorer, copy all files except Bin & Obj from the renamed BlogEngine.NETOld folder  to the new created BlogEngine.NET folder.
  7. In Visual Studio, click the “Show All Files” icon in the Solution Explorer.
  8. Right click the newly displayed files (with the exception of the aspnet_client and obj folders) and select “Include in Project” until your Solution looks like the image below.  Note: don’t forget to include the files and folders below the Account, Add_Data, Scripts & Styles folders.

    05_IncludedFilesAfterCopy
  9. Add a new folder called Custom_Code and move everything except the Helpers folder from App_Code folder to Custom_Code folder. 

    The app code directory is one of the major differences between WAP and WSP. Most of the files in app code need to be moved out of app code, to a non-magic-name directory. The Helpers, however, are Razor helper classes and will only work if you paste the directly into the razor views, or leave them in the App_Code directory.

    One consequence of moving the Extensions folder out of App_Code and into Custom_Code is that it will no longer be possible to view or edit the source code of an extension from the browser. This is good from a security perspective.

    If, however, you want that functionality, create an App_Code/Extension folder and place those extensions in there. Do not, however, put all the extensions back because some of the extensions that ship with the product have dependencies and need to be included in the main dll (like the captcha extension).


    Quoted from:
    Converting BlogEngine.net 2.5 to Web Application Project
  10. Create a Helpers folder under Custom_Code and move RazorHelpers.cs there from the Helpers folder in App_Code.  After steps 8 & 9 your Solution should be structured like the below image.

    06_FilesAfterMoves
  11. After moving the files from App_Code to Custom_Code the build action may be incorrect on many of the class files.  For each of the files in Custom_Code change the build action to Compile in the Properties window.

    07_CustomCodeBuildActions
  12. In the BlogEngine.NET project make sure you have the following references (use the 1.0.0.0 versions if there are multiple versions available):

    08_NewReferences

  13. Add a project reference to BlogEngine.Core.
  14. Since we’ve technically moved the App_Code into a new assembly, we need to let the app know where it’s at.  Update the Web.Config pages section as follows:
    <pages enableSessionState="false" enableViewStateMac="true" enableEventValidation="true" 
      controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
        <controls>
        <!--WAP FIX-->
        <!--<add namespace="App_Code.Controls" tagPrefix="blog"/>-->
        <add namespace="App_Code.Controls" assembly="BlogEngine.NET" tagPrefix="blog"/>
      </controls>
    </pages>
  15. I had the async ctp installed on my pc, which makes async a reserved word and causes a handful of exceptions, so we’ll need to fix that.  Rename parameter async to asyncResult in BlogEngine.NET/Custom_Code/Controls/Blogroll.ProcessResponse.

    //WAP FIX
    //private static void ProcessResponse(IAsyncResult async)
    private static void ProcessResponse(IAsyncResult asyncResult)
    {
        //WAP FIX
        //GetRequestData data = (GetRequestData)async.AsyncState;
        GetRequestData data = (GetRequestData)asyncResult.AsyncState;
        Blog.InstanceIdOverride = data.BlogInstanceId;
        var blogReq = data.BlogRequest;
    
        try
        {
            //WAP FIX
            //using (var response = (HttpWebResponse)blogReq.Request.EndGetResponse(async))
            using (var response = (HttpWebResponse)blogReq.Request.EndGetResponse(asyncResult))
            {
                var doc = new XmlDocument();
                var responseStream = response.GetResponseStream();
  16. There’s a naming collision in themes between StandardSite and TitaniumX (WAP class names need to be unique). Rename BlogEngine.NET/themes/TitaniumX/site.master.cs from StandardSite to TitaniumSite class, change inherits in BlogEngine.NET/themes/TitaniumX/site.master as well.

    <%@ Master Language="C#" AutoEventWireup="true" Inherits="TitaniumSite " Codebehind="site.master.cs" %>
    <%@ Import Namespace="BlogEngine.Core" %>
    <% //WAP FIX 
       //<%@ Master Language="C#" AutoEventWireup="true" CodeFile="site.master.cs" Inherits="StandardSite " %>

    using System;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using BlogEngine.Core;
    
    //WAP FIX
    //public partial class StandardSite : System.Web.UI.MasterPage
    public partial class TitaniumSite : System.Web.UI.MasterPage
    {
  17. Update the BlogEngine.Core/Utils.CodeAssemblies method by replacing assembly names with BlogEngine.NET.

    public static IEnumerable<Assembly> CodeAssemblies()
    {
        var codeAssemblies = new List<Assembly>();
        CompilationSection s = null;
        //WAP FIX
        //var assemblyName = "__code";
        var assemblyName = "BlogEngine.NET";
        try
        {
            try
            {
                s = (CompilationSection)WebConfigurationManager.GetSection("system.web/compilation");
            }
            catch (SecurityException)
            {
                // No read permissions on web.config due to the trust level (must be High or Full)
            }
    
            if (s != null && s.CodeSubDirectories != null && s.CodeSubDirectories.Count > 0)
            {
                for (var i = 0; i < s.CodeSubDirectories.Count; i++)
                {
                    assemblyName = string.Format("App_SubCode_{0}", s.CodeSubDirectories[i].DirectoryName);
                    codeAssemblies.Add(Assembly.Load(assemblyName));
                }
            }
            else
            {
                //WAP FIX
                //var assemblyName = "App_Code";
                assemblyName = "BlogEngine.NET";
                codeAssemblies.Add(Assembly.Load(assemblyName));
            }
  18. Update BlogEngine.Core/Web/Extensions/ManagedExtension.GetPathAndFilename  to point to the proper filename.

    public string GetPathAndFilename(bool checkExistence)
    {
        string filename = string.Empty;
        var appRoot = HostingEnvironment.MapPath("~/");
        var codeAssemblies = Utils.CodeAssemblies();
        foreach (Assembly a in codeAssemblies)
        {
            var types = a.GetTypes();
            foreach (var type in types.Where(type => type.Name == Name))
            {
                var assemblyName = type.Assembly.FullName.Split(".".ToCharArray())[0];
                assemblyName = assemblyName.Replace("App_SubCode_", "App_Code\\");
                var fileExt = assemblyName.Contains("VB_Code") ? ".vb" : ".cs";
                //WAP FIX
                //filename = appRoot + Path.Combine(Path.Combine(assemblyName, "Extensions"), Name + fileExt);
                filename += Path.Combine("Custom_Code\\Extensions", Name + fileExt);
            }
        }
    
  19. Although this may not be absolutely necessary, since in WAP we won’t be writing changes to cs files from the admin screens anyway, it’s a good idea to clean up loose ends just the same. Update BlogEngine.NET/admin/Extensions/Editor.cshtml.

    var extensionFilename = ext.GetPathAndFilename(false);
    //WAP FIX
    //var canWrite = Utils.CanWrite(Href(Utils.ApplicationRelativeWebRoot + "App_Code/Extensions"));
    var canWrite = Utils.CanWrite(Href(Utils.ApplicationRelativeWebRoot + "Custom_Code/Extensions"));
    var fileExists = !string.IsNullOrWhiteSpace(extensionFilename) && File.Exists(extensionFilename);
    
  20. Convert to Web Application.

    09_ConvertToWebApplication

    10_WarningYes
  21. Success!

All in all the conversion wasn’t the most straight forward process, but not excessively complex by any means.  The most difficult part was nailing down the correct steps and the correct sequence.  After that, the conversion could be performed in under 30 mins.  If there’s enough interest, I’ll upload a converted solution to GitHub.

For more information about BlogEngine.NET http://www.dotnetblogengine.net/ or http://blogengine.codeplex.com/

References

  • 6 Comments