LINQ Goodness: Google Charts Edition

My day job (one of them, anyway) is to design*, run and maintain Flying Shakes

If someone had told me when I started  that 90% of the code (and 87.653% of all stats are made up, but you get my drift) I’d write would be for the administration side of things, I’d never have believed it.

 

Anyway, to cut a long story short, it was in this context that I came across a fascinating article from the Association for Computing Machinery (and no, I have not heard of them before either). I came across this a month or so ago, but lost the link.

 

With a little bit of Google-fu, I’ve found it once again: The World According to LINQ.

While its a fascinating article that appeals to the Computer Scientist in me (supposedly useless classes on in-depth database theory tend to do that), what caught my eye was the code sample right at the bottom for generating Google Chart Url’s.

That sample is going to come in very handy for me and I thought I’s share it with you.

Go ahead and read the article.

 

*If you see me ranting on Twitter or Google+ about CSS, this is probably why.

WCF Chat Update: Long Polling

Updating WCF chat continues slowly but surely. I have not made any commits yet, so you’ll have to wait to see the changes.

In addition to the changes to Authentication, there are changes to the callback mechanism that I originally wrote.

 

When i originally wrote the chat application, the callback was one of the first pieces of code that i wrote. The fact of the matter is, the the only requirement for it was to work across the local network (or even simply between instances on the local machine). So when I wrote the Cloud version, suddenly callbacks had to work across NAT to let the application function across the internet.

 

Now, there are a number of possible design patterns that would allow the server to execute a callback on a remote client. 

 

The first is ,indeed, the design pattern we use at the moment. Where we actually have a callback. the enabler for this is actually found in WCF. The wsHTTPDuplexBinding allows for dual HTTP connections – one in each direction. This allows you to invoke an operation on the client. However, in order for this to work, you need to have an instance of WCF server on a per-instance basis. So. Every new client session will spawn a new instance of the server. This means that you are going to end up with dozens ( or hundreds etc) of long-lived instances. The question here is scalability. Is this scalable?

It might seem somewhat arrogant to talk about scalability, but if you design with scalability in mind, you’re not going to end up dealing with it later.

 

The other is something that, while not new, really hit the big-time after Friendfeed released its Tornado server. Tornado supports long polling http connections. Long polling is not in and of itself new. The basic design pattern involves a client making a call ( http or otherwise) to a server. The server receives the connection and keeps it open until it has something to return. Some long polled connections eventually time out and this is the implicit signal for the client to immediately open another connection. Others, such as the Friendfeed implementation, keep them open indefinitely.

 

There are probably more that you can think of, but these are the two that I considered for the Chat Application. As with most things, the choice is between a Push model (where notifications are pushed to the client) and the Pull model (where information, Notifications or otherwise, is pulled from the server by the client).

 

The fact of the matter is that I like both. Both are Cool. And both are supported intrinsically by WCF – no coding voodoo to make thins work.

Of the two, I’ve begun implementing the long polling method. Although it s radical departure, it will allow the overall design of to server-side to remain the same. The WCF server remains as a Single Instance service, and so the implementation remains the same.

The WCF stack is written in such a way that when you mark a OperationContract as needing the Async Pattern, WCF with start the Asyc operation and then go off and handle another request until that method returns. The End method that receives the results then returns the data to the client. In other words, its non-blocking.

I’ve not sorted out the exact specifics of implementation, but there will be changes to both the server and the client to accommodate  this. In saying that, I’m doing  a lot of simplification to the class structure. So hopefully what emerges from all these changes will be better than the current setup. Even I had to go back and follow the inheritance tree to figure things out.

These changes are happening in parallel with the changes to the authentication scheme.

 

So, while I’ve got no code, I leave you with this MSDN blog post on Async programming with WCF and this post that adapts it to long-polling specifically.

Some Interesting Code – your thoughts required

Without going to into a long story, I found some interesting code here to convert anonymous types to any strongly typed, well, type.

 

public static object ToType<T>(this object obj, T type)
{

    //create instance of T type object:
    var tmp = Activator.CreateInstance(Type.GetType(type.ToString())); 

    //loop through the properties of the object you want to covert:          
    foreach (PropertyInfo pi in obj.GetType().GetProperties()
    {
      try 
      {   

        //get the value of property and try 
        //to assign it to the property of T type object:
        tmp.GetType().GetProperty(pi.Name).SetValue(tmp, 
                                  pi.GetValue(obj, null), null)
      }
      catch { }
     }  

   //return the T type object:         
   return tmp; 
}

From this codeproject article.

Anyone have any thoughts on this?  Is it good? Bad? Inefficient? Crap??

Windows Azure Block Blobs

In Windows Azure Blob Storage, not all blobs are created equal. Windows Azure has the notion of Page Blobs and Block Blobs.  Each of these distinct blob types aim to solve a slightly different problem, and its important to understand the difference.

To Quote the documentation:

