I finally got around to playing with the bits for the Azure SDK, which as of this writing is currently in May 2009 CTP mode. Here are some thoughts.

Pretty good local development experience

Develop against a local cloud, deploy to the real one. The “role” stuff related to the project types in Visual Studio is a little odd at first but once you get past it, it’s the normal Asp.Net development experience we’ve had for a long time now, at least until you want to use the Azure blob/queue/table-storage services.

Hosting services

Literally, File –> New Asp.Net Web Application –> Publish –> (Upload via Azure portal) –> done. Definitely was not expecting this to be so straight forward. Should be really easy to migrate existing Asp.Net sites to the cloud, providing they comply with Azure’s security posture.

There’s a real over-reliance on the StorageClient sample.

Every sample or piece of code for demonstrating developing against Azure is using the StorageClient library, which is one of the sample projects that ships with the Azure SDK. There are numerous posts out there saying it is not to be considered an official API, and that the REST APIs are the real deal. That’s fantastic, but I don’t think any developer is interesting in writing a bunch of HttpWebRequest-heavy code to use Azure or worse, build out their own end to end wrapper to the REST interfaces. Sure, if no official libraries are published, some usable ones will surely pop up on CodePlex but I don’t see how Microsoft would even consider not providing an official .Net API, given what it could potentially do related to adoption of their platform. Microsoft has historically been very pro-RAD in its development platform and tooling, and this is contrary to that, which is puzzling. I mean, one might half-expect to see a TableStorageDataSource control for WebForms. Instead, it sounds like there will be nothing but some docs on MSDN describing the REST calls.

Table Storage != table storage.

Table Storage has a strong connotation for “relational”, and Azure’s Table Storage is anything but. It really should be called Structured Blob Storage, because that’s basically what it is, storing a structured property bag instead of an unstructured blob of ones and zeros. Trying to develop a simple “Post has many Comments” example lead me down a path where I:

    1. Chose Guids as object-keys. Since this is off-premises and not bound to a strict schema, there is no options for auto-incremented properties. You either handle it yourself at the application level or find a better way to handle uniqueness among your entities. Guid.NewGuid() to the rescue.
    2. Realized I either don’t “get” Table Storage and/or I’m doing it wrong. The LINQ capabilities of table storage extend to 4 LINQ operators.  And of those, only the most basic ones. Better support for Take, combined with support for Skip and OrderBy/OrderByDescending would at least provide the foundation of something usable from a querying perspective. I get that it’s not relational, so joining and grouping are probably overkill, but not being able to get the second set of 50 posts sorted by publish date, without fetching all of them and doing it in-memory? Come on. Taking the effort to develop against table storage to leverage the scalability and availability does not make sense when you have to fetch a whole ton of entities only to do a bunch of manipulation in memory in order to send just the right ones back to the client/browser.

Because of the querying limitations, the only way I think I would use Table Storage in an Azure-centric application with non-trivial storage requirements would be to use it as a structured cache for highly-requested or relatively static data. The rest would come from or something else entirely, possibly Sql Azure, formerly Sql Data Services. Of course, Sql Azure isn’t available in any sort of CTP or preview, so the jury is out on that one.

Blob storage

This is the strongest part of the Azure platform as I see it today. Even with the over-reliance on the StorageClient sample, shoving files up to Azure to get reliable, scalable file hosting is one area I think will really shine.

No development support for Windows XP

This is kind of lame, in my opinion. But it will sting less when Windows 7 is out as I suspect a ton of people will be moving to that directly from XP.

 

Overall, I really do like the platform from a development standpoint. Looking forward to what comes out surrounding it during PDC later this year.


 
Categories: Azure

Of all the controls in the Asp.Net WebForms family I think I like the ObjectDataSource the most. It’s a shiny beacon of hope in a framework otherwise bogged down by the perils of ViewState, heavy and un-testable infrastructure classes, and much to be desired in terms of abstractions. I know everyone else is all about the MVC angle bracket soup these days but for those (stuck or by choice) in WebForms land, ODS is fantastic. What it allows you to do, in short, is to make often awkward data-binding your bitch. Let’s see how.

The essence of all data source controls is allowing you, the developer, to short-circuit traditional architectural techniques like layering and get to having working CRUD in a very just-let-me-get-this-done-and-go-home-what-do-you-mean-unit-testing fashion. SqlDataSource goes direct to a database, XmlDataSource goes to xml, and so on. ObjectDataSource is the only one that lets you break out of the 2-tier forms-over-data model that Microsoft likes to push. But what about LinqDataSource? Well, ODS works by binding to methods on a specified class in your code. Which, since it’s your code, allows you much more freedom than any other the others, including the LinqDataSource. Want to provide a specific instance of the binding class to be consumed by the ODS at runtime by your DI container of choice? Want to invoke custom business logic or validation during the CRUD binding-calls? Want to use constructor injection and make your binding class actually, you know, testable? Want to actually put code in a place other than an web form’s code-behind? Want to leverage server-side paging in Linq to Sql to only fetch and display the data you’re concerned with showing? Want to pipe in some custom data from the http cache? All doable with ODS, the others not so much.

