Wednesday, 9 September 2009

Preventing Page Navigation While an AJAX Queue is Working

AJAX is quick. As internet technologies go, it's as fast a server call as you're likely to make. This having been said, it's not instantaneous. While the callback is occurring there is plenty of time for your users to do stuff you'd rather they didn't, such as navigating away from the page or closing the browser altogether. If you've implemented a good, scalable AJAX solution for your custom calls and built a queuing object, then there might even be server calls which haven't been initiated by the time the user decides to move onto the next screen in your application.

There is a solution to this problem. The following method takes care of processing links while making sure that an AJAX queue has finished running.

function doNav(path)
{
    if(ajaxQueue.running)
    {
        setTimeout('doNav(path)', 50);
    }
    else window.location = path;
}

This method assumes that the queue object is called ajaxQueue and this has a boolean property named 'running'. The reason we call setTimeout is because JavaScript isn't threaded in the same way as some server side languages. If you don't call setTimeout and instead call doNav with direct recursion, the script engine will enter an infinite loop as the thread will never allow the queue processing time to complete its task. The call to setTimeout here will cause the thread to let other things to get on with their job for 50 milliseconds and then, once the script engine completes the task it is currently running (setTimeout doesn't exactly time the process by 50 ms, it does guarantee a minimum of 50 ms however) doNav will be fired again.

Directing all page navigation in your AJAX application through a method like doNav will help make your application more robust and reliable.



Tuesday, 26 May 2009

Copying Hierarchical Data with Transient Links

This problem came up in a current project. Initially the problem appears quite straight forward but it’s actually quite tricky. Let’s start by explaining what I mean by transient links in hierarchical data.

In the original project, I was working with a hierarchy of 5 levels but I think we can simplify that a little and work with just 3. For argument’s sake lets use ‘Document, ‘Section’ and ‘Paragraph’ as the three levels. Although blatantly contrived, this structure could possibly be used in a system managing changes to documents.

Figure 1
Figure 1

Figure 1 shows a very simple data structure for this situation. Documents are made up of Sections which are made up of Paragraphs. In this system any of our three entities can be copied by creating a new record with the LInkedToID field referencing the Primary Key for the original record. If a Section record is copied, then new Paragraph records are also generated which are copies of the original Section’s Paragraphs. Similarly, if a Document record is copied then its Sections and Paragraphs are also copied.

The first sign of this getting tricky is encountered when we add in the next requirement: when a Section record is copied, the new Paragraph records shouldn’t all link back to where they were copied from – the new records should generate a copy of the same structure of copied Paragraphs which were in the original Section. The root record for the new structure of Paragraphs should reference the original root Paragraph record. Figure 2 contains some XML formatted data showing how the Paragraph records of a parent Section and it’s copy would relate to each other.

Figure 2.
<Paragraph>
    <ParagraphID>1</ParagraphID>
    <SectionID>1</SectionID>
    <LinkedToID>null</LinkedToID>
    <Text>This is the text for paragraph 1</Text>
</Paragraph>
<Paragraph>
    <ParagraphID>2</ParagraphID>
    <SectionID>1</SectionID>
    <LinkedToID>1</LinkedToID>
    <Text>This is text for paragraph 1 which has been re-versioned.</Text>
</Paragraph>
<Paragraph>
    <ParagraphID>3</ParagraphID>
    <SectionID>1</SectionID>
    <LinkedToID>2</LinkedToID>
    <Text>This is the text for paragraph 1 which has been re-versioned a second time.</Text>
</Paragraph>
<Paragraph>
    <ParagraphID>4</ParagraphID>
    <SectionID>2</SectionID>
    <LinkedToID>1</LInkedToID>
    <Text>This is the text for paragraph 1 in the copied section.</Text>
</Paragraph>
<Paragraph>
    <ParagraphID>5</ParagraphID>
    <SectionID>2</SectionID>
    <LinkedToID>4</LinkedToID>
    <Text>This is the first revision of the paragraph in the copied section.</Text>
</Paragraph>
<Paragraph>
    <ParagraphID>6</ParagraphID>
    <SectionID>2</SectionID>
    <LinkedToID>5</LinkedToID>
    <Text>This is the second revision of the paragraph in the copied section.</Text>
</Paragraph>

In the Figure 2 scenario, Section 1 is made up of a single Paragraph which has been revised twice. Section 2 is a revision of Section 1, so the root Paragraph references the root Paragraph of Section 1 while the other Paragraphs of Section 2 link back to Section 2’s root Paragraph.

The requirement is for this pattern to apply for all levels. So if a Document is copied then the Sections will be copied maintaining the references. Likewise, each Section copied to the new Document would also have their Paragraphs generated with the same linked structure of their parent Paragraphs in the original Document.

Now we have some understanding of what I mean by transient links in hierarchical data. Copying data in this way might seem quite simple. In fact initially I thought it was a no brainer and wrote a method similar to the one in Figure 3.

Figure 3.
public void CopyDocument(Document doc)
{
    var newDoc = new Document
        {
            Name = String.Concat(“Copy of “, doc.Name),
            LinkedToID = doc.DocumentID
        };
    dataContext.Document.InsertOnSubmit(newDoc);
    dataContext.SubmitChanges();

    var sections = dataContext.Section.Where(s=>s.DocumentID==doc.DocumentID);

    foreach(var section in sections)
    {
        var newSection = new Section
            {
                DocumentID = newDoc.DocumentID,
                LinkedToID = section.SectionID,
                Text = section.Text
            } ;
        dataContext.Section.InsertOnSubmit(newSection);
        dataContext.SubmitChanges();

        var paragraphs = dataContext.Paragraph.Where(p=>p.SectionID==section.SectionID);

        foreach(var paragraph in paragraphs)
        {
            var newParagraph = new Paragraph
                {
                    SectionID = newSection.SectionID,
                    LinkedToID = paragraph.ParagraphID,
                    Text = paragraph.Text
                };
            dataContext.Paragraph.InsertOnSubmit(newParagraph);
            dataContext.SubmitChanges();
        }
    }
}

At first glance this might look like it could do the job but in fact this would link each new record back to the record it was copied from rather than maintaining the original structure.

So how is it done?

The example in Figure 2 is pretty simple. For that situation, the LinkedToID could be followed back to the root Paragraph record and then the children created one at a time pointing to the new root record and the first child respectively. Unfortunately this is a hugely oversimplified example. In actuality the root record may have already been copied into several other Section records already, and have other children which are linked via the LinkedToID but shouldn’t be copied in this process. What’s more, we may not always be copying a root node!

To accomplish the task, we need to introduce two new fields into each entity: ProcessID and CopiedFromID (I would normally use ProcessGuid instead of ProcessID but typing out a guid in a blog is tedious so an integer field will suffice here). Figure 4 contains C# code to accomplish this.

Figure 4.
public void CopyDocument(Document doc)
{
    // GetNewProcessID() is a method which returns an
    // integer which hasn’t been used as a ProcessID yet.
    var processID = GetNewProcessID();

    var thisDoc = document;
    CopyDocumentMaintainingLinks(thisDoc, processID);

    var originalSections = dataContext.Section.Where(s=>
        s.DocumentID==doc.DocumentID);
    foreach(var section in originalSections)
    {
        var thisSection = section;
        CopySectionMaintainingLinks(thisSection, 
            thisSection.SectionID, processID);

        var originalParagraphs = dataContext.Paragraph
            .Where(p=>p.SectionID==thisSection.SectionID);

        foreach(var paragraph in originalParagraphs)
        {
            var thisParagraph = paragraph;
            CopyParagraphMaintainingLinks(thisParagraph,
                thisParagraph.ParagraphID, processID);
        }
    }
}

public void CopyDocumentMaintainingLinks(Document doc,
    int linkedToID, int processID)
{
    var newDoc = new Document
        {
            Name = String.Concat(“Copy of “, doc.Name),
            LinkedToID = linkedToID,
            CopiedFromID = doc.DocumentID,
            ProcessID = processID
        };

    dataContext.Document.InsertOnSubmit(newDoc);
    dataContext.SubmitChanges();

    var linkedDocuments = dataContext.Document
        .Where(d=>d.LinkedToID == doc.DocumentID);
    foreach(var document in linkedDocuments)
    {
        var thisDoc = document;
        CopyDocumentMaintainingLinks(thisDoc,
            newDoc.DocumentID, processID);
    }
}

public void CopySectionMaintainingLinks(Section section, 
    int linkedToID, int processID)

    var newParentDocument = dataContext.Document
        .SingleOrDefault(d=>
        d.CopiedFromID == section.DocumentID &&
        d.ProcessID == processID);

    var newSection = new Section
        {
            LinkedToID = linkedToID,
            CopiedFromID = section.SectionID,
            Text = section.Text,
            DocumentID = newParentDocument.DocumentID,
            ProcessID = processID 
        };
    dataContext.Section.InsertOnSubmit(newSection);
    dataContext.SubmitChanges();

    var linkedSections = dataContext.Section.Where(s=>
        s.LinkedToID==section.SectionID
        && s.DocumentID==section.DocumentID);
   
    foreach(var section in linkedSections)
    {
        var thisSection = section;
        CopySectionMaintainingLinks(thisSection, 
            newSection.SectionID, processID);
    }
}