  • Block blobs, which are optimized for streaming.
  • Page blobs, which are optimized for random read/write operations and provide the ability to write to a range of bytes in a blob.

About Block Blobs

Block blobs are comprised of blocks, each of which is identified by a block ID. You create or modify a block blob by uploading a set of blocks and committing them by their block IDs. If you are uploading a block blob that is no more than 64 MB in size, you can also upload it in its entirety with a single Put Blob operation.

When you upload a block to Windows Azure using the Put Block operation, it is associated with the specified block blob, but it does not become part of the blob until you call the Put Block Listoperation and include the block’s ID. The block remains in an uncommitted state until it is specifically committed. Writing to a block blob is thus always a two-step process.

Each block can be a maximum of 4 MB in size. The maximum size for a block blob in version 2009-09-19 is 200 GB, or up to 50,000 blocks.

About Page Blobs

Page blobs are a collection of pages. A page is a range of data that is identified by its offset from the start of the blob.

To create a page blob, you initialize the page blob by calling Put Blob and specifying its maximum size. To add content to or update a page blob, you call the Put Page operation to modify a page or range of pages by specifying an offset and range. All pages must align 512-byte page boundaries.

Unlike writes to block blobs, writes to page blobs happen in-place and are immediately committed to the blob.

The maximum size for a page blob is 1 TB. A page written to a page blob may be up to 1 TB in size.

So, before we determine what blob type we’re going to use, we need to determine what we’re using this particular blob for in the first place.

You’ll notice the above extract is quite clear what to use block blobs for: streaming video. In other words, anything that we don’t need random I/O access to. On the other hand page blobs have a 512-byte page boundary that makes it perfect for random I/O access.

And yes, its conceivably possible for you to need to host stuff such as streaming video as a page blob. When you think about this stuff to much, you end up imagining situations where that might be possible.  So, these would be situations where you are directly editing or reading very select potions of a file. If you’re editing video, who wants to read in an entire 4MB for one frame of video? You might laugh at the idea of actually needing to do this, but that the Rough Cut Editor is web based and works primarily with web-based files. If you had to run that using Blob storage as a backend you’d need to use page blobs to fully realise the RCE’s functionality.

So, enough day-dreaming. Time to move on.

Some groundwork

Now, in our block blob, each individual block can be a maximum of 4MB in size. Assuming we’re doing streaming video, 4MB is not going to cut it.

The Azure API provides the CloudBlockBlob class with several helper methods for managing our blocks. The methods we are interested in are:

  • PutBlock()
  • PutBlockList()

The PutBlock method takes a base-64 encoded string for the Block ID, a stream object with the binary data for the block and a (optional) MD5 hash of the contents. Its important to note that the ID string MUST be base-64 encoded or else Windows Azure will not accept the block. For the MD5 hash, you can simply pass in null.  This method should be called for each and every block that makes up your data stream.

The PutBlockList  is the final  method that needs to be called. It takes a List<string>  containing every ID of every block that you want to be part of this blob. By calling this methods it commits all the blocks contained in the list. This means, then, that you could land up in a situation where you’ve called PutBlock but not included the ID when you called PutBlockList. You then end up with an incomplete and corrupted file. You have a week to commit uploaded blocks. So all is not lost if you know which blocks are missing. You simply call PutBlockList with the IDs of the missing blocks.

There are a number of reasons why this is a smart approach.  Normally, I fall on the side of developer independence, the dev being free to do things as he likes without being hemmed in. In this case, by being forced to upload data in small chuncks, we realise a number of practical benefits. The big one being recovery from bad uploads – customers hate having to re-start gigabyte sized uploads from scratch.

Here be Dragons

The following example probably isn’t the best. I’m pretty sure someone will refactor and post a better algorithm.

Now there are a couple of things to note here.  One bring that I want to illustrate what happens at a lower level of abstraction that we usually work at, so that means no StreamReaders – We’ll read the underlying bytes directly.

Secondly, not all Streams have the same capability. Its perfectly possible to come across a Stream object where you can’t seek. Or determine the length of the stream. So this is written to handle any data stream you can throw at it.

With that out of the way, lets start with some Windows Azure setup code.

StorageCredentialsAccountAndKey key = new StorageCredentialsAccountAndKey(AccountName, Account Key);
CloudStorageAccount acc = new CloudStorageAccount(key, true);

CloudBlobClient blobclient = acc.CreateCloudBlobClient();
CloudBlobContainer Videocontainer = blobclient.GetContainerReference("videos");
Videocontainer.CreateIfNotExist();

CloudBlockBlob blob = Videocontainer.GetBlockBlobReference("myblockblob");

Note how we’re using the CloudBlockBlob rather than the CloudBlob class.

In this example we’ll need our data to be read into a byte array right from the start. While I’m using data from a file here, the actual source doesn’t matter.

byte[] data = File.ReadAllBytes("videopath.mp4");

Now, to move data from our byte array into individual blocks, we need a few variables to help us.