For a class to serve as a binding source for an ObjectDataSource, it needs:

  1. One or more methods to return stuff to bind against. Business objects, a DataTable, whatever. These methods can optionally have
    • Two integer parameters for paging (defaulting to ‘maximumRows’ and ‘startRowIndex’) indicating a subset of data to be returned
    • A string parameter for sorting, provided in the form of ColumnName DIRECTION such as ProductName ASC or UnitPrice DESC
  2. A public constructor. Unless you subscribe to the ObjectDataSource’s ObjectCreating event in order to provide a custom instance before the binding calls are executed.
  3. A public method that returns the total number of rows not including the fetched-page size. This is only necessary if your ODS has EnablePaging set to true.
  4. Some attributes on the class or methods that do nothing but tell Visual Studio HEY! SHOW ME AS BINDABLE. Technically these are optional.

Which, in the case of Northwind might look like:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Northwind.Model;

namespace Northwind.DataBinding
{
    [DataObject(true)]
    public class ProductQuerySource : IDisposable
    {
        private NorthwindDataContext _dataContext;
        private bool _disposeContextWhenDone = false;
        private int _count = 0;

        public ProductQuerySource(NorthwindDataContext dataContext)
        {
            if (dataContext == null)
                throw new ArgumentNullException("dataContext");
            
            _dataContext = dataContext;
        }

        public ProductQuerySource()
            : this(new NorthwindDataContext())
        {
            _disposeContextWhenDone = true;
        }

        [DataObjectMethod(DataObjectMethodType.Select)]
        public IList FetchAll(int startAt, int pageSize)
        {
            _count = _dataContext.Products.Count();
            
            var query = _dataContext.Products.Skip(startAt).Take(pageSize).ToList();
            
            return query;
        }

        [DataObjectMethod(DataObjectMethodType.Select)]
        public IList FetchAll(int startAt, int pageSize, string sortExpression)
        {
            _count = _dataContext.Products.Count();

            IQueryable products = _dataContext.Products;

            if (!string.IsNullOrEmpty(sortExpression))
                products = _dataContext.Products.OrderBy(sortExpression);
            
            return products.Skip(startAt).Take(pageSize).ToList();
        }

        public int GetCount()
        {
            return _count;
        }

        public void Dispose()
        {
            if (_disposeContextWhenDone)
                _dataContext.Dispose();
        }
    }
}

With our ObjectDataSource markup resembling

<asp:ObjectDataSource ID="odsNorthwindProducts" runat="server" 
        OldValuesParameterFormatString="original_{0}" 
        SelectMethod="FetchAll" TypeName="Northwind.DataBinding.ProductQuerySource"
        EnablePaging="true"
        MaximumRowsParameterName="pageSize" 
        StartRowIndexParameterName="startAt" 
        SelectCountMethod="GetCount" SortParameterName="sortExpression">
    </asp:ObjectDataSource>

Link that sucker to a GridView with AllowPaging and AllowSorting both set to “true” and you’ll get a grid displaying Products in which only the products currently being rendered are even returned from the database. Click on a column header to sort? Current paged fetched and sorted in database. Fantastic. Note that standard parameter-binding applies here as well, Fetch() could easily have a categoryid parameter which might limit the results to all Products in that category. Since its all just methods on a class, our binding class can be tested using whatever the your testing strategy of choice happens to be.

Oh, but what about that pesky sorting? We can’t sort a linq query by a string, can we? Well, yeah, normally that would be the case, but not to fear, because but by taking a bit of code based on this post by Pradeep Mishra (which has alot of typos in the code there, beware) we’ll be able to dynamically use those string sort expressions to invoke Linq’s OrderBy and OrderByDescending methods. Which, in the case of Linq to Sql, will result in the respective ORDER BY clauses being added to the query once it is executed against the database.

using System;
using System.Linq.Expressions;

namespace System.Linq
{
    public static class LinqExtensions
    {
        public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string sortExpression) where TEntity : class
        {
            if (string.IsNullOrEmpty(sortExpression))
                return source; // nothing to sort on

            var entityType = typeof(TEntity);
            string ascSortMethodName = "OrderBy";
            string descSortMethodName = "OrderByDescending";            
            string[] sortExpressionParts = sortExpression.Split(' ');
            string sortProperty = sortExpressionParts[0];
            string sortMethod = ascSortMethodName;

            if (sortExpressionParts.Length > 1 && sortExpressionParts[1] == "DESC")
                sortMethod = descSortMethodName;    

            var property = entityType.GetProperty(sortProperty);
            var parameter = Expression.Parameter(entityType, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);

            MethodCallExpression resultExp = Expression.Call(
                                                typeof(Queryable), 
                                                sortMethod, 
                                                new Type[] { entityType, property.PropertyType },
                                                source.Expression, 
                                                Expression.Quote(orderByExp));

            return source.Provider.CreateQuery<TEntity>(resultExp);
        }
    }
}

So having that in place means we can have SortParameterName=”sortDirection” in our ODS markup as well as the sortDirection string parameter on the binding method. Hello, server-side paging and sorting.

I should note that this sorting and paging isn’t unique to Linq To Sql- it applies to anything queryable by Linq. It’s just that leveraging this approach with Linq To Sql yields for a more elegant sorting and paging solution when working with a database than some other the other switch-based or (god forbid) stored-procedure based approaches.


 
Categories: Asp.Net | data binding | database | Linq to Sql | Sql Server