Wednesday, September 30, 2009

eCommerce in the Cloud: Running NopCommerce on Azure

NopCommerce is a well-written open source eCommerce application based on .NET and SQL Server. It’s clean, full-featured, but not bulky and unwieldy like some of it’s competitors. Azure, if you aren’t familiar with it, is Microsoft’s upcoming ‘Cloud Computing’ platform, which allows customers to run .NET applications in Microsoft’s massive data centers with advanced load balancing and high availability.  One key feature of Azure, and cloud computing in general, is that the hosting can be scaled to meet demand.  If demand is high, then with literally one button click, you can make the application run on 2,3, or 20 instances (which can be thought of as servers, though they are technically virtual server instances).  You pay only for the instances and bandwidth you use at any given time.

In eCommerce, this has a very practical implications: you can ramp up the site at peak shopping times, such as holidays, and scale back when not as many people are hitting the site.  In addition, the organization need not invest in servers and IT to maintain them and can focus on their business instead of complex tasks like database backups, load balancing, and clustering infrastructure.  With Azure’s pricing model, this functionality is within the reach of mom-and-pop stores as well as larger companies.

That explains a little why NopCommerce in the cloud is cool.  But how hard is it to do?  Well, I was able to get NopCommerce running on Azure in just a few hours with relatively little fuss.  In a real project, there would of course be all of the normal issues, such as setting up products, design, and such, but Azure was really not much more difficult than your typical hosting provider.  Here’s how I went about it.

Creating a SQL Azure Database

Azure offers several different flavors of data access.  The easiest to work with is probably SQL Azure, which is essentially a slightly modified version of SQL 2008.  To set this up, you simply click ‘Create Database’ on the SQL Azure management page, and enter in a database name.  SQL Azure gives you connection strings to use in your app, with the default ADO.NET or even ODBC and OLEDB providers.  I had to adjust these connection strings (removing the ‘tcp:’ prefix).

image

Once set up, it’s possible to connect SQL Server Management Studio (after jumping through a few minor hoops), or as I did, run the SQL Azure Migration Wizard to copy a database from my PC to SQL Azure.  This tool is nice, but in the version I used had a few bugs that I think are now fixed.  A few SQL Server features aren’t supported in SQL Azure, so you have to tweak most DB scripts to run.  The wizard does this for you, but misses some. Fortunately, the errors are easy to fix:

  • ‘text’ and ‘image’ are not supported.  Use varchar(max) and varbinary(max) instead.
  • ROWGUID is not supported.  Use DEFAULT NewId()
  • Some SQL Server metadata information is not available.  This meant DotNetNuke could not function as-is against SQL Azure.

One the wizard completes, the database is deployed to the cloud, but contains no data.  I used SQL Management Studio to script the data as INSERT statements (Generate Scripts…turn off all scripts except ‘Script Data’) and run them against the SQL Azure instance.  

To test, I changed the connection string in nopCommerce’s configuration, and it worked!

Creating a New Cloud Web App

imageYou don’t simply FTP files to Azure.  Instead, they are packaged in a custom format that contains some service configuration information.  (Also, applications are not just Web apps – Worker apps, similar to windows services, can be packaged and deployed as well).  With Azure Tools for VS installed, I added a ‘Web Cloud Service’ named ‘AzureNopCommerceStore’ to the existing NopCommerce solution.

I copied the references and files from the ‘NopCommerceStore’ ran.  Somewhat to my surprise, everything built and ran, which underscores that this is the same ASP.NET you’re already used to –not a different, scary language or something like ASP.NET MVC (which, by the way is also supported in Azure).  A few bugs did arise, though.  Azure apps run in a limited trust environment in which some functionality is not permitted.  If you’ve developed in Medium Trust, you know the sorts of restrictions, but these are a even more restricted.  A list of restrictions is available here, but in NopCommerce, the mostly revolved around code that generates bitmaps and tries to save them to disk, causing a FileIOPermissions error.

This makes sense – if deployed to multiple instances, writing a file to one instance will not be ‘synced’ up to the other instances.  Instead, you are supposed to store files like this in Azure Blob Storage.  However, in interest of time, I opted to instead generate pictures on the fly, and not cache them to disk at all.  I wrote a quick page to do this, and modified ‘PictureManager’ to accommodate.

With that out of the way, the app ran with no errors (that I’ve found yet, anyway).

Publishing to the Cloud

At this point, NopCommerce is running with one foot in the cloud.  It’s running against a SQL Azure Database in Microsoft’s datacenters, but the app itself is running on a little simulated cloud on my laptop.  To get the app running in production, you right click the ‘AzureNopCommerceStore’ and click ‘publish’.  Visual Studio builds, then creates two files – a package containing all of the web pages, etc., and a configuration file.  The Azure website is opened to a page that allows uploading these files.  Once uploaded, the deployment can be run and the app is ‘live’ on Azure.

One particularly nice feature here is that the publishing infrastructure allows for a ‘Staging’ and ‘Production’ environment.  The package can be uploaded to Staging, tested, then with a single click, transferred over to Production.  Brilliant.