            int id = 0;
            int byteslength = data.Length;
            int bytesread = 0;
            int index = 0;
            List blocklist = new List();
  • Id will store a sequential number indicating the ID of the block
  • byteslength is the length, in bytes of our byte array
  • bytesread keeps a running total of how many bytes we’ve already read and uploaded
  • index is a copy for bytes read and used to do some interim calculations in the body of the loop (probably will end up refactoring it out anyway)
  • blocklist holds all our base-64 encoded block id’s

Now, on to the body of the algorthim. We’re using a do loop here since this loop will always run at least once (assuming, for the sake of example, that all files are larger than our 1MB block boundary)

do
            {
                byte[] buffer = new byte[1048576];
                int limit = index + 1048576;
                for (int loops = 0; index < limit; index++)
                {
                    buffer[loops] = data[index];
                    loops++;
                }

The idea (that of using a do loop) here being to loop over our data array until less than 1MB remains.

Note how we’re using a separate byte array to copy data into. This the block data that we’ll pass to PutBlock. Since we’re not using StreamReaders, we have to do the copy byte for byte as we go along.

It is this bit of code would be abstracted away were we using StreamReaders (or, more properly for this application, BinaryReaders)

Now, this is the important bit:

                 bytesread = index;
                string blockIdBase64 = Convert.ToBase64String(System.BitConverter.GetBytes(id)); //1

                blob.PutBlock(blockIdBase64, new MemoryStream(buffer, true), null); //2

                blocklist.Add(blockIdBase64);
                id++;
            } while (byteslength - bytesread > 1048576);

There are three things to note in the above code. Firstly, we’re taking the block ID and base-64 encoding it properly.

And secondly, note the call to PutBlock. We’re wrapped the second byte array containing just our block data as a MemoryStream object (since that’s what the PutBlock methods expects) and we’ve passed in null rather than an MD5 hash of our block data.

Finally, note how we add the block id to our blocklist variable. This will ensure that the call to PutBlockList will include the ID’s of all of our uploaded blocks.

So, by the time this do loops finally exits, we should be in a position to upload our final block. This final block will almost certainly be less than 1MB in size (barring the usual edge case caveats). Since this final block is less than 1MB, our code will need a final change to cope with it.

            int final = byteslength - bytesread;
            byte[] finalbuffer = new byte[final];
            for (int loops = 0; index < byteslength; index++)
            {
                finalbuffer[loops] = data[index];
                loops++;
            }
            string blockId = Convert.ToBase64String(System.BitConverter.GetBytes(id));
            blob.PutBlock(blockId, new MemoryStream(finalbuffer, true), null);
            blocklist.Add(blockId);

Finally, we make our call to PutBlockList, passing in our List array (in this example, the “blocklist” variable).

blob.PutBlockList(blocklist);

All our blocks are now committed. If you have the latest Windows Azure SDK (and I assume you do), the Server Explorer should allow you to see all your blobs and get their direct URL’s.  You can downloaded the blob directly in the Server Explorer, or copy and paste the URL into your browser of choice.

Wrap up

Basically, what we’ve covered in this example is a quick way of breaking down any binary data stream into individual blocks conforming to Windows Azure Blob storage requirements, and uploading those blocks to Windows Azure. The neat thing here is that by using this method not only does the MD5 hash let Windows Azure check data integrity for you, but block ID’s let Windows Azure take care of putting the data back together in the correct sequence.

Now when I refactor this code for actual production, a couple of things are going to be different. I’ll do the MD5 hash. I’ll upload blocks in parallel to take maximum advantage of upload bandwidth (this being the UK, there not much upload bandwidth, but I’ll take all I can get). And obviously, I’ll use the full capability of Stream readers to do the dirty work for me.

Heres the full code:

StorageCredentialsAccountAndKey key = new StorageCredentialsAccountAndKey(AccountName, Account Key);
CloudStorageAccount acc = new CloudStorageAccount(key, true);

CloudBlobClient blobclient = acc.CreateCloudBlobClient();
CloudBlobContainer Videocontainer = blobclient.GetContainerReference("videos");
Videocontainer.CreateIfNotExist();

CloudBlockBlob blob = Videocontainer.GetBlockBlobReference("myblockblob");

byte[] data = File.ReadAllBytes("videopath.mp4");

int id = 0;
int byteslength = data.Length;
int bytesread = 0;
int index = 0;
List blocklist = new List();

do
            {
                byte[] buffer = new byte[1048576];
                int limit = index + 1048576;
                for (int loops = 0; index < limit; index++)
                {
                    buffer[loops] = data[index];
                    loops++;
                }
                bytesread = index;
                string blockIdBase64 = Convert.ToBase64String(System.BitConverter.GetBytes(id));

                blob.PutBlock(blockIdBase64, new MemoryStream(buffer, true), null);

                blocklist.Add(blockIdBase64);
                id++;
            } while (byteslength - bytesread > 1048576);