public void CopyParagraphMaintainingLinks(
Paragraph paragraph, int linkedToID, int processID)
{
    var newParentSection = dataContext.Section
        .SingleOrDefault(s=>
        s.CopiedFromID == paragraph.SectionID &&
        s.ProcessID == processID);

    var newParagraph = new Paragraph
        {
            SectionID = newParentSection.SectionID,
            LinkedToID = linkedToID,
            Text = paragraph.Text,
            CopiedFromID = paragraph.ParagraphID,
            ProcessID = processID
        };
    dataContext.Paragraph.InsertOnSubmit(newParagraph);
    dataContext.SubmitChanges();

    var linkedParagraphs = dataContext.Paragraph
        .Where(p=>p.LinkedToID == paragraph.ParagraphID &&
        p.SectionID == paragraph.SectionID);

    foreach(var para in linkedParagraphs)
    {
        var thisParagraph = para;
        CopyParagraphMaintainingLinks(thisParagraph,
            newParagraph.ParagraphID, processID);
    }
}

The method CopyDocument is pretty straight forward, the fun bits are in the other three methods. Because the target parent object isn’t necessarily known, we have to find it using the CopiedFromID and the ProcessID fields we added earlier. In this way there are two types of transient relationships defined: linked records and copied records. Of course, a record might be copied dozens of times which means the ProcessID field is needed to restrict the scope of the query to just this copy process.