image 

I only get one Azure hosting service to play with in the CTP so it may go away if I decide to try something else out, but for now, you can see it running here:

http://danielazure.cloudapp.net/default.aspx

How to Build 20 Servers in 1 Click

One more cool thing I want to show here.  The promise of Azure is that the hosting service can be adjusted as needed to meet demand.  You can imagine in current scenarios if you needed to set up load balancing for an app, you would order another server, install software, deploy your app, etc. all in a few weeks at best.  If you have a virtual environment, you would provision another server in a few minutes and deploy your app, which is nice, and essentially what Azure does behind the scenes.  But check out the UI for it:

image

By changing ‘Instance count=”1”’ to “20” and clicking ‘Save’, I get 20 virtual instances serving up my site.  I did ‘2’ and it took about 5 minutes to provision.  As I understand it, future releases will support growing and shrinking instances automatically, but for now this is pretty close.

Conclusion

A few things still remain to be done.  I haven’t fully tested, especially around payment gateways and the like, so there still may be bugs to resolve.  Also, I’m not certain how SSL and custom domains work, though I imagine they are supported.  Finally, to really take advantage of Azure, it may make sense to move away from SQL Azure, which is limited to 10GB of data, to one of the other storage options.  This would require more code, but should be feasible.  For all of the hype, in my mind Azure and other cloud offerings really are just next generation hosting providers,with some services such as “infinite” storage and security federation added.  Instead of waiting hours or days for dedicated servers or shared hosting, highly available hosting is provisioned in minutes.  From a developer perspective, working with Azure required some know-how and coding, but in general it is not much more difficult than working with other hosting providers.  If you’re a developer and haven’t tried it yet, give it a shot today.

Saturday, September 26, 2009

INotifyPropertyChanged Performance Shootout

A question recently came up over on the LINDUG about a particular method of implementing INotifyPropertyChanged.  This interface has always been used for databinding, but has gained new importance with WPF and SilverLight binding.  Writing code inline to each property can be tedious and the poster had a creative solution involving a static method to handle the logic.  In his implementation, your properties look like this:

public int PublicInteger
{
get { return _privateInteger; }
set { PropertyHelper(this, ref _privateInteger, value, "PublicInteger",
PropertyChanged); }
} 

We got to discussing the alternatives, and possible performance implications, and another poster pointed out that saving lines of code does not always equal better performance.  So, out of curiosity, I thought I’d do a little test. 

using System;
using System.Diagnostics;
using NUnit.Framework;
using System.ComponentModel;
 
namespace SpikeNotifyPropertyChanged
{
    [TestFixture]
    public class NotifyPropertyChangedTests
    {
 
        [Test]
        public void CustomerNotifyWithInline_Should_Raise_PropertyChanged()
        {
            var target = new CustomerNotifyWithInline();
 
            var propertyChangedWasRaised = false;
 
            target.PropertyChanged += (s, e) => { propertyChangedWasRaised = true; };
 
            target.CustomerName = "Test";
 
            Assert.IsTrue(propertyChangedWasRaised);
 
        }
 
        
        public long CustomerNotifyWithInline_In_100000_Iterations()
        {
            var stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < 100000; i++)
            {
                CustomerNotifyWithInline_Should_Raise_PropertyChanged();
            }
 
            stopwatch.Stop();
            Console.WriteLine("CustomerNotifyWithInline 100000 times took " + stopwatch.ElapsedTicks + " ticks.");
            return stopwatch.ElapsedTicks;
        }
 
 
        [Test]
        public void CustomerNotifyWithInstanceBase_Should_Raise_PropertyChanged()
        {
            var target = new CustomerNotifyWithInstanceBase();
 
            var propertyChangedWasRaised = false;
 
            target.PropertyChanged += (s, e) => { propertyChangedWasRaised = true; };
 
            target.CustomerName = "Test";
 
            Assert.IsTrue(propertyChangedWasRaised);
 
        }
 
      
        public long CustomerNotifyWithInstanceBase_In_100000_Iterations()
        {
            var stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < 100000; i++)
            {
                CustomerNotifyWithInstanceBase_Should_Raise_PropertyChanged();
            }
 