            int final = byteslength - bytesread;
            byte[] finalbuffer = new byte[final];
            for (int loops = 0; index < byteslength; index++)
            {
                finalbuffer[loops] = data[index];
                loops++;
            }
            string blockId = Convert.ToBase64String(System.BitConverter.GetBytes(id));
            blob.PutBlock(blockId, new MemoryStream(finalbuffer, true), null);
            blocklist.Add(blockId);
            blob.PutBlockList(blocklist);

Sitemaps in ASP.Net MVC: Icing on the Cake

This is short simple and sweet (forgive the pun).  The reason why i say that is that you have two options when doing a sitemap in MVC (actually, you have more, but whatever).

The first is using a Library. There’s a MVC Sitemap provider on Codeplex that you can download and install. It involves some XML configuration and attributes on all the actions you want to include in your sitemap.

The fact is, I don’t have time to fiddle around with configurations. I just want a simple sitemap file with a handful of products, categories and one or two other links. If the site was larger and more complex I might consider it.

So, we come to the second, DIY way. Now, this is not entirely my idea. I just repurposed it to pull the correct URL parameters out of the db. The original code is found on Codeplex.

Firstly, we have to register a new route to www.example.com/sitemap.xml. Go to Global.asax and put the following in your RegisterRoutes() method. I put mine after the call to IgnoreRoute.

routes.MapRoute("Sitemap", "sitemap.xml", new { controller = "Home", action = "Sitemap", id = UrlParameter.Optional });

Now, you can use any default routing you want with this. As you can see above, the route is pointing to the Sitemap action of the Home controller.

Then we have to actually populate our Action with some code.

  protected string GetUrl(object routeValues)
        {
            RouteValueDictionary values = new RouteValueDictionary(routeValues);
            RequestContext context = new RequestContext(HttpContext, RouteData);

            string url = RouteTable.Routes.GetVirtualPath(context, values).VirtualPath;

            return new Uri(Request.Url, url).AbsoluteUri;
        }
        [OutputCache (Duration=3600)]
        public ContentResult Sitemap()
        {
            var categories = storeDB.Categories.Include("Products").Where(g => g.Id != 8); //some filtering of categories
            XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            XElement root = new XElement(xmlns + "urlset");

            List<string> urlList = new List<string>();
            urlList.Add(GetUrl(new { controller = "Home", action = "Index" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "Terms" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "ShippingFAQ" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "Testimonials" }));
            foreach (var item in categories)
            {
                urlList.Add(string.Format("{0}?{1}={2}",GetUrl(new { controller = "Store", action = "BrowseProducts"}),"category",item.Name));

                foreach (var product in item.Products)
                {
                    urlList.Add(string.Format("{0}/{1}", GetUrl(new { controller = "Store", action = "ProductDetails" }), product.Id));
                }
            }

            foreach (var item in urlList)
            {
                root.Add(
                new XElement("url", 
                new XElement("loc", item), 
                new XElement("changefreq", "daily")));
            }

            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
                {
                    root.Save(writer);
                }

                return Content(Encoding.UTF8.GetString(ms.ToArray()), "text/xml", Encoding.UTF8);
            }
        }

Essentially, we’re just outputting an xml file with the correct format and structure.  This gives us a file that looks like:

<?xml version="1.0" encoding="utf-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

  <url xmlns="">

    <loc>http://localhost:26641/</loc>

    <changefreq>daily</changefreq>

  </url>

  <url xmlns="">

    <loc>http://localhost:26641/Home/Terms</loc>

    <changefreq>daily</changefreq>

  </url>

  <url xmlns="">

    <loc>http://localhost:26641/Home/ShippingFAQ</loc>

    <changefreq>daily</changefreq>

  </url>

You get the idea.

The above code is using Entity Framework 4.1, so you can replace the line that declares  “var categories” with whatever data source you have. And you’ll have to reformat the url strings to conform to your parameter format.

Now I’m not suggesting this for any large MVC deployment. The code could get rather messy.

 

But for something simple, it works like a dream.