Another possible pit fall is when selecting the linked items. Because of the way things are copied, we’re only interesting in copying Sections which are in the source Document and for each individual Section we don’t need to copy linked Paragraphs from outside that Section. So we can constrain the query as so.

It’s worth  noting that this technique will continue to work no matter how many levels of data exist. Originally I was using 5 levels but there are certainly applications for this technique using more than this. It’s also worth noting that although I’ve written these methods out ‘long hand’ if you like, it would be possible to write a single method to handle all data levels as long as the classes implemented an interface defining the ID, LinkedToID, CopiedFromID and ProcessID fields. This slightly more complex recursive method would need to use reflection to determine what level of data was being copied in any given iteration in order to create the new record.

That’s pretty much all I have to say on this subject. I thought it was an interesting problem which I couldn’t find a solution for elsewhere on the web (although I’m sure they’re out there).

NB: I didn’t copy the code directly from my project so don’t expect it to work perfectly after a copy and paste.

Tuesday, 12 May 2009

New Website

Finally my website is available!

If you’re looking for a company software development services you might want to consider contacting me. All details are on my site: www.e-netservices.co.uk.

Friday, 13 March 2009

AJAX DIY

It’s been a long time between blogs and a very busy start to the year for me. One of my clients has some pretty hefty requirements for a web based, SQL Server backed, SharePoint integrated production system to be accessible world wide via their less than super fast WAN. I’ve been kept very busy and I’m yet to hit the really tricky bits.