            stopwatch.Stop();
            Console.WriteLine("CustomerNotifyWithInstanceBase 100000 times took " + stopwatch.ElapsedTicks + " ticks.");
            return stopwatch.ElapsedTicks;
        }
 
 
        [Test]
        public void CustomerNotifyWithStaticBase_Should_Raise_PropertyChanged()
        {
            var target = new CustomerNotifyWithStaticBase();
 
            var propertyChangedWasRaised = false;
 
            target.PropertyChanged += (s, e) => { propertyChangedWasRaised = true; };
 
            target.CustomerName = "Test";
 
            Assert.IsTrue(propertyChangedWasRaised);
 
        }
 
        
        public long CustomerNotifyWithStaticBase_In_100000_Iterations()
        {
            var stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < 100000; i++)
            {
                CustomerNotifyWithStaticBase_Should_Raise_PropertyChanged();
            }
 
            stopwatch.Stop();
            Console.WriteLine("CustomerNotifyWithStaticBase 100000 times took " + stopwatch.ElapsedTicks + " ticks.");
            return stopwatch.ElapsedTicks;
        }
 
        [Test]
        public void CompareResults()
        {
            long instanceTime = 0;
            long staticTime = 0;
            long inlineTime = 0;
 
            for (var i = 0; i < 10; i++)
            {
                instanceTime += CustomerNotifyWithInstanceBase_In_100000_Iterations() ;
                staticTime += CustomerNotifyWithStaticBase_In_100000_Iterations();
                inlineTime += CustomerNotifyWithInline_In_100000_Iterations();
            }
            instanceTime = instanceTime/10;
            staticTime = staticTime/10;
            inlineTime = inlineTime/10;
            Console.WriteLine("Average instance time: " + instanceTime);
            Console.WriteLine("Average static time: " + staticTime);
            Console.WriteLine("Average inline time: " + inlineTime);
           
 
 
        }
 
    }
 
    public class CustomerNotifyWithStaticBase : NotifyWithStaticBase 
    {
 
        private string customerName;
 
        public string CustomerName
        {
            get { return customerName; }
            set
            {
                SetValue(this, ref customerName, value, "CustomerName", GetHandler());
            }
        }
 
      
 
    }
 
    public class NotifyWithStaticBase : INotifyPropertyChanged 
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        public PropertyChangedEventHandler GetHandler()
        {
            return this.PropertyChanged;
        }
 
        protected static void SetValue<T>(object sender, ref T field, T value, string propertyName, PropertyChangedEventHandler handler) where T : class
        {
 
            if (field != value)
            {
                field = value;
                
                if (handler != null)
                    handler(sender, new PropertyChangedEventArgs(propertyName));
            }
        }
   
    }
 
 
    public class CustomerNotifyWithInstanceBase : NotifyWithInstanceBase 
    {
        private string customerName;      
 
        public string CustomerName
        {
            get { return customerName; }
            set
            {
               SetValue(ref customerName, value, "CustomerName");                
            }
        }
 
    }
 
    public class NotifyWithInstanceBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected void SetValue<T>(ref T field, T value, string propertyName) where T: class
        {
 
            if (field != value)
            {
                field = value;
 
                var handler = PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
 
 
    public class CustomerNotifyWithInline : INotifyPropertyChanged
    {
        private string customerName;
        public event PropertyChangedEventHandler PropertyChanged;
 
        public string CustomerName
        {
            get { return customerName; }
            set
            {
                if (customerName != value)
                {
                    customerName = value;
                    OnPropertyChanged("CustomerName");
                }
            }
        }
 
        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

This code implements INotifyPropertyChanged in three different ways. 

  • Inline- with all of the logic inside the property setter, and no base class. 
  • StaticBase – with a static method inside a base class, similar to the poster.
  • InstanceBase – with an instance method inside a base class

It then tests each with 10 iterations of 100000 calls to set CustomerName, and averages the number of ticks.  Unfortunately, the test is inconclusive at this point.  The times are just too close.  Plus, with each run of the test, a different method is fastest, which means that some internals to .NET, such as garbage collection or some other factor, are skewing the results:

Average instance time: 84166
Average static time: 82924
Average inline time: 80326

Average instance time: 78257
Average static time: 78422
Average inline time: 75133

All is not lost, though.  We can use NDepend to examine the code.  In terms of IL Instructions:

  • Inline is 63 IL Instructions, and has no base class.
  • StaticBase is 21 for the subclass and  54 for the base class, or 75 total IL instructions.
  • InstanceBase is 19 for the subclass and 50 for the base class, or 69 total IL instructions.

So, strictly speaking, inline has fewer instructions total, but using a base class makes more sense if you have more than one class inheriting from it.  As we added classes, InstanceBase would be a narrow winner. It also has the lowest cyclomatic complexity by one or two points. 

But there’s still one more tool we can throw at this.  Visual studio’s .NET built-in profiler instruments or samples the app and measures the total time an app spends inside a particular method.  As with the timed tests, the results varied, but generally favored the static approach.

image

I’m not sure my tests are conclusive at all, but the static approach may have a slight performance advantage.  In retrospect, this makes sense, as Microsoft Design Guidelines recommend marking methods static when possible:

After you mark the methods as static, the compiler will emit non-virtual call sites to these members. Emitting non-virtual call sites will prevent a check at runtime for each call that ensures that the current object pointer is non-null. This can result in a measurable performance gain for performance-sensitive code.

Of course, this doesn’t necessarily mean everything should be static- in this case the static approach necessitates some additional code that nearly erases any performance benefits.  In both cases, the use of ‘ref’ is also questioned by MS design guidelines.  In the end, there are probably more significant bottlenecks to worry about, but it’s always interesting to dig into stuff like this.  My recommendation: create a base class to help reduce repetitive code with an approach that doesn’t use ‘ref’, or use something like CSLA.