Using SQL Azure with ELMAH

If you don’t know what ELMAH is, stop right now and go and read about it.

ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.

Then go and read Scott “TheHa” Hanselman’s post on it.

There is a Nuget package for it as well, to make things really super easy.

In fact, running Nuget, setting up SQL Azure and tweaking some config settings took me all of 20 minutes. No freaking kidding. 

Now remember that this is being installed on an MVC site, so don’t let that put you off. Here we go:

Step One: Install from Nuget (making sure you have the latest build of Nuget in the process)

Step Two: Setup SQL Azure

Step Three configure web.config

 

And done Smile

 

So, lets go back and look at the details.

In step two, this is the SQL Azure script that the Migrate Assist wizard spat out:

--~Changing index [dbo].[ELMAH_Error].PK_ELMAH_Error to a clustered index.  You may want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_Error]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[ELMAH_Error](
	[ErrorId] [uniqueidentifier] NOT NULL,
	[Application] [nvarchar](60) NOT NULL,
	[Host] [nvarchar](50) NOT NULL,
	[Type] [nvarchar](100) NOT NULL,
	[Source] [nvarchar](60) NOT NULL,
	[Message] [nvarchar](500) NOT NULL,
	[User] [nvarchar](50) NOT NULL,
	[StatusCode] [int] NOT NULL,
	[TimeUtc] [datetime] NOT NULL,
	[Sequence] [int] IDENTITY(1,1) NOT NULL,
	[AllXml] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_ELMAH_Error] PRIMARY KEY CLUSTERED 
(
	[ErrorId] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_Error]') AND name = N'IX_ELMAH_Error_App_Time_Seq')
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_App_Time_Seq] ON [dbo].[ELMAH_Error] 
(
	[Application] ASC,
	[TimeUtc] DESC,
	[Sequence] DESC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[DF_ELMAH_Error_ErrorId]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[ELMAH_Error] ADD  CONSTRAINT [DF_ELMAH_Error_ErrorId]  DEFAULT (newid()) FOR [ErrorId]
END

GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_GetErrorsXml]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[ELMAH_GetErrorsXml]
(
    @Application NVARCHAR(60),
    @PageIndex INT = 0,
    @PageSize INT = 15,
    @TotalCount INT OUTPUT
)
AS 

    SET NOCOUNT ON

    DECLARE @FirstTimeUTC DATETIME
    DECLARE @FirstSequence INT
    DECLARE @StartRow INT
    DECLARE @StartRowIndex INT

    SELECT 
        @TotalCount = COUNT(1) 
    FROM 
        [ELMAH_Error]
    WHERE 
        [Application] = @Application

    -- Get the ID of the first error for the requested page

    SET @StartRowIndex = @PageIndex * @PageSize + 1

    IF @StartRowIndex <= @TotalCount
    BEGIN

        SET ROWCOUNT @StartRowIndex

        SELECT  
            @FirstTimeUTC = [TimeUtc],
            @FirstSequence = [Sequence]
        FROM 
            [ELMAH_Error]
        WHERE   
            [Application] = @Application
        ORDER BY 
            [TimeUtc] DESC, 
            [Sequence] DESC

    END
    ELSE
    BEGIN

        SET @PageSize = 0

    END

    -- Now set the row count to the requested page size and get
    -- all records below it for the pertaining application.

    SET ROWCOUNT @PageSize

    SELECT 
        errorId     = [ErrorId], 
        application = [Application],
        host        = [Host], 
        type        = [Type],
        source      = [Source],
        message     = [Message],
        [user]      = [User],
        statusCode  = [StatusCode], 
        time        = CONVERT(VARCHAR(50), [TimeUtc], 126) + ''Z''
    FROM 
        [ELMAH_Error] error
    WHERE
        [Application] = @Application
    AND
        [TimeUtc] <= @FirstTimeUTC
    AND 
        [Sequence] <= @FirstSequence
    ORDER BY
        [TimeUtc] DESC, 
        [Sequence] DESC
    FOR
        XML AUTO

' 
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_GetErrorXml]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[ELMAH_GetErrorXml]
(
    @Application NVARCHAR(60),
    @ErrorId UNIQUEIDENTIFIER
)
AS

    SET NOCOUNT ON

    SELECT 
        [AllXml]
    FROM 
        [ELMAH_Error]
    WHERE
        [ErrorId] = @ErrorId
    AND
        [Application] = @Application