Whilst designing and building this system, I’ve found myself writing a lot of bespoke AJAX. I’m used to working on a fast company LAN so I’ve always talked about AJAX as being an efficient use of bandwidth. I now had my eyes opened to just how badly conceived some AJAX frameworks actually are. For example, Microsoft’s AJAX control toolkit offers a wide range of easy to use components but partial page renderings often end up costing as much (if not more) in bandwidth as a full page refresh! This is something which I was only vaguely aware of until I tried running my AJAX pages from an office in Shenzhen!

It quickly became obvious that Microsoft’s AJAX tools weren’t up the job at hand so I had a look at what else was out there. There are some excellent toolkits available, Telerik's RAD Controls are undoubtedly one of the best with some very flashy looking elements and some very good reviews (from people I know as well as on their site). But though they are more efficient than the Microsoft tools, I would still have had to work extensively to craft the feature rich GUI which my client was looking for. In my mind it seems silly to pay for something which ultimately isn’t going to save time or increase the value of the build. Also, even the Telerik controls had performance problems in the environment in question.

This was when I started thinking back many years to a time before .NET, when possibly the most powerful tool in a web developer’s arsenal was their knowledge of JavaScript. I spent quite a few years making the DOM dance to my tune long before I discovered asp.NET and server controls. There are so many AJAX ‘helper’ kits out there that it’s easy to forget how straight forward an AJAX call is to make. In fact, over the last few months I’ve realised that much of what is provided by these tools is pretty straight forward to code yourself.

My message to any developer is this:

Don’t automatically think that because something is available for download and looks flashy that it will make your application better / quicker / smarter. Just because something is for sale doesn’t make it any better than what you could build yourself. Think about what your client REALLY needs and how much work it would take both with or without 3rd party kit. You might just find that you’re quite capable of going it alone!

Thursday, 4 December 2008

From HTTP End Points to Linq

Http end points in SQL Server have been promoted since SQL Server 2005 but with SQL Server 2008 they're on the way out.

Initially, I thought this to be a bit of a shame. I hadn't got round to making propper use of this facility although it always seemed pretty cool. Allowing your stored procedures to be published as a web service without having to do any coding seems very attractive, so why have Microsoft decided to get rid?

One possibility could be the emergence of .NET 3.5 and specifically Linq.

I come from a SQL development background and I've always thoroughly believed that all data manipulation should be carried out in the SQL Server, so I'm used to using stored procedures for just about all interactions between my applications and the data. However, in my most recent role I'm under huge time constraints and I'm being asked to produce a hugely complex system which can be handed over to an in-house junior developer after I'm done. It's because of this I wanted to reduce the number of skills needed to maintain the system.

Now I'm not saying that Linq is going to mean the new developer won't need to work with SQL Server but while he's still inexperienced with SQL, he doesn't have to write much. Instead he can work in C# which he's much more familiar with.

I have to admit that initially I was dubious with Linq. I don't believe that the translation of managed code to SQL is as efficient as writing a stored procedure would be, especially the first few times you use Linq. Having said this, I'm really very pleased with the results. The SQL being produced by Linq is not what I would have written manually, but unless it was to be executed over and over a few thousand times the difference isn't really noticable. It's worth noting that the system I'm building is a line of business application come time management come document management system - a user's path through any task rarely hits the database very hard. So maybe I shouldn't be surprised that the performance seems adequate.

Does this mean we seeing the technology of publishing SQL code to a web service without having to write the web service getting replaced with writing a web service which interacts with SQL Server without having to write any SQL code?

Some obvious benefits of this method over the usual interaction with stored procedures would be:
  1. It's in managed code - it isn't everyone who is as at home writing SQL as they are managed code.
  2. Exception handling - no half way house, exception handling with Linq to SQL is exactly the same as with anything else written in managed code.
  3. No need to write copious amounts of code passing SQL values to managed objects.

There are probably more, but these three tend to get banded around the most.

As I am so insistant on efficiency of code, I found the lack of solid examples of how to make more complex queries efficient quite frustrating. In fact, the life of the DataContext itself is a huge issue, especially when building a web application with the possibility of many concurrent users. This is why I've decided to write about my own experience in the hope it will help someone else in a similar situation.

I'll begin in my next entry: Linq to SQL for Web Applications.