' 
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_LogError]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[ELMAH_LogError]
(
    @ErrorId UNIQUEIDENTIFIER,
    @Application NVARCHAR(60),
    @Host NVARCHAR(30),
    @Type NVARCHAR(100),
    @Source NVARCHAR(60),
    @Message NVARCHAR(500),
    @User NVARCHAR(50),
    @AllXml NVARCHAR(MAX),
    @StatusCode INT,
    @TimeUtc DATETIME
)
AS

    SET NOCOUNT ON

    INSERT
    INTO
        [ELMAH_Error]
        (
            [ErrorId],
            [Application],
            [Host],
            [Type],
            [Source],
            [Message],
            [User],
            [AllXml],
            [StatusCode],
            [TimeUtc]
        )
    VALUES
        (
            @ErrorId,
            @Application,
            @Host,
            @Type,
            @Source,
            @Message,
            @User,
            @AllXml,
            @StatusCode,
            @TimeUtc
        )

' 
END
GO

Log in to SQL Management Studio and run that script against your chosen db and you’re good to go.

 

In step 3, there are 2 main things you want to do.

The first is obviously setting up ELMAH to talk to the db. We do it like so.

<elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ConnectionStringhere" />
    <security allowRemoteAccess="yes" />
  </elmah>

And the second is securing the actual elmah.axd page.

  <location path="elmah.axd">
    <system.web>
      <authorization>
        <deny users="?"/>
        <allow roles="Administrator"/>
      </authorization>
    </system.web>
  </location>

And we’re done. Easiest thing I’ve ever done. Smile

Pre Sunday Sunday Times iPad App Review

Now before we get much further into this review, you need to understand that I am very much an information junkie. Reading the Sunday times over of cup of tea on Sunday morning is very much a part of life. Of course, being a Sunday morning, it involves actually getting out of bed and driving to the shop to get it. I’m not Tory enough to get it delivered. In fact, I’m not Tory At all. I’m kidding.

The fact is that I very much prefer the Sunday papers, their articles and opinion pieces having been digested for an entire week before writers put pen to paper. Even a Murdoch paper ends up sounding reasonable after a week of through thought.

But I digress Now, on to the app itself.

I must say that at least visually, the app is very well designed. For a paper the size of the Sunday Times, the navigation is actually quite simple. Each issue of the times is split up into a number of sections. Each section has a front page and a table of contents for each story in that section.

The majority of your time is going to be spent in the Section part of the application. Her you have the sections laid out for you. Then, you can filter these sections by the issue they come from. So unless you filter, this area is going to be come rather crowded.

This is also where you download the individual sections from the issue you have bought. This is of prime importance for me. Basically because I’m not going to be reading every single section of the paper. So I get to pick and choose what I want to download and I content have to wait for the whole paper to download before I can start reading.

Now, you also get a page view, where you can scrobble along to find the exact page you’d like to read. This is rather useful, specially given the sheer number of pages you’re going to end up with in the larger sections of the paper.

Finally, the store is quite simply laid out, with the option buy the latest issue front and centre. You can swipe to the right to but older issues if you want, though frankly why would you want to? Anyhow, i can see why it could come in useful for some.

Finally, it should be noted that the multimedia content is only visible in landscape mode, or so it appears anyway. You have the option of reading a story in portrait if you went as well, but I fee that this app really is made to be viewed in landscape. It is after all a Sunday paper, made for reading slowly and thoughtfully on the couch, and not a daily paper made for busy people with less time on their hands.

The fact of the matt is that at £1.79 an issue, this is a steal. And in the process, as if its not a bargain already, I get to stay warm in bed and read it on Sunday morning. It doesn’t get much better an that.

Heres the obligatory screenshot gallery. Note: I used one of the sample issues here and downloaded the Magazine section of the paper.

photo 1photo 2photo 3photo 1photo 2photo 3photo 5photo 4

Flipboard Review

One of the first apps I installed on my 64Gb wifi ipad was the Flipboard app. Now, after all the hoopla I heard from Robert Scoble and others, I was eager to use the app myself.

Now, the fact of the matter is that the app is beautifully designed. Really it is. A work of art. The page flips are beautifully animated. The app start up is brilliant, making me wonder each and every time i start it up what picture I’m going to get. The popout article pages are beautifully presented. Even the twitter client aspect of the app is very nicely done.

However, there are times when I go through my settle very leisurely and rather randomly, and Flipboard is sheer gold dust when it comes to this. Other times I’m more structured about my reading. I read the Tech folder first, then the Space folder, and finally the General folder. Only then, if i have time, do I randomly go through my other folders. This second way of reading my feeds is rather difficult on Flipboard. Moving between folders isn’t a smooth process and it requires too much work.

I actually prefer Feedly on my iPhone for reading my feeds when I’m going through Feedly quickly.

Feedly for iPad is coming soon, and we’ll see what difference it makes in this area.

There is one thing I’ve noticed: read/unread items do not always translate back to Feedly on the desktop. So, in fact, I end up reading some items twice. Since I’ve no idea of how Flipboard works under the hood, I’m not sure where the lag is coming in, whether it’s a Flipboard, Google Reader, or Feedly issue. But it sure would be nice to have some sync going on.

However, that having been said, Flipboard is very much of my routine. I rather enjoy reading it in the mornings over a cup of tea. It’s the first app I open. I really do think that it’s a most marvellous application and will definitely be using it very often.

Client Server Chat with WCF

Almost a year after I wrote this post promising to keep WCF Chat updated, I’m living up to that promise and updating my WCF Chat application over on Codeplex. The original release on Codeplex is actually just a zip file with the project in it. All things considered it was a knee-jerk posting in the mist of the openFF effort to clone Friendfeed. Of course, the original, actual reason why I posted it is lost to history. And in the middle of all that  hoohah I never wrote an introduction to and an explanation of the codebase.

An Introduction

 

The WCF Chat application was actually a class assignment for a class that included, among other things, WCF, REST and TCP. Its actually interesting to see how that class has changed since I took it three years ago. This year, for example, its including MVC, but I digress. The fact is that my submission did go above and beyond the requirements. And the reason for that is that once I wrote the basic logic, the more complicated stuff was easy. In other words: given enough layers of abstractions, anything is easy.

Having dusted off and worked with the code for a few hours, its rather amazing how easy a chat application is. Now, that statement should be taken in the context of the fact that WCF is doing most of the heavy lifting. So getting the client to ask for data is a relatively trivial task. The tricky bit is the need for a callback.

In this case, I use callbacks for Direct Messages and File transfers. Now, you are probably wonder why I went through the trouble given that the sensible option is simply to poll a server. And it is a sensible option. Tweetdeck, Seesmic and other twitter clients all use polling. Basically, it was in the requirements that there should be two way communication. There are a number of way sto implement this. One could, for example, have a WCF service on the client that the server can call back to. This did occur to me, but its a complex and heavy handed approach, not to mention a resource intensive one. WCF always gives me headaches and so I was only going to do one service. So I wrote a TCP listener that received pings from the server on a particular port.

Thats one peculiarity about this app. The other is the way the server is actually written. We have the WCF service implementation and we have a second server class that the WCF service calls. There is a division of responsibility between the two. The service is always responsible for getting the data ready for transmission and the server does the actual application logic.

The client is fairly straightforward. It uses the Kryton Library from the Component Factory. Its a great UI library that I use anytime I have to write a Windows forms UI. The actual UI code is rather like the Leaning Tower of Pisa – its damn fragile. Basically because it relies on the component designer logic for the way controls are layered. So I haven’t touched it at all. In fact, I haven’t needed to. More on this later.

When you are looking at the client code, you’ll realise that for each type of message control, there is a message type base control. The reason for this is that I foolishly (and successfully) tried to use generic controls. In the current implementation, there is actually precious little code in the MessageBase control. The reason  for this is mainly historical. There was originally a lot of code in there, mainly event code. In testing, I discovered that  those events weren’t actually firing for reasons beyond understanding. So they were moved from the inherited class to the inheriting class.  This is the generic control.

There are message type base controls that inherit from the MessageBase control, and pass in the type (Post, DM, File). This control is in turn inherited by the actual Message, DM or File control. The reason for this long inheritance tree is that the designer will not display generic controls. Rather, that was the case. I’ve yet to actually try it with Visual Studio 2010 Designer. As I said, I haven’t changed the client UI code and architecture at all.

The client has a background thread that runs a TCP Listener to  listen for call backs from the server. Its on a background thread so that it does not block the UI thread. I used a background worker for this rather than the newer Task functionality built into .Net 4 that we have today.

Functionality

 

Basically, every one sees all the public messages on a given server. There is no mechanism to follow specific people or ever to filter the stream by those usernames. Archaic, I know, But I’m writing my chat application, not Twitter.

There are Direct Messages that can be directed to a specific user. Because the server issues callbacks for DM’s, they appear almost instantly in the users stream.

You can send files to specific users as well. These files are stored on the server when you sent them. The server will issue a call back to the user and the file will be sent to them when the client responds to that callback.  You can also forward a file you have received to another user. Files are private only by implication. They are able to be accessed by whoever is informed of the files existence.

All of the above messages are persisted on the server. However, forwarding messages is not persisted in any shape or form.

Also, you can set status. This status is visible only when you are logged in. In fact, your username is only visible to others when you are logged in.

It should be noted that you have to use the Server Options panel to add and remove users.

Todays Release

 

Todays changes basically upgrade everything to .Net 4  and make sure its compatible. Todays release does not take advantage of anything new other than some additional LINQ and extension methods. Taking advantage of the new stuff will require a careful think of how and where to use them. I’m not quite willing to sacrifice a working build for new code patterns that do the exact same thing.

The original server was actually just a console application. I took that original code and ported it to a Windows Service. There were trivial logic changes made at most. The UI ( i.e the Options form) that was part of that console application has been moved into its own project.

I also ported the server code to a Windows Azure web role. And let me tell you something- it was even easier that I had anticipated. The XML file and the collections I stored the streams  in  are replaced with Windows Azure Tables for Users, Streams, DMS and Files. The files themselves are written to Windows Azure Blobs rather than being written out to disk. 

The web role as written is actually single instance. The reason is that the collection that stores the active users (i.e. what users are active right now) is still a collection. I haven’t moved it moved it over to windows azure tables yet. You could fire up more than one instance of this role, but all of them would have a different list of active users. And because Windows Azure helpfully provides you with a load balancer, there’s no guaranteeing which instance is going to respond to the client. There is a reason why i haven’t move that collection over to Windows Azure Tables. Basically, I’m not happy with it. If Azure had some sort of caching tier, using Velocity or something so i could instantiate a collection of objects to the cache and have all instances share that collection. The Windows Azure table would be changing from minute to minute with Additions, Edits and Deletions and I don’t think Windows Azure Tables would keep up. I’m interested to now what you think of this.

I also added an Options application to talk to the Windows Azure Web Role, and I wrote a WCF web service in webrole to support this application.

The client  is essentially the same as it has always been. There is the addition of a domain when you are logging in – this could be for either cloud or service based server implementations. Since there is no default domain, the client needs one when you are logging in.  The client will ask for one when logging in. once you have provided one, you’ll have to restart the application.

There are installers for all the applications except for the Cloud project. The service installer will install both the service and the Options application.

Bear in mind that for the Options Applications, there is no authentication and authorisation. If you run the app on a server with the ChatServer installed, or you point the CloudOptions app at the appropriate server, you are in control. This is a concern to me and will be fixed in a future release.

Future changes

 

I was tempted to write a HTTP POST server for all this. MVC makes it so easy to implement. There would be plenty of XML flying back and forth. Some of the WCF operations would require some high-wire gymnastics to implement as HTTP POST, but its possible. I might to this.

The one thing that I didn’t update was the version of the Kryton UI library I use. I’d very much like to use the latest version to write a new UI from scratch. Again its a possibility.

The fact is that once you start thinking of implementing following a la twitter, your database schema suddenly looks much more complicated. And since I’m not writing Twitter, I’ll pass.

If you have any suggestions on future changes, holler.

Final Words

 

Bear in mind that for the Options Applications, there is no authentication and authorisation. If you run the app on a server with the ChatServer installed, or you point the CloudOptions app at the appropriate server, you are in control. This is a concern to me and will be fixed in a future release.

Also, bear in mind that this is marked Alpha for a reason. If it eats your homework and scares your dog, its not my fault – I’m just some guy that writes code.

Finally, this code all works IN THEORY. I’ll be testing all these pieces throughly in the coming weeks.

Where you can get it

 

You can get it off Codeplex. The source code for all the above mentioned components is checked into SVN source control.

For this 1.1 Alpha release, you’ll find each setup files for each component in a separate downloadable zip file. The CloudServer code is included as is, since no setup files are possible for Cloud projects.

Note to self– Use OutputCache in MVC 3

I’m just reading ScottGu’s post on the MVC 3 release candidate.

What got me really thinking was the output cache attribute:

image

Scott explains:

Notice how the DailySpecials method above has an [OutputCache] attribute on it.  This indicates that the partial content rendered by it should be cached (for 3600 seconds/1 hour).  We are also indicating that the cached content should automatically vary based on the category parameter.

If we have 10 categories of products, our DailySpecials method will end up caching 10 different lists of specials – and the appropriate specials list (computers or diapers) will be output depending upon what product category the user is browsing in.  Importantly: no database access or processing logic will happen if the partial content is served out of the output cache – which will reduce the load on our server and speed up the response time.

This new mechanism provides a pretty clean and easy way to add partial-page output caching to your applications.

So, with my Windows Azure Feedreader in mind,  my note to self is as follows:

In a couple of weeks, when we get to the shared items Rss feed, we can use this code. We vary by user id rather than by category in the example above.

I’m actually quite relived, as I was wondering how we’d do the shared items Rss feed. These actions would, arguably, be highly trafficked and reading directly from the blobs (which was my original plan) would be too bandwidth intensive. Problem solved.

I’m very excited about MVC 3 as a whole, but when i see the direct application of features, I get even more excited.

In fact, when Razor first came out, I really was going to use it for the Feedreader instead.