Skip Navigation Links / Posts / Posts By Category
Search site. 
Powered by Google
Darren Neimke (Me)

My Book

Readify

">ASP.NET MVP


Interesting Portals 

NetVibes
This portal feels similar to PageFlakes in many ways but I love their gallery. They also have a feature whre certain chrome elements only become visible when you hover over the web part.

Xtra
A New Zealand news portal. I especially liked the content rotator web part at the top of the middle row. Seems like a nice way to allow a user to browse through data.

 

Posts Archive 

Posts for Category: Web

Feed for this Category
Live Applications

This week I installed the new Live desktop applications and have been using them on my 3 Vista computers.  I'm liking some of the integration that you get between these.  For example, yesterday we went across to the local park to fly kites and, I had my phone on me so I took some photos:

 

When I got back home, I plugged my phone into my TabletPC and imported the photos from my phone straight into the new Windows Live Photo Gallery.  From there I used the new "stitch" feature to create the following landscape photo from 3 of the photos:

 

The I used the 'Publish' option within Windows Live Photo Gallery to publish those photos directly to my Live Space:

http://showusyourcode.spaces.live.com/default.aspx

Now I'm using Windows Live Writer - another of the new Live applications - to blog about it.  It would be nice if Windows Live Writer was slightly more integrated with Live so that the 'Insert Picture' module could be configured to pull pictures straight from my Live Space without me having to get the URL's from the Spaces web site.

It's taken a while, but Live's 'Software + Services' stuff is finally starting to take shape.

posted on 9/9/2007 9:31:53 AM ( 0 Comments )


Microsoft SkyDrive blog - how NOT to have a conversation in the blogsphere

I'm constantly amazed when I see the new product teams in Redmond getting started with their brand new shiny blogs.  They invariably write an excited post - like this one - telling the world about their new product and how excited they are to be able to have a blog so that they can have a conversation with the punters about it.  Hot on the heels of this magical first post by a new product team, other influential bloggers from Redmond start pimping it from their blogs saying how cool it is to see product X being blogged about.  I've seen this on a number of occasions now, the BizTalk services in the cloud blog was probably the most recent example. 

After the initial excitement of getting their first blog post out of the way, these teams then seem to get writers block or something because quite often it's the last post of any substance that we see. 

This post by the SkyDrive team really bothers me because it's their initial post and people have followed up by posting 80 comments (mostly "when will this be available in my region") and not a single reply from the team.   That just sucks, but is in line with the other stellar communication efforts that I've seen from teams working underneath the Live brand.

posted on 8/14/2007 9:28:35 AM ( 3 Comments )


What Google Gears really is.

A couple of months ago I opened Google Reader and was presented with a message from the web site that there was now an option of working with my reader while offline.  To do this I was required to download a small, client-side program called Google Gears.  The idea sounded cool enough so I installed the program pretty much straight away.  In the following 5 or 6 weeks that I had "Gears" installed, I discovered that browsing the web in offline mode is obviously not a scenario that I'm all that interested in, because I think that I tried it once - and it didn't work because opening the web page in either offline or online mode while I was disconnected gave me errors.  So I uninstalled it without ever having enjoyed that experience that I was expecting.

Having thought about it some more I don't really think that we'll ever really work with web pages while in disconnected mode.  Instead, we'll use smart client applications that allow us to achieve certain goals while disconnected such as some of the applications that we are seeing underneath the Live brand such as Live Writer and Live Mail.

It's worth dissecting Google Gears though because if it's just something that allows you to browse the web in disconnected mode, and I don't believe that that is such a key scenario, then either I'm wrong or Google is - and quite frankly, I don't believe that I'm that smart. Nerd

Google Gears is essentially 3 things:

  1. A client-side persistence store for storing large amounts of data.
  2. A technology that enables an offline browsing experience in the browser.
  3. Enables the scenario of querying data in the client using SQL syntax.

I've already discounted point #2 as not that important, so let's focus on points #1 and #3.

Storing larger amounts of data on the client

This is a key scenario as we look to create richer web experiences for our end users.  Here's a couple of scenario's where having a larger client-side cache of data is very important.

Saving draft copies of documents

Whether they are personal articles such as blog articles and emails, or business documents, we are all using the the web to create and update documents a lot more these days.  And if you've ever had the experience that I have, where you've just finished writing a large document in the browser only to have it crash on you, then you will understand exactly how important it is, to be able to save draft copies of documents as you are working with them.  To do this now would require saving the data on a server somewhere, thus making it impossible to continue working with the document when you go offline.  With a client-side cache, you could start writing a document in the browser while online and then continue later in offline mode by accessing the document via a smart client application.  Either way, having a draft copy would mean that the experience of losing data could be a thing of the past.

Providing a better application experience

While at Tech.Ed last week, I had the pleasure of attending Dan Green's presentation on UX.  It was a very stimulatory (yep, a made up word Smile) and during it he gave the example of how the Visual Studio intellisense engine remembers our previous choices - and therefore when we repeatedly re-access certain members, they are already pre-selected for us.  Consider when you do lots of Console.WriteLine's in a row just how easy it is to simply accept the defaults that are thrown up at you by Intellisense, without having to constantly scan a list from the top each time. 

In the same way it would be nice to provide a richer experience to users of web applications by storing more defaults and settings in the client.  With the size limitations of cookie's, storing a large cache of preference settings in the past has been unreliable or impossible - and so having a client-side database would alleviate these types of issues and would allow us to provide much richer client experiences, similar to that of the Intellisense scenario.

Querying data in the client using SQL syntax 

For certain types of applications - such as mail - having the ability to query data in the client is an important optimization.  I imagine that Google came up with this idea through features that they had to provide with their GMail application.  For an application that works in the browser - such as GMail - it would be quite costly to send such large amounts of data back and forth between the server and the browser whenever you wanted to work with it.  However pushing the logic down into the client would increase the client-side complexity for certain operations like sorting and finding data.  For these types of scenarios, having the ability to work with data via SQL statements in the client is highly desirable.

Silverlight

In Silverlight 1.1 we will have the ability to write managed code which runs on the client, and as a part of this we will initially have access to an IsolatedStorage implementation.  This will solve the first problem of having a larger client-side cache of data.  I'm not sure about Linq and Silverlight but if we were to get Linq capabilities in Silverlight then many of the features that Google Gears delivers will actually be present within Silverlight itself.

posted on 8/12/2007 9:29:54 PM ( 0 Comments )


Google, you've done it again!

In the past week Google has announced Google Gears, an offline data storage solution for web applications.  This has been implemented by Google Reader so I can now take my blog reading offline to read offline:

Google Gears

In addition to adding offline reading support for Google Reader, Google have added cool new themes to their portal.  Here you can see that I've added the theme called "Seasonal Scape".  During the daytime the little critters can be seen at play...

Google Gears

 

But at nighttime things are much quieter... smile_regular

Google Gears

posted on 6/4/2007 7:22:24 PM ( 1 Comments )


SharePoint -> Popfly -> SharePoint

Here's an interesting article whcih talks about using SharePoint as a data source for Popfly blocks and then hosting Popfly mashups within SharePoint itself:

Link to Microsoft SharePoint Products and Technologies Team Blog : SharePoint and Popfly integration -- yes, really!

Pretty cool.  Getting Popfly mashups "out there" is a significant step forward.

posted on 5/28/2007 10:41:05 AM ( 0 Comments )


Now using Popfly

Yesterday I received my invite to start using the Popfly beta.  I wrote a little bit about Popfly the other day and explained the high level concepts behind it.  Having now created my first mashup I must say that I'm very impressed by the simplicity.  Within 30 minutes of logging in I had created a simple mashup which took data from a Flickr 'block' and displayed it using a Carousel 'block' to display a carousel of images of Readify from Flickr.  You can view a video of my first simple mashup here:

Simple Mashup 

Conceptually there's 3 main types of blocks that you can create:

  1. Data providers - the Flickr block is an example of this type of block.  Basically, the Flickr block connects to the Flickr web services to return data from them.
  2. UI Presentation - the Carousel is an example of this, so is the Page Turner.  In the case of the Carousel, it accepts data from a data provider and renders the pictures from that data in a carousel.  Likewise, the Page Turner takes links to URL's and displays them in a Silverlight "book" that allows you to flip through the pages to view images.
  3. Functions - yep, you can write blocks which take input and transform it into something else.  The RegExp block is an example of this.  With the RegExp block you provide the input, define an expression and choose a method that is exposed by the block.  The most interesting method that it exposes is getMatches.  One way to use getMatches might be to find a block which returns a string and then create a regex which scrapes that string to return all image URL's and then pipe the matches of that to a Carousel block.

I've also created a few blocks now and that is also very simple.  All you have to do is to create a bunch of Javascript which "does stuff" and then describe the metadata of your javascript via an XML manifest file.

Overall, Popfly looks like an interesting platform for creating high level functions and running them from the cloud.

posted on 5/27/2007 3:14:06 PM ( 0 Comments )


Successful CrowdSourcing applications will require Reputation

Today I was thinking about virtual marketplace applications that provide services to customers by farming out requests to helpers.  This concept is known as CrowdSourcing and some examples might include things like Google Answers and Amazon's Mechanical Turk.  I expect the opportunities that exist for this style of application will grow in parallel with the growth of mash-up style applications on the web.  The rise of mash-ups and the success of folksonomy-style activites such as tagging have created an environment where CrowdSourcing is growing as a business model.

One of the barriers that I see to the growth of this new business model is working out how to provide service level agreements (SLA's) for activities that are outsourced to groups of participants over the internet.  I mean how do you start a business that relies on a crowd to be able to run - it's a bit of a chicken and egg problem in that until you have some inertia you may not be able to attract sufficient resources and you may not generate enough resources until you have a high enough profile.

So having an SLA which states that you can provide X within Y minutes or hours may be difficult.

Another barrier to the success of CrowdSourcing as a viable business model could be Reputation.  I mean would you pay big bucks for a Ferrari if you knew that it may have been assembled and designed by rank amateurs?  No, of course you wouldn't.  The quality of an item is usually linked to its reputation in some way... and so it will be with knowledge that is served up by the crowd.

So it's probably timely that, in my thinking about these types of problems that there's currently a bit of a blogging discussion going on Microsoft's next community reputation initiative: Claimspace.  Here's the thread as I've seen it so far:

Korby describes Claimspace

Ted Haeger asks whether we can trust Microsoft

Korby's reply to Ted's post

Reputation and Federated Reputation could certainly have a very significant role to play in the future, collaborative web, so conversations such as these fascinate me.

 

NOTE: I just realized that Korby linked to ProjectDistributor in his article about Claimspace... cool! smile_shades

posted on 5/24/2007 5:01:30 PM ( 1 Comments )


Popfly

I’ve been looking at Popfly this week and it started a whole lot of searching and reading.  If you haven't seen Popfly yet I'd highly recommend that you head off and watch this video now and then come back:

http://msdn.microsoft.com/vstudio/media/en/popfly/PopFlyin15.wvx

Popfly is a tool for building mash-up style applications.  With this application you create Blocks that connect data and visualize it somehow.  Sample scenario:

Connect a VirtualEarth Block to a Twitter Block and produce a mash-up map showing where on the planet conversations are taking place in real time.

The concept is extremely cool and I've already applied to use the system in its infancy.  Popfly will empower a whole new breed of people to build and deploy mashups on their blogs and community sites - so it's really needed.

posted on 5/24/2007 4:31:33 PM ( 0 Comments )


Expression and Silverlight videos

There appears to be a lot of awesome video content washing around today in line with the kick-off of MIX07. 

Microsoft Expression Knowledge Center Videos

Dozens of Sliverlight videos from the Silverlight site

A bunch of Silverlight screencasts from Tim Sneath's team

posted on 5/1/2007 9:14:49 AM ( 0 Comments )


ASP.NET AJAX under the hood secrets

Nice article about how the PageFlakes guys got their Ajax implementation up and running:

Link to ASP.NET AJAX under the hood secrets - The Code Project - AJAX / Atlas

posted on 2/16/2007 7:57:15 PM ( 0 Comments )


RegexHelper - a javascript wrapper for regex usage

Now that I've started to do a lot more work with javascript again - to create Vista Sidebar Gadgets - I need to revert to some of my old helper libraries of useful functions.  One that will probably be very useful is this one that I wrote to assist me when working  with javascript regexen:

Link to ShowUsYour : RegexHelper - a javascript wrapper for regex usage

Here's an example of how you would use that code to help enumerate the headings on the home page of the Dilbert blog and displays them in a list in my Gadget:

window.onload = function() {
    try {
        var url = "http://dilbertblog.typepad.com/" ;
        var titlePattern = "<h3 class=\"entry-header\">(([^<]|.)+?)</h3>" ;
        var scraper = new WebScraper() ;
        var pageString = scraper.Scrape(url) ;
        var matches = new RegexHelper().Matches( pageString, titlePattern ) ;

        for( i=0; i<matches.length; i++ ) {
            var match = matches[i] ;
            var text = document.createTextNode(match.Groups[0]);
            var e = document.createElement("li");
            e.appendChild(text);
            myList.appendChild(e);
         }
    } catch ( ex ) {
        alert( ex.message ) ;
    }
}

That function also uses the WebScraper class that I've been using to grab web pages from within my Gadgets:

 

/////////////////////////////////////////////////////////////////////////////
//
// WEBSCRAPER MODULE
// Author: Darren Neimke
//
/////////////////////////////////////////////////////////////////////////////

// WebScraper Class
function WebScraper() {
    var xmlHttp = null;
   
    this.Scrape = function( url ) {
        var html = "" ;
        initializeProxy() ;
       
        try {
            if (xmlHttp != null) {
                xmlHttp.open("GET", url) ;
                xmlHttp.send(null) ;
                html = xmlHttp.responseText;
            }
        } catch(ex) {
            throw new ErrorObject( ex.message ) ;
        }
    return html ;
}


function initializeProxy() {
    xmlHttp = null ;
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest()
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
}
}

posted on 12/30/2006 9:41:01 AM ( 1 Comments )


Getting started with developing WPF/E applications

Some links to good resources for getting started with WPF/E:

Link to David Boschmans Weblog : Getting started with developing WPF/E applications

posted on 12/18/2006 9:34:34 PM ( 0 Comments )


Friendly Url's, Provisioned Pages

I was sitting at Docklands tonight having dinner with Aymeric and talking about our respective web engines - mine: SingleUserBlog and his: AymericWeb smile_regular 

We each had things that we liked about the others' engine.  Aymeric liked the web parts of SUB and I really liked two of the features that he had: Friendly Url's and the ability to provision new pages (ala Wiki's). 

I'm really hoping that I'll get some time later this week to pull down the latest code for SUB from CodePlex and start to think about how these things might get added into the core SUB codebase.  Before I integrate any code changes into the SUB codebase I'll prototype how these changes might fit in.  Basically I see SUB as now having a number of page types (which BlogML supports smile_wink) such as:

  • BlogPost
  • Article
  • Wiki

I think that each page type would derive from a different page template and would be provisioned in a different manner.  For example, to create a new blog entry you would go into the Administration section and choose "New Post" from the menu.  Doing that would:

  • Instance a page from the BlogPost Template
  • Save the content of the page into the Posts data path
  • Save one post file per page

To create a new Wiki page you would embed a special syntax into the content of any page - something like what Aymeric used:

[[pageid|pagedisplayname]]

So, for example, if I wanted to create a Wiki entry for Regex, I could embed the meta tag like so:

[[regex|Regular Expressions]]

In addition to having these Wiki pages provisioned on the fly, they would also:

  • Use a friendly URL format
  • Save historical versions

This means that each version would get saved as a different content file in the Wiki data path - i.e.: Regex, Regex(1), Regex(2), Regex(3), etc.  The reason for saving all historical versions of the Wiki entry is so that you can track the evolution of the thought/idea.

The friendly URL format would probably look something like this:

http://MarkitUp.com/Wiki/Regex.aspx

On the topic of friendly URL's, Aymeric shared this great link with me which discusses some of the benefits of having nice, neat URL's:

http://www.edition3.com/articles/friendly-urls

posted on 10/30/2006 10:55:59 PM ( 2 Comments )


Google Reader update

This week Google Reader was given a new look with a significant update, you can read about it here.

Google Reader interface

This update has addressed many of the usability issues which had previously existed and makes it much simpler to manage feeds and tags, view categories of feeds (now displayed in a tree), and to read.

Well done Mr Google! 

posted on 9/30/2006 9:16:49 AM ( 0 Comments )


MySpace - is it Web 2.0 or Spam 2.0?

Most people have probably seen this article which was posted on ValleyWag a couple of weeks ago, but I thought that I'd post a link to it here for posterity:

    http://valleywag.com/tech/myspace/myspace-the-business-of-spam-20-exhaustive-edition-199924.php

If you haven't read Trent Lapinski's article, head over and check it out.  It's a good read :-)  I'd especially recommend following the links to help think about the research that went into creating that article.  This is what this morning's AFR had to say about Trent:

Trent Lapinski, a 20-year-old blogger and journalism student, has been investigating the social-networking site MySpace since July 2005, when News Corporation bought it...

posted on 9/19/2006 3:51:53 PM ( 0 Comments )


OzGadgets.com.au - New Aussie Gadget Community

As I mentioned in my last post, I've started a new website that I hope may form the beginnings of an Aussie Gadget Community.  The site is hosted at http://OzGadgets.com.au and the plan is to be an aggregator of information about Australian gadgets and also to post some tutorials about creating gadgets while I'm at it.

So far the only Aussie gadget that I know about is my AFL Ladder gadget, so if you know of others, please let me know about them so that I can feature them on the OzGadgets blog.  Likewise, if you have requests for Aussie Gadgets that you'd like to see, then please let me know about those too so that I can add them to the site.

I hope to post a few tutorials up on the site over the next week or so about creating and deploying gadgets.  Over time, the tutorials will include scripts for doing common tasks - such as displaying grids of data, or providing a customization interface for your gadget.

Please let me know if you'd like to get involved with the site - maybe we can make http://OzGadgets.com.au the first multi-user instance of SingleUserBlog :-)

posted on 9/17/2006 8:02:44 PM ( 3 Comments )


AFL Ladder Gadget Data

In a comment to a recent post, Matt asks where I'm grabbing the data for the AFL Gadget from.  It's all a dirty trick though, because, as I told Matt in my reply, so far I've just created a static XML file and am hosting it from this site:

    http://www.markitup.com/data/aflladder.xml

My plan is to actually remove that file at some stage and replace it with a web service that other people can access via a subscriber identifier - not that I'm thinking of charging for it, I just want to be able to track who's using it.

I'll probably move the web service over to my new domain:

    http://OzGadgets.com.au

Where I envisage hosting a number of data services for "Aussie" sports data. 

More about http://OzGadgets.com.au to follow :-)

posted on 9/17/2006 7:55:10 PM ( 0 Comments )


AFL Ladder Gadget

I was having lunch with Omar, Dan, and Paul on Monday and I mentioned that I'm planning to create a few Live Gadgets that are based on Australian regional information.  As a sample, I've uploaded the most dirt simple gadget that I could think of - the AFL premiership ladder:

AFL Ladder Gadget

You can add the Gadget to your Live.com page by adding the following manifest link:

    http://www.markitup.com/Gadgets/AFLLadderGadget/AFLLadderGadget.xml

Or, by simply clicking on this image :)

posted on 9/13/2006 10:23:27 PM ( 4 Comments )


Better the Devil you know

This week I changed my Live.com communication preferences in the hope that I might be able to keep control over my Space and better manage the flow of Friends into it:

Live.com Communication Preference Settings

The rationale behind this change is that I'm much more familiar at dealing with Friend pollition :) in Instant Messenger (now Live Messenger) than I am at dealing with it in my Space.  By allowing anybody to invite me to Messenger, I can deal with Friend requests in the same way that I have done for the past 5 years.  Once on my Messenger list, people can then request to be added to my Friends list on Live.

Finally, I've removed a lot of the "Friends of Friends" stuff.  Not that I think that it's a necessarily bad thing but it definitely increases the "attack surface".

posted on 9/9/2006 8:59:17 AM ( 0 Comments )


The mashup story just got a whole lot clearer

For a while now I've sat and watched as a range of the Live.com team have struggled to explain Live and what it really is all about.  Sure I've seen Ajax in action and have been thrown a bunch of buzzwords but the real story has never really been revealed.  In fact, in desperation I actually made a bit of an idiot of myself at a meeting where I stood up and said, quite bluntly... "I don't get it!".  And I didn't.  And the guy giving the talk couldn't bridge that gap.

Yesterday some of that changed when I watched this awesome Channel 9 video with Danny Thorpe:

    http://channel9.msdn.com/ShowPost.aspx?PostID=232926

In this awesome video, Danny shows some new techniques that they have for allowing our own apps to host gadgets.  I'll say that again... this video shows how we could host gadgets in our own applications. 

In the video, Danny shows the Windows Live Contacts Gadget hosted within a web page and showing the technique that they are looking at for allowing gadgets to share their data with the hosting page - sharing data across domains!  To get your mind spinning, just consider that the Live contact database that sits behind this gadget is home to between 12 and 14 billion records.

For me this - and more of the monetization story - had previously been significant missing parts in the Live story and now it's all getting good for me.

posted on 9/8/2006 11:01:01 AM ( 0 Comments )


Getting ready for Tech.Ed

In getting ready for Tech.Ed I started having a bit of a play with the main technologies in the sessions that I'm going to attend - which are: Architecture, LINQ, Atlas, and performance/testing.

To kick things off I re-installed the latest Atlas, Linq, and Blinq bits and started building a little website to try things out.  Most of today was spent re-learning Linq and taking my first look at Blinq.  The first thing that I did was to fire up Blinq and point it at my test database like so:

> Blinq /t:c:\Projects\PD1 /database:projectdistributor /server:. /sprocs

Blinq is a command-line application which calls through to SqlMetal to produce a database context and then creates a website with pre-generated pages for every crud scenario using a series of DetailsViews and GridViews.  Some highlights from the output of a Blinq web app are that they:

    - generate a file called StaticMethods.cs which has static methods over all of the SqlMetal stuff
    - use CssAdaptors for nice menus

As for the rest of the website that gets produced, I'd say that its intent is to show "DLINQ in Action" from a web application perspective.

During the day I was reminded of how totally cool Linq is.  Here is an example of calling a business proc in my ProjectDistributor app:

Projectdistributor db = Projectdistributor.CreateDataContext() ;
int newID = db.AddUserToApplicationRole(1, 1) ;

Both the Projectdistributor class here and the AddUserToApplicationRole method were generated by SqlMetal. 

I think that when we get to using Linq in real world applications that we may use procs for some business level operations - such as above - but that most of the time we'll just code directly off of the SqlMetal produced proxies.  For example, using nothing but the generated proxies I could page through the records in my Users table like so:

    gvw.DataSource = db.Users.Seek(100).Take(25);

This would grab the 100th - 124th records from the Users table and bind them to a GridView.  If the Users table was quite "wide" I could also improve the efficiency by binding to a projection from that table instead:

 
    gvw.DataSource = from user in db.Users
                       orderby user.UserName
                       select new {
                           UserID = user.ID,
                           FirstName = user.FirstName,
                           City = user.City,
                           IsPublic = user.IsPublic
                       };

This would produce SQL under the hood which only requested the 4 columns from the User table.  ScottGu has a great post here which shows how simple it can be to display data on a web page using Linq.

posted on 8/20/2006 9:05:33 PM ( 1 Comments )


Using Rhino Mocks to test objects

Yesterday Phil Haack posted up this nice post about how to code the MVP pattern in a web application.  The implementation would look fairly familiar to anyone who has used MVC before but apparently big 'A' guy Martin Fowler asserts that there are now many different flavors of a model-view-controller|presenter pattern and in this post, Phil is showing us what the Supervising Controller pattern looks like.

One of the best things that I learned most from Phil's post was how he used the Rhino.Mocks library to create mock objects for his unit tests of his code.  This looks like a very simple way to test code that is normally difficult to test - such as ASP.NET code or code whose state is heavily reliant upon certain runtime conditions to be met.  In such cases you'll often find yourself factoring code out into interfaces and then writing testable stubs for them.  Mock objects save you from writing lots of additional code just for the sake of getting testable stubs of objects.  Here's some code from Phil's sample project in his post where he tests the events and the state of a view in his test code:

[TestMethod]
public void HandlesLoadEventAndSetsViewPropertiesCorrectly()
{
    //Setup the service return values.
 BlogPost blogPost = new BlogPost(1);
    blogPost.Tags.Add(new Tag("ASP.NET"));
 blogPost.Tags.Add(new Tag("C#"));
   
    blogPost.Description = "My computer's cup holder is broken.";
   
    //Setup the load event
    viewMock.Load += null; //ugly syntax, I know, but the only way to get this to work
    IEventRaiser loadRaiser = LastCall.IgnoreArguments().GetEventRaiser();

    // Make sure that the proper service methods were called
    // by the presenter.
    Expect.Call(this.dataServiceMock.GetById(1)).Return(blogPost);
    mocks.ReplayAll();

    //Now run the test.
    new PostEditController(viewMock, this.dataServiceMock);
    loadRaiser.Raise(viewMock, EventArgs.Empty);
   
    //Check that the view was properly populated.
    Assert.AreEqual(2, viewMock.Tags.Count);
    Assert.AreEqual("My computer's cup holder is broken.", viewMock.BlogPostBody);

    mocks.VerifyAll();
}

If the code looks a little odd then read from one of Phil's other fine article where he specifically shows how to use Rhino.Mocks to test events - that will help explain what some of that code is doing.

posted on 8/11/2006 3:31:58 AM ( 1 Comments )


XSLT extension objects

I had to create an XSLT extension object today that would format a DateTime value into a custom format.  I haven't used XSLT extension objects before but finding this article by Dare Obasanjo certainly steered me in the right direction.  In the end it wasn't very difficult at all, 20 minutes was about all it took to create my very own XSLT extension object!

Essentially you just create a little class that does what you want - in my case, formatting dates:

public class XsltDateFormatter {

    public string formatdate(string d, string format) {
        try {
            DateTime date = DateTime.Parse ;
            return date.ToString(format);
        } catch (FormatException) {
            return "";
        }   
    }
}

Then you add your class to an XsltArgumentList object, giving it a namespace:

XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddExtensionObject("http://exslt.org/dates-and-times", new XsltDateFormatter());

Then you can pass the xslArg object to your Transform method when you transform your XML:

transform.Transform(doc, xslArg, writer);

To reference the formatdate method from within your XSLT sheet you register your namespace:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    exclude-result-prefixes="date">

And then use the function like so":

<xsl:value-of
    select="date:formatdate(substring-before(scheduledstart, 'T'), 'D')"/>

The article actually comes with a download that contains hundreds of functions for things such as Math operations, Regex, and DateTimes, etc.  The actual download library is basically a .NET implementation of the EXSLT community initiative.

posted on 7/20/2006 10:18:14 PM ( 0 Comments )


Google Spreadsheets

First, let me start by saying that I've been on the road all week talking about Vista and so I'm only just catching up on my mail and blog reading.  It's funny though, because it seems that whenever you turn your back in this industry that something big gets announced - and this week it was undoubtedly Google Spreadsheets.

If you are an antagonist like me then you would surely agree that Google would have to be the greatest company in the world to work for because of the way that they can get under the skin of Microsoft simply by announcing some half-baked Web 2.0 app.  It seems that whenever Google sneezes, the Microsoft community catches a cold - I love it!

Having used spreadsheets as business applications for almost half of my working life I look forward to learning about how Google will entice big business to use their website to process mission critical, highly sensitive, highly confidential company financial data.

Whilst this is an interesting web application I can't help but think that the advertising guru's at Google must be sitting back having a real good laugh over all this fuss that this has caused right now.

posted on 6/9/2006 8:11:35 PM ( 0 Comments )


Interesting opinions on Live.com

I just read Paul's and Tim's articles about Live.com and have to say that I certainly agree with many of the things that were said.  I think that Live.com suffers from the same thing that most Microsoft offerings suffer from and that is that too much of the marketing glitz gets applied.  A first look a the Live.com portal gives you a real dose of eye-candy as opposed to the Google portal which is bare-bones in comparison.  But when you actually use both of these portals as your daily base you very quickly begin to appreciate the simple elegance of the Google portal - especially when connecting via a mobile device!

Paul's comments run deeper than a simple dislike of Live.com, he actually opines that it's the Atlas'ness of the site that is annoying.  This is interesting to me because one of the factors that I took into account when I decided to stop selling my development services (for the time being at least) was my geniune lethargy about some of these cutting edge technologies that are coming out.

Go read both Paul and Tim's articles and make up your own mind about the Live.com, Atlas, and Microsoft in general but here's my wrap on all of this... someone needs to go and tell those lovely folks Microsoft about the benefits of keeping things simple. 

posted on 5/12/2006 5:42:55 PM ( 0 Comments )


More Google Portal Goodness

The Google Personalized Home Page and Google Reader totally rock!  To use Google them you must first create a GMail account and then sign in to the Google.com home page to start personalizing it to your own liking.  Unlike Live.com, Google have gone for the kind of simple elegance that has made Google a market leader in web technology.  One of the great recent additions to the portal has been the tight integration between it and the Google Reader (click here to learn about Google Reader).

Today I noticed another really cool thing about Google Reader.  Click on this button to see it for yourself (and then return to the article):

   Add to Google

Notice that, by adding that link to your blog you can take users to a page that allows them to add your blog to either their default portal view or to your subscriptions. 

Google Reader impresses me and I'm sure that as soon as Google iron out a few bugs in their UI that it is going to gain a very important slice of the feed subscription market.  I'm not sure whether Google Reader plan to open up an API to access feed stores but I'll be watching this space with a great deal of interest.

posted on 5/11/2006 3:59:20 PM ( 0 Comments )


Buggy XSD Behavior? Cannot convert type 'string[]' to 'string'.

Suppose that you wanted to craft some schema that would match to the following XML:

<MyNames>
  <Name>
    <Nickname>Bluey</Nickname>
    <Nickname>Red</Nickname>
    <Nickname>Chief</Nickname>
    <Nickname>Tiger</Nickname>
  </Name>
  <Name>
    <Nickname>Red</Nickname>
  </Name>
</MyNames>


This would do the trick:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Test"
  targetNamespace="http://new.webservice.namespace"
  xmlns:my="http://new.webservice.namespace"
  elementFormDefault="qualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="NamesType">
    <xs:sequence maxOccurs="3">
      <xs:element name="Name" type="my:NameType" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="NameType">
    <xs:sequence>
      <xs:element name="Nickname" type="xs:string" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>

  <xs:element name="MyNames" type="my:NamesType" />
</xs:schema>


However when you run that through XSD it creates the following class definition:

public partial class NamesType {
   
    private string[][] nameField;
   
    /// <remarks/>
    [System.Xml.Serialization.XmlArrayItemAttribute("Nickname", typeof(string), IsNullable=false)]
    public string[][] Name {
        get {
            return this.nameField;
        }
        set {
            this.nameField = value;
        }
    }
}


That's interesting.  A multi-dimensional array of strings names Name.  Not quite what I'd expect to see.  I would have expected that the NamesType class would have an array of complex types called NameType and that the NameType class would have an array of strings.

Anyways, I came across this behavior when I received an error by adding a Web Reference to a valid WSDL file that had been created in XML Spy.  The error occurs when you have operations on a WSDL file that return these types.  The operations deserialize correctly by returning an array of strings for the Nickname element whereas the generated types contain a string[][]. 

There's some documentation about this behavior here:

    http://support.microsoft.com/?scid=kb;en-us;891386&spid=1444&sid=5

posted on 3/21/2006 11:03:56 AM ( 0 Comments )


Follow-up on prescriptive guidance for instrumenting code

How many of the pages in your web application execute in over 1 second?  How many execute in over 3?  Do you know?  And for the pages that are taking longer than 3 seconds, what's the cause and how often does it occur?

Last week I posted an intro article on the topic of instrumenting code and discussed some of the issues as I see them.  The point of writing about this topic is that I want to arrive at some simple prescriptive guidance for when and how to use Health Monitoring and Instrumentation in applications.  In this post I want to mention some of things that should be monitored for health. 

Unlike standard tracing, the purpose of health monitoring is exactly that - to determine the health of code so that we can be proactive in fixing code before problems occur.  Here is a list of some of the things that are good candidates for Health Monitoring code:


Calls to External Systems
Whether it is a connection to a database or a web service call to an external site, you should monitor these activities and raise health alerts when the time to perform the action exceeds a certain limit.  For example, if you make a web service call as a part of the execution of a page you don't really want to get an alert for every call that is made and you don't want to wait until that connection starts timing out.  Instead you can write some health monitoring code that notifies you whenever the time that it takes to make the web service call rises beyond a certain limit - say 1 second.  Or you could write the code so that it was even smarter and informs you whenever the time that it takes to call that resource is "growing".

Here is a sample of code that raises a custom health event named ExternalCallWebEvent whenever the time to load an XmlDocument from an external resource exceeds a hard-coded limit of 2 seconds:


Stopwatch watch = new Stopwatch();
XmlDocument tmp = new XmlDocument();

watch.Start();
tmp.Load(this.OpmlPath);
watch.Stop();

#region Health Monitoring Code

if (watch.ElapsedMilliseconds >= 2000) {
    ExternalCallWebEvent e = new ExternalCallWebEvent(
        string.Format(
            "The call to {0} took {1} milliseconds to complete.",
            this.OpmlPath,
            watch.ElapsedMilliseconds
        ),
        this,
        WebEventCodes.WebExtendedBase + 1
        );

    e.Raise();

}

#endregion

return tmp.OuterXml;


Application Restarts

Another symptom of failing health is when your application see's a large number of application re-starts.  Aside from anything else, application restarts can indicate things such as thread pool starvation and also denial of service attacks.  Typically you will want to receive batched health alerts when your application has many restarts in a short space of time.  The following configuration entry will raise an alert that will be displayed in the Event Log whenever event 1001 (ApplicationStart) has 5 or more instances within a minute.


<healthMonitoring>
  <rules>
    <add name="Check For DOS"
         eventName="Application Start"
         provider="EventLogProvider"
         profile="Critical" minInstances="5"
         maxLimit="Infinite"
         minInterval="00:01:00" custom=""
         />
  </rules>
  <eventMappings>
    <add name="Application Start"
         type="System.Web.Management.WebApplicationLifetimeEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"
         startEventCode="1001" endEventCode="1001" />
  </eventMappings>
</healthMonitoring>

 

Security Audit Warnings

Another thing to keep an eye out for are security warnings.  If someone enters a bad username/password attempt then that's no biggie, but get 10 of those in a minute and you can be sure that something's going on.  The following article provides some information about health monitoring the security of your application.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000016.asp

posted on 3/20/2006 12:31:23 PM ( 0 Comments )


My Live.com "killer feature"

One of the killer features on the new Live.com web portal is that all of the web parts offer this great "Read More" feature.

Live.com Killer Feature


With this feature you can hover the mouse over the "[more]" link for an item and have the details of the item displayed in a pop-up panel.  In the case of blog posts or news articles you get the additional text and in the case of something like the Flickr web part you get a larger version of the image.

Very nice as it allows you to consume lots of information without ever having to leave the page.  I find that it also allows you to make pages much busier with links - such as by adding dozens of news web parts - and then simply scanning over them for interesting news titles and then hovering over those interesting titles to get the content.

posted on 3/16/2006 7:37:59 AM ( 0 Comments )


Hey Web 2.0 guy - ShowUsYour

Just like SOA before it, Web 2.0 can mean pretty much anything you "feel" it to mean.  For me it means: Simple, Commercial, and Shiny.

OK, if you are reading this there's a fair chance that you're a programmer right.  Then guess what, even though you say you "Get Web 2.0", you probably don't.  In fact there's loads of people who tell us that they "get" Web 2.0 - and probably about 40 or so who really do.

Lately I've seen new blogs and podcasts springing up all over the place espousing their passion and knowledge for Web 2.0.  Which is fine... kinda.  I guess that I think that there's probably more "feel" that "grok" in there.  In other words, when you hear people say:  "I really get Web 2.0", just keep in mind that what they probably mean is: "I really get a stiffy from Web 2.0".

If you doubt it, ask them to point you at their most successful Web 2.0 "commercial" ventures :-)

posted on 3/15/2006 10:37:03 PM ( 1 Comments )


OK... so now that we're all mobile...

Answer me this: How will Ajax sites perform on my new JAMin mobile device?

 IMate JAMin

posted on 3/13/2006 8:42:56 PM ( 0 Comments )


Organizing my Live.com Home Portal Page

In my last blog post I mentioned that I've moved to having Live.com as my home portal and today I thought that I'd talk about how I can use the features of the Live.com portal to light up all areas of my browsing world.

The Live.com portal allows you to easily create new pages on the fly and each of these "pages" appears as a tab within the portal itself.  The idea behind this is that you create a page and then you can add web parts to that page to show you a specific set of information.  In my portal I have created the following pages:

  • Home
  • News and Sport
  • Blogs
  • My Custom Feeds

Here is a picture of the tabs being displayed in the Live.com portal page:

Live.com TabPages are nice

The Home page contains my Mail web part, a Flickr web part and also displays the weather and time information for a set of cities that I'm interested in.  For example, I often IM with the Development Editor on my web portal book and so it's useful to have her timezone and weather displayed while I'm chatting with her. 


The News and Sport page is a dump of news, finance, and sporting information from around the globe so that I can easily scan it to look for stories that might be of interest to me.

The Blogs page allows me to easily keep up to date with the latest feeds from a very small subset of Thought Leaders on topics that are relevant to me.  Currently I have Frank Arrigo's blog listed on this page so that I can keep abreast of the latest news from the Australian developer market.  I have Scoble's blog listed there so that I can keep up to date with the latest buzz and gossip that is relevant to the industry.  Finally I have the GadgetNews feed and the Live.com feed listed there so that I know when new Gadgets or Features are being added to the site.


The last page - "My Custom Feeds" - is similar to the blogs page but these feeds are based on custom search queries that I have created to alert me when new information about my projects appears on the web.  Currently I have two web parts on this page - one web part runs a search for information relating to BlogML while the other web part searches for information about SUBV2.


All-in-all I'm enjoying using the Live.com portal to light up my world and keep me in tune with the information that I need to be effective in my role.

posted on 3/13/2006 8:16:27 PM ( 13 Comments )


Live.com Gadgets - Come all ye Component Builders?

I was fortunate enough to see a preview of the Live.com platform last night in Sydney.  At the event I saw the Live applications and heard about the future of the platform.  I have to say that I walked away with a head full of ideas.

My main interest in Live.com centers around gadgets and so I'm very interested to see whether  "Live" exposes an open set of services that could act as a bedrock for building rich Web 2.0 mash-up style applications.  My hope is that at some point developers will be able to tap in to the Live services to create gadgets that are highly personalized and which target the end-user.

I haven't done a lot of research into gadgets at this stage but I'm very keen to learn more about where Microsoft is heading with this stuff.   If the Live services are open then this is going to be an amazing time to be a component builder in the web apps space.

 

posted on 3/10/2006 7:14:50 PM ( 0 Comments )


Been bitten? Then you should check for Byte Order Marks

A little while ago Chris Frazier wrote this post about Byte Order Marks in the payload of an XML response.  All that I can say is that I'm extremely grateful for that post because it has saved me on a couple of occassions now.  The first time that it saved me was when Mitch and I were doing some work at a client site last year and we were having trouble reading the XML that was being returned from the TFS web services.  I encountered this problem again the other day while consuming Grant's Readify Bloggers OPML file.  If you download the OPML file and look at the first character you will see that it is not a '<' character.

As Chris points out in his post, the way to fix this is to check the first character of the XML payload before reading it in and if it's not a '<' character then simply strip the Byte Order Mark off like so:


//...the DeserializeResponse method that accepts a stream
StreamReader sr = new StreamReader(stm);

string content = sr.ReadToEnd();

if(content.Trim().Length > 0 && content[0] != '<'){
 content = content.Substring(1);
}

StringReader str = new StringReader(content);

try{
 xdoc.Load(str);
}

posted on 3/8/2006 6:03:03 AM ( 3 Comments )


Implementing the Cache Pattern

I mentioned recently that the performance of SUB has been quite poor and I've started diagnosing the cause of this by instrumenting my code to see what's going on.  I also wrote an introductory article on code instrumentation which can be found here:

     http://markitup.com/Posts/Post.aspx?postId=fa94c852-fd16-4ba9-a5f0-1f72437f7cd2

I'll talk more about the specifics of the instrumentation and diagnostics in a follow-up post when I have things totally sorted although the changes that I've made so far have improved things quite dramatically. 

While going through the SUB file handling code I've been taking the time to check some of my coding patterns to ensure that operations such as caching and how I'm handling resource locking is all sweet.  Because caching plays such a large and important role within SUB I decided that I should check my caching pattern just to be sure that things are cool there and that the pattern is solid.  Currently my caching pattern looks something like this:

Data GetData( dataID ) {

     string key = "GetData" + dataID ;

     if (Cache[key] == null) {
         Data item = GotoDatabaseAndFetchData( dataID ) ;
         CacheHelper.Insert(key, item);
     }

     return HttpRuntime.Cache[key] as Data;
}

To check my pattern I headed off to Steve Smith's blog since he is the caching expert that I know best.  While browsing Steve's blog I found the exact post that I was after here:

     http://weblogs.asp.net/ssmith/archive/2003/06/20/9062.aspx

As Steve pointed the correct pattern to use is this:

Data GetData( dataID ) {

    string key = "GetData" + dataID ;
    Data item = Cache[key] as Data ;

    if (item == null) {
         item = GotoDatabaseAndFetchData( dataID ) ;
         CacheHelper.Insert(key, item);
    }

     return item;
}

Notice that in Steve's pattern a local variable is populated and then inserted into the Cache but that it is the variable that is returned from the method.  In my original code I was returning the value held in the Cache directly from the method.  As Steve notes in a recent email, on a busy site where you have sufficient load/memory pressure the code in my original pattern can cause inconsistent behavior because the item can actually be removed from the Cache in-between adding the item to the Cache and returning it at the end of the method.

Thanks Steve!

posted on 3/6/2006 5:15:14 PM ( 2 Comments )


Web 2.0 API's

Web 2.0 API Reference
 

posted on 2/19/2006 8:22:48 PM ( 0 Comments )


Flakey Security?

I was doing some research about Web 2.0 over the weekend for my book and while browsing across the various Web 2.0 sites it struck me that some of them are doing some very interesting things with data - notice that I didn't say "Good Things"... just interesting things.

First I was looking for Web 2.0 portals and came across this one:

http://www.pageflakes.com/


After fiddling around with that portal for a while and "walking away" with an astonished look on my face I came across this popular site:

http://www33.meebo.com/

Again, total amazement!

So let me get this again... they want me to key my username and password for other sites into forms on their site?  Err, yeah... right!

posted on 2/7/2006 3:50:19 AM ( 2 Comments )


IE7 Preview from an ex-Mozilla Team member.

Found via Digg:

Asa Dotzler takes on the new IE7 beta in a post detailing why it still falls short of Firefox:

thoughts on the preview of ie 7 beta 2

posted on 2/5/2006 3:59:02 PM ( 0 Comments )


Web Portals

  1. http://Live.com (or Start.com) [Microsoft]
  2. http://my.msn.com [Microsoft]
  3. http://Google.com/ig [Google]
  4. http://www.PageFlakes.com [Web 2.0 startup]
  5. http://my.yahoo.com [Yahoo]

 

NOTE: I'll start adding reviews and feature comparisons here shortly.

posted on 2/5/2006 3:11:51 AM ( 0 Comments )


Lightbox script

Here is a link to a nice set of scripts and CSS that provide an unobtrusive way to display images from a web page:

     http://www.huddletogether.com/projects/lightbox/

posted on 1/29/2006 9:13:07 PM ( 1 Comments )


Time Zone Web Service

I've uploaded a working demo of the TimeZone web service which you can find here:

    http://projectdistributor.net/Projects/Project.aspx?projectId=183

 

posted on 1/29/2006 6:33:13 PM ( 1 Comments )


Displaying dates and times in a local users time zone

Yesterdy I wrote about the TimeZones web service that I've added to this site and today I'll further explain the need for the web service.  To start, let's take a look at the problem of dates and break it into 2 segments: The date value and the format of the date value.

Formatting a culture aware date.

Let's say that you are from the US and you visit my site.  On reading an article (and after sighing that this guy doesn't know what he's talking about) you notice that the time that page says that the article was written on 18/1/2006.  Hrmm, you think to yourself... what is the 18th month again?  This is of course because in the US, dates are formatted as mm/dd/yyyy whereas in Australia here they are formatted as dd/mm/yyyy.

The answer to fixing the formatting of dates is thankfully quite simple.  Rather than formatting the date for a specific culture you can dynamically read the culture for the current user from the accept-languages array that is passed along with the head section of the request.  To do this you simply set the culture of the current thread when the request begins and then delegate all of the formatting of dates and number strings to the framework - in other words, it just works!  Here's the code that you can place in your application's BeginRequest method to achieve this outcome:

void Application_BeginRequest(Object sender, EventArgs e) {
    try {
        if (Request.UserLanguages.Length > 0) {
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(Request.UserLanguages[0]);
        }
    } catch (Exception ex) {
        PublishException(ex);
    }
}


SUB has that code in its startup so go ahead and try it out.  In Internet Explorer open up Tools | Options and choose "Languages" from the General tab.  In there you can add language or change the order of your language preferences.  Change it by adding Arabic or Chinese as your first preference and refresh the browser to see how the dates for this article are formatted.


Setting the correct date value

OK, so formatting culture aware dates is a breeze.  Just a couple of lines of code.  But what about storing the value that is used?  That's somewhat harder.  Here's a scenario:

Your website is hosted on a webserver that is located on the west coast of the US and you are currently living in Australia.  You use the web interface that is supplied with your blogging software to add a new article at 8:00am Australian time which is about 1:00pm Pacific time.  A time difference of 19 hours.

The next week, the people hosting your website move to Greenland and so when you post your next article - again at 8:00am Australian time, the time on the server is now 6:00pm on the previous day.  A time difference of 14 hours.

Finally, daylight time ends in Australia and you post another article at 8:00am Australian time which is now 7:00pm in Greenland.  A difference of 13 hours.

So how would you write a single piece of code that would always know to display the published times of your articles in Australian time?  One way would be to use javascript on the client and pass through the clients time to the server and use that.  It would work but it's cumbersome.

The better way - and the way that it is done for SUB - is to immediately store all dates in UTC time at the time that they are entered.  Working out the current UTC time is a no brainer:


     currentArticle.DateCreated = DateTime.UTCNow ;
     currentArticle.Modified = DateTime.UTCNow ;

The reason for storing the dates in UTC time is that it's easy to work with because every country already has a pre-existing way of defnining an offset from that time to work back to their own local time - the timezone difference.

Now that the time is stored as UTC time it can simply be converted to the local time of a given time zone as soon as it is reloaded from storage.  In the case of SUB the logic for doing that looks like this:


DateTime dt1 = DateTime.Parse(node.Attributes["dateCreated"].Value);
DateTime dt2 = DateTime.Parse(node.Attributes["dateModified"].Value);               
               
TimeZoneInformation info = TimeZoneInformation.FromName(
    BlogConfigurationSettings.TimeZoneName
    );


DateTime utc1 = info.FromUniversalTime(dt1);
DateTime utc2 = info.FromUniversalTime(dt2);

this.DateCreated = utc1;
this.DateModified = utc2;


See that the UTC times are pulled from the XML storage and then the TimeZoneInformation class is spun up for the time zone that the blog has been configured to use.  Then, using that class (which itself uses the underlying Windows API's) the UTC time can easily be converted to the timezone that the blog has been configured to use.

When the data is stuffed back into storage - such as when it is edited - the TimeZoneInformation class is again used to convert the local time back to UTC time as shown in the next snippet:


TimeZoneInformation info = TimeZoneInformation.FromName(
    BlogConfigurationSettings.TimeZoneName
    );

DateTime utc1 = info.ToUniversalTime(this.DateCreated);
DateTime utc2 = info.ToUniversalTime(this.DateModified);


attr = node.OwnerDocument.CreateAttribute("dateCreated");
attr.Value = FormatDateTime(utc1);
node.Attributes.Append(attr);

attr = node.OwnerDocument.CreateAttribute("dateModified");
attr.Value = FormatDateTime(utc2);
node.Attributes.Append(attr);

So when you read this article and you see that it was posted on 19/01/2006 at 8:19:10 AM (if your browser language is Australian anyway) you will know that I wrote it on the morning of the 19th January and not at 1:00am on the morning of the 20th January as would be the case if I was using the server times to store dates.

posted on 1/19/2006 6:21:58 PM ( 0 Comments )


Time Zone Web Service

I was chatting with Paul Stovell yesterday about SUB and he asked for a specific feature to do with having posts and comments displayed in his current time zone and not the time zone of the web server.  Specifically he asked:


Well, if you look at my site, it's got the time underneath the post - monday, 7:32pm... that's because it's stored in american time again... but I think even with SUB2 if you store them as universal times, they will be displayed again as american time (ie 10 hours behind)... could you have a Display Timezone or something?


Paul's right.  Even if I stored the dates as UTC format, when I got them back out and converted them based on the current time zone they would appear in US date times again.  When we first started to think about solving this problem it seemed simple: create a config setting that allows the admin to enter the UTC offset for the blog and then all DateCreated and DateModified times will use that.  The steps would be:

  • store all dates as UTC values
  • when re-loading dates calculate the difference between the offset and the server GMT offset
  • apply that difference to the UTC time

Something that simple would be great and easy to implement - except for daylight time adjustments.  To implement the daylight adjustments would mean that the user would have to enter a value for:

  • UTC Offset
  • Daylight adjustment minutes
  • Daylight start date
  • Daylight end date

It'd all be so much easier if the TimeZone class in the Framework exposed this information.  Luckily for me somebody had already gone to the trouble of exposing this information via API calls and made their code available via this CodeProject article:

    http://www.codeproject.com/dotnet/WorldClock.asp

I very hastily downloaded the code and hacked away at a few prototypes.  As you can see from the CodeProject article I also tacked on a couple of useful helper properties to help work out whether a current time zone is experiencing daylight time or not.

SUBV2 now uses this logic to store dates in UTC format and convert them to the blog owner's time before they are displayed on the site.

I've also exposed the some of the TimeZone logic via web services on this site.  You can go here to test them out:

     http://MarkItUp.com/WebServices/TimeZones.asmx

Feel free to play around with them but if you'd like to reference them from an application be sure to contact me first so that I can advise you of any changes or if I plan to move them to a new location.  Over time I'll probably issue keys to access the service so that I can formally keep track of who is using them.  If you want to try it out you'll have to hit this method first to get a list of the time zone names so that you can pass them to the other methods:

     http://markitup.com/WebServices/TimeZones.asmx?op=GetTimeZoneNames

 

posted on 1/19/2006 12:29:51 AM ( 10 Comments )


Adding app-relative items to the Head section of a MasterPage

There was an interesting post on one of the ASPNETV2 lists today and yesterday about what is the best way to set an app-relative path for a script block in a Master Page.  Ideally you would just be able to do something like this:

    <script
       language="javascript"
       type="text/javascript"
       src="<%= Request.ApplicationPath %>/myhelper.js"></script>


Part of the issue here is that you cannot use something like <%= Request.ApplicationPath %> because the <head> tag in the master page is set to runat=server so if you use code blocks within the head section ASP.NET with throw an exception.

A few people chimed in to suggest doing a simple replace operation on the contents of the head section.  One such suggestion was to do this:

<head runat="server" id="myHead">
    <script language="javascript" type="text/javascript" src="[MYROOTPATH]/myhelper.js"></script>
</head>

Then in the Page_Load

myHead.InnerText = myHead.InnerText.Replace( "MYROOTPATH", "<rootpath>" );

Unfortunately this won't work because you cannot treat the InnerText property as a simple string object.  The way to achieve a result similar to this would be to override the AddParsedSubObject method of control and carry out the parsing logic there.   To do so for the above snippet of HTML would mean doing something like this:


protected override void AddParsedSubObject(object obj) {
    base.AddParsedSubObject(obj);
    if (obj is HtmlHead) {
        HtmlHead head = (HtmlHead)obj;
        foreach (Control ctl in head.Controls) {
            if (ctl is LiteralControl) {
                LiteralControl ltl = (LiteralControl)ctl;
                ltl.Text = ltl.Text.Replace("[MYROOTPATH]", Request.ApplicationPath);
            }
        }
    }
}

Bertrand Le Roy chimed in to the list and suggested that a better way would be to encapsulate the logic within a control so I tried that out.  My first thought was to create a ScriptControl server control that contained the logic for rendering a script tag, you could then use the server control in the head section of the page like so:

<wp:ScriptControl Path="~/foo.js" ID="ScriptControl1" runat="server" />

The control that I came up with to achieve this was dirt simple as can be seen in the following snippet of code:

public class ScriptControl : Control {

    const string TAG = "<script type=\"text/javascript\" language=\"javascript\" src=\"{0}\" />";

    public ScriptControl() { }


    private string _path;
    public string Path {
        get { return _path; }
        set { _path = value; }
    }


    public override void RenderControl(HtmlTextWriter writer) {

        writer.Write(string.Format(TAG, ResolveClientUrl(Path)));
        writer.Write(Environment.NewLine);
    }
}

The problem here is that the user is stuck with hard-coded attributes such as "language", "type", and "source".  Ideally the user would add their own attributes and also be able to specify what type of tag it was so that the server control could be re-used for other non-visual elements in the head section of the document that need to reference a specific resource.  The .NET Framework actually provides us with an interface called IAttributeAccessor which allows controls to be the recipients of arbitrary attribute data.  I actually blogged about the IAttributeAccessor interface previously when describing how the GenericWebPart control works (http://markitup.com/Posts/Post.aspx?postId=322871ea-a255-4542-b729-80ffc4d6b352).

The control that I arrived at allows you to create elements such as this in the head section of the master page:L

<wp:PathControl Path="~/foo.js" ID="PathControl1" runat="server" type="text/javascript" language="javascript" TagType="Script" />

<wp:PathControl Path="~/bar.css" ID="PathControl2" runat="server" type="text/css" media="screen" TagType="Link" />

<wp:PathControl Path="~/Rss.aspx" ID="PathControl3" runat="server" type="application/rss+xml" rel="alternate" title="Rss" TagType="Link" />


And here's the code for the PathControl server control:


public enum TagType : short {
    Script,
    Link
}

public class PathControl : Control, IAttributeAccessor {

    public PathControl() { }

    public string Path {
        get { return ViewState["Path"] as string; }
        set { ViewState["Path"] = value; }
    }

    public TagType TagType {
        get { return (ViewState["TagType"] == null) ?TagType.Link : (TagType) ViewState["TagType"]; }
        set { ViewState["TagType"] = value; }
    }


    Hashtable attribs = new Hashtable();


    protected override void Render(HtmlTextWriter writer) {
        base.Render(writer);

        RenderStartTag(writer);

        foreach (string key in attribs.Keys) {
            writer.WriteAttribute(key, (string)attribs[key]);
        }

        RenderEndTag(writer);
        writer.Write(Environment.NewLine);

    }


    void RenderStartTag(HtmlTextWriter writer) {

        if (TagType == TagType.Script) {
            writer.Write("<script src=\"" + ResolveClientUrl(Path) + "\"");
        } else {
            writer.Write("<link href=\"" + ResolveClientUrl(Path) + "\"");
        }
    }

    void RenderEndTag(HtmlTextWriter writer) {

        if (TagType == TagType.Script) {
            writer.Write("></script>");
        } else {
            writer.Write(" />");
        }
    }

 

    public string GetAttribute(string key) {
        return attribs[key] as string;
    }

    public void SetAttribute(string key, string value) {
        attribs[key] = value;
    }
}

posted on 1/12/2006 2:34:10 AM ( 12 Comments )


Interesting WSDL behavior

The purpose of this post is to show how to reproduce and correct the following WSDL error message:

No methods were found in the WSDL for this protocol.


1) Create a service contract:

[WebService(Namespace = "urn: MarkItUp-Schemas-Service ")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public interface IService {
    [WebMethod]
    string HelloWorld() ;
}

2) Create a concrete implementation of it:

public class Service : WebService, IService {
    public string HelloWorld() { return "Hello World"; }
}

3) Generate a proxy for the service for clients to use to connect to the service:

> wsdl http://localhost/SimpleWebService/Service.asmx

Notice that when the proxy file is generated that WSDL has created two classes.  One class is named IService, and the other is named ServiceSoap.  To use the proxy class the clients will have to refer to concrete class named IService.  Ie:

IService service = new IService() ;
string result = service.HelloWorld() ;

If you look carefully at the code that was generated by WSDL when it created the class named ServiceSoap, you will also see that an warning was emitted into the code.  The warning states: CODEGEN: No methods were found in the WSDL for this protocol.

There is a way to remove this warning which also ensures that clients are able to refer to the proxy class using the more desirable classname of Service as as opposed to IService.  The secret is to specify a name for the service in the WebServiceBinding attribute like so:

[ WebService(Namespace = " urn: MarkItUp-Schemas-Service ")]
[WebServiceBinding(
    Name="Service",
    ConformsTo = WsiProfiles.BasicProfile1_1
    )
]
public interface IService {
    [WebMethod]
    string HelloWorld() ;
}

When a name is specified for the service WSDL generates only a single class and the warnings do not appear.

Just thought that I'd share that piece of knowledge!

posted on 11/30/2005 4:06:59 AM ( 10 Comments )


ASP.NET 2.0 Themes and Skinning

One of my favourite features in ASP.NET 2.0 is Themes (in fact I like it so much that I own the domain aspthemes.net) so naturally it's one of the features that I'm hoping to get a lot of mileage out of when writing SUB V2.

Yesterday I showed how, with zero code, I was able to create the Post Categories tree by simply dragging out a TreeView and binding it to an XmlDataSource.  Today I'd like to talk about how, by moving all of those style attributes into my themes folder, that I can get a very customizable site.

When you move the style information into a skin file you can optionally give the skin an ID and then refer to it explicitly.  The TreeView that I showed yesterday had a pretty simple style so I'd give it a skin ID of something like: "SimpleTree".  The power of themes is that I could easily create several other skin ID's and add them to the skin file also and then, at runtime, I could actually allow the user to choose which theme they want to display.

The following image shows how I was able to create 4 different skins for the TreeView based on some out-of-the-box ones that ship with ASP.NET 2.0. 

Styled Trees

From the developer perspective I was able to do all of this in less than 10 minutes and, from the end-user's view, they will love the ability to easily style the application in whichever way they choose to do.

All of this makes for a very customizable blog when I'm finished with SUB V2.

posted on 11/13/2005 1:26:04 AM ( 0 Comments )


IE7 thoughts

I've been playing with IE7 for a month or so now and, for the most part it's been pretty good.  I wouldn't call it the most revolutionary product release but it certainly seems better.  These are some thoughts about things that might improve it:

  • Bring back the Refresh and Stop buttons
  • Warn me if I'm closing the browser and I have more than 1 tab open
  • Allow me to save all open tabs - just in case I need to re-boot or something

posted on 10/28/2005 12:21:26 AM ( 1 Comments )


Focus! You're showing me your password.

One of the things that has always annoyed me is applications that force themselves into being focussed.  You see it a lot with windows applications that seem to resurrect themselves from the Windows Taskbar magically and you also see it in certain web applications. 

This is especially a problem when you think that the cursor is in a password field and the focus is automatically switched to another field or application; thus allowing you to enter your password for the whole office to see.  Some of the passport enabled sites suffer from this - sites such as Hotmail that have a heavy Css file and a few images to load before they run their SetFocus() function.

The following form demonstrates the problem - to simulate it yourself, point the image at a large bitmap or implement your an HttpHandler that sleeps for a while to simulate a slow loading page.  Just load the page and start using the web form by entering your username and then tabbing and entering your password:

<html><body onload="Focus();">

<script language="javascript">
    function Focus() { document.getElementById("uname").focus() ; }
</script>

<form id="frm">
    <input name="uname" type="text" /><br />
    <input name="pwd" type="password" />
</form>

<img src=" http://localhost:60165/Stuff/SlowLoad.ashx " />

</body></html>

the HttpHandler code:

public class SlowLoad : IHttpHandler {
   
    public void ProcessRequest (HttpContext context) {
        System.Threading.Thread.Sleep(5000);
    }
 
    public bool IsReusable {
        get { return false; }
   }
}

Here's my proposed solution... if you have a form with a password field on it, make your focussing logic just a little smarter.  Start the form with the password field disabled by default and then, in your kick-ass focussing code, re-enable it after you set the focus:

<html><body onload="Focus();">

<script language="javascript">

    function Focus() {
       document.getElementById("uname").focus() ;
       document.getElementById("pwd").disabled = "" ;
    }

</script>

<form id="frm">
    <input name="uname" type="text" /><br />
    <input name="pwd" type="password" disabled="disabled" />
</form>

<img src=" http://localhost:60165/WebParts/BigImage.ashx " />

</body></html>

That's all!

posted on 10/25/2005 12:45:16 PM ( 1 Comments )


Web Part Pages - DisplayModes

The DisplayMode of a web parts page is an interesting thing and, when you look at the syntax for changing it you'll probably wonder why an enum wasn't used. Here's an example showing the code that is required to change the mode to "catalog" mode:

WebPartManager wpm = WebPartManager.GetCurrentWebPartManager(this) ;
wpm.DisplayMode = WebPartManager.CatalogDisplayMode;

If you've done any amount of .NET programming then you would most likely have expected to have seen something which looks a bit more like this:

WebPartManager wpm = WebPartManager.GetCurrentWebPartManager(this) ;
wpm.DisplayMode = DisplayModes.CatalogDisplayMode;

There are actually 5 "standard" display modes in total - BrowseDisplayMode, CatalogDisplayMode, ConnectDisplayMode, DesignDisplayMode, and EditDisplayMode - and each of those has an associated property of the same name which hangs off of the WebPartManager instance. These properties are actually instances of a class which inherits from an abstract base class named WebPartDisplayMode. This is done because the mode changing actually requires certain logic and state which is held within this class. For example, because of the impact of things such as personalization, each mode may behave slightly differently on a per-user basis.  The initial values of the display mode instance are set by the WebPartManager as you'd expect.

The 5 "standard" display modes are:

BrowseDisplayMode
This is just as it suggests - browse mode. Browse mode is the default mode for a page and is the mode that you you'd be in if you were just browsing a web parts page. No special permissions are required to enter this mode.

CatalogDisplayMode
Switching the page into "catalog mode" displays the catalog user interface so that the user can add new web parts to the page at runtime. When you attempt to change to this mode there is a check to ensure that you have a CatalogZone control on the page before the mode is changed. If you have not added a CatalogZone control to the page then that mode will not be supported for the page and an exception will be thrown.

ConnectDisplayMode
Before you can switch the page into "connect" mode you will need to have a ConnectionsZone on the page and you will need to be authenticated. When in "connect" mode users can manage dynamic connections by displaying the ConnectionsZone. When in this mode, each part that is configured for connections will automatically have a "Connect" verb added to its verbs collection; to display the ConnectionsZone you click on the connect verb for a specific part and the ConnectionsZone will allow you to manage the dynamic connections for that part.

DesignDisplayMode
"Design" mode allows users to drag web parts between zones. When you switch into this mode each zone the user interface for each zone changes appearance to indicate that web parts can be dragged onto it.

EditDisplayMode
In "edit" mode users can move web parts between zones just as they can when in "design" mode. Switching the page into "edit" mode displays the editor user interface so that the user can add eidt web parts properties at runtime. When you attempt to change to this mode there is a check to ensure that you have an EditorZone control on the page before the mode is changed. If you have not added a EditorZone control to the page then that mode will not be supported for the page and an exception will be thrown.

posted on 9/25/2005 3:45:59 AM ( 5 Comments )


Watch Anders talking about LINQ (Language INtegrated Queries)

UPDATE[1]: Next time I need to read the "friendly" manual before saying that something isn't working.  Everything is now working as expected!

UPDATE: I downloaded the LINQ preview and installed it.  It actually installed real quick with no reported errors.  The LINQ-Preview templates didn't show up so I went and copied them into my default templates folder.  I opened up VS and copied some LINQ code into the a code file, pressed compile and received an error stating that: "System.Array does not contain a definition for WHERE".  Sorry LINQ... you promised so much. 

I've posted this question to the LINQ forum so hopefully there will be a response soon: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=90075


http://channel9.msdn.com/showpost.aspx?postid=114680

In this video Anders shows how to use LINQ and also explains some of the implementation that make it possible at a language and CLR-level such as: Extension Methods (lambda-like functions) and Anonymous Types.   I'll be interested to have a play with the samples to get a better understanding of how I'd implement some of this stuff. 

The possibilites behind Extension Methods seem very exciting to me and they are a very powerful concept. 

Having just written a filesystem data provider (for SUB) I know what's involved in working with data outside of the database.  Stop and think about where we get data from these days - WinFS, XML, etc - and you start to realize how cool it would be to have data model unification across each of these things.

I think that one obvious area that will benefit from this in the future is for writing strongly typed queries in the database using managed code but, as Dan Fernandez points out in the video, being able to run LINQ over any enumerable data means that the power of database queries can now be brought to a whole range of things such as querying the registry keys or other interesting things such as querying controls on a User Interface... think about that for a while!

Also, the other day, Joseph talked about his first impressions of XLinq which sounds as though it is an XML-specific flavour of LINQ:

    http://jcooney.net/archive/2005/09/13/6731.aspx

posted on 9/16/2005 10:33:13 PM ( 1 Comments )


Secure Your Parameters!

Secure those parameters!

Rocky has written a great, common-sense style article about security with respect to securing inputs and outputs.   I had just finished reading it and started working through some ATLAS hands-on-labs.  The first sample that I ran through was showing how to accept some text input from a user and pass it to a WebMethod from the client machine.  Here is step 3 of that excercise:

·         Change the method to accept a single string parameter.

·         Encode the string passed to the service to protect against scripting attacks.

·         Format the input string as a message. For example, format the string to return Hello, you queried for {0}.

·         Append the current date and time to the string.

·         Return the string.

 

Way to go Rock and the ASP.NET Team!

posted on 9/14/2005 10:15:13 PM ( 0 Comments )


SmartPart

SmartPart allows you (apparently, haven't tried it yet) to host any User Control as a SmartPart within Sharepoint.  This would absolutely rock! 

Between continuing with my document writing, downloading and playing with ATLAS and downloading and trying this, I can see many sleepless nights ahead.

Note to Wally... stop IM'ing me and telling me to go to bed :P

posted on 9/14/2005 4:37:16 AM ( 1 Comments )


Atlas is alive, long live Atlas!

This is the big news of the day, ATLAS is now live :-)

I can't wait to get into this stuff and have even set aside a section in a document that I'm writing to discuss it.

UPDATE: I just had some feedback from someone who is actually at the PDC, apparently, regarding ATLAS... "The buzz is good" :-)

posted on 9/14/2005 12:11:32 AM ( 0 Comments )


ASMX2 and SchemaImporterExtension links

I've been working on an application that is essentially a data processing pipeline.  Due to the nature of this service we essentially started from a contract-first design principle.  This was interesting as it forced me to look at many of the application development processes from a diffrent viewpoint and, in the process I discovered some really cool tools and articles that can help you design from a schema-first standpoint and wanted to blog about them so that I don't lose some links.

SchemaImporterExtension

After the schema contracts were defined the next task was to get the code generation tools in place to assist with the generation of business classes and some of the business and data component layers.  Here are some articles that describe how to use the SchemaImporterExtension class to meet any shortfalls from the out-of-the-box XSD.exe code.

    John Bristowe's tutorial on implementing SchemaImporterExtension
    Walking XMLSchema objects

ASMX2

    Christian Weyer talking about WebService enhancements in ASMX2

Schematron

We decided to use Schematron to assist with some of the data validation for business rule data constraints.  This is really nice an allows you to easily create standalone rulesets that can be applied against incoming XML documents to validate data constraints:

    http://www.schematron.com/spec.html

posted on 9/8/2005 4:00:22 AM ( 1 Comments )


TechEd - The Hour Of Power

There's a session at TechEd this year which sits waaay down at the bottom.  Last session.  Last day.  Friday, 3:45pm-5:00pm.

Officially this session is titled: ".NET Framework: What's New in the Framework for V2.0 Paul Glavich and Dave Glover".  The unofficial name for this session is: "The Hour of Power!".

This is a session where a bunch of people get to stand up for 10 minutes and show-off their absolute favourite part of .NET V2.  For me this is an absolute no-brainer - The ASP.NET Portal Framework.  During my "10 minutes of fame", I'll show how you can extend the CatalogZone web control to convert it into a fully-functional, Sharepoint-like Catalog.

Take a look at these 2 images to compare the differences between a standard Sharepoint Catalog and a standard Web Portal Catalog:

The Sharepoint Catalog and Galleries The standard ASP.NET Catalog and Galleries


The Sharepoint gallery has a much nicer UI with all of those icons and super-styled hover buttons for the categories and parts.  It also supports rich Galleries such as the Online Gallery and also the Virtual Server Gallery.  I'll show how to add both of these features into your Catalog.

By the end of my 10 minutes session you will - hopefully - see how to extend the base CatalogZone class to override its rendering.  You'll also see how to implement these specialized galleries so that you can, for example, have galleries which store their parts in the database and are accessed via web services by multiple applications.

So, don't miss this session... there will be plenty of time for Margharitas when we are done ;-)

posted on 8/22/2005 1:10:29 PM ( 3 Comments )


Simple (yet cool) MapPoint demo online

Dave Glover, has added a nice little MapPoint demo online.  The demo is written in VS2005 and you can grab it from here:

    http://projectdistributor.net/Projects/Project.aspx?projectId=143

2 things that I'd like to say about this demo:

  1. If you are planning to use it go and grab it now.  Reason is that you'll need to apply for a MapPoint account - which I'm told can take 1-2 days for approval, so get started now.
  2. This is a "Codezone" release so if you are using VS2005, go and download the release to experience the new vsi install process.

posted on 8/1/2005 11:39:01 PM ( 0 Comments )


Nice web templates - and other web resources

Found this link today which has some great XHTML templates:

    http://particletree.com/features/quick-start-your-design-with-xhtml-templates

That page also has nice AJAX-style context menu's on the context sensitive words. 

On my searches I found these other neat web techniques and tricks:

Sidenotes/Footnotes
http://www.brandspankingnew.net/specials/footnote_3.html

Link Preview
http://particletree.com/features/preview-your-links

Component Art Web Components
http://webui30.componentart.com/

posted on 7/31/2005 2:00:08 AM ( 2 Comments )


WebRequest ConnectionGroupName

Yesterday whilst working on enabling trackbacks in my blogging app. I wrote a little harness which could simulate an application by driving trackback data into this web server.  Basically, I created a WebRequest instance, grabbed the request stream from it and then wrote some bytes - my trackback data - straight back to the server.

What I noticed is that I could successfully simulate 1 trackback but that for each subsequent test that I ran, nothing would show up in the trackbacks for the post that I was pinging.  Then I noticed that if I ftp'd into the server and reset my application that I could again send 1 more trackback request before more nothing.

I spoke to Mitch who said that it probably has something to do with the web using keep-alive's and that I should try setting the KeepAlive property to false or that I should explicitly pass in a different ConnectionGroupName for each request to get pulled anew from the pool.

First I wrapped my WebRequest code in a try...catch to see what the exact error was and it turned out that it was: "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.".  So Mitch's suspicions were correct.

First I tried fiddling with the KeepAlive setting on the underlying HttpWebRequest by explicitly setting it to false before requesting the stream.  This didn't work and I still got the same error.

Next I set the ConnectionGroupName property on the request to a random value before requesting the stream.  Success!   I must admit that I've never used that property before so it was nice to learn something about it.  Now I'll have to try and understand what goes on between IIS and ASP.NET on the server when KeepAlive's are switched on and how setting the ConnectionGroupName circumvents it.

 

posted on 7/9/2005 5:04:28 AM ( 9 Comments )


MarkItUp.Web.Personalization

Just wanted to discuss a component that I've uploaded to ProjectDistributor:

    Personalization

This is one of the first web controls that I created for myself back when I started getting into ASP.NET and is designed to abstract away the complexity of working with cookies which have many keys and sub-keys.  The component itself is designed to work around the notion of a "store" - which is the abstraction of a key.  When you work with Personalization you must mention which store you are working with up front, ie:

Personalization p = new Personalization("CommentForm_ascx") ;

if( p.Items["chkRememberMe"] != null ) {
   
this.chkRememberMe.Checked = bool.Parse(p.Items["chkRememberMe"].ToString()) ;
    if( this.chkRememberMe.Checked ) {
        this.txtName.Text = p.Items["txtName"].ToString() ;
        this.txtUrl.Text = p.Items["txtUrl"].ToString() ;
    }
}

The above snippet opens a store named "CommentForm_ascx" and reads keys (which map to sub-keys) from it.  Notice how the component lends itself to logically creating stores around specific page functions.  This snippet would normally appear in your page load code to set the initial state of a page based on some persisted personalization settings.

Conversely, in your page unload (or pre render) logic, you should persist settings back into the personalization store like so:

protected override void OnPreRender(EventArgs e) {
    base.OnPreRender (e);
   
Personalization p = new Personalization("CommentForm_ascx") ;

   
if( this.chkRememberMe.Checked ) {
       
p.SetValue("chkRememberMe", "true");
       
p.SetValue("txtName", this.txtName.Text);
       
p.SetValue("txtUrl", this.txtUrl.Text);
   
}else{
       
p.Remove("chkRememberMe") ;
       
p.Remove("txtName") ;
       
p.Remove("txtUrl") ;
    }
}

posted on 7/9/2005 3:12:26 AM ( 0 Comments )


Ajax the implementation

Unless you've been living on some faraway place you will already know that a little while back, somebody coined the term AJAX (Asynchronous Javascript and Xml) for applications which load data via asynchronous XmlHttp requests.  It sounds sexy for sure.  In fact, when I told a friend about this new blogging engine that I've built, his first question was: "Are you using AJAX?".

The more I thought about that question, the less I understood it.  I mean this site is certainly not slow (http://www.websiteoptimization.com/services/analyze) so I didn't need it for that.  There's not that many options on each page, so I don't need it for real estate. 

Then I decided to look around the web to see how all of these other people were using it.  I found this page which gives some examples of the usage of AJAX:

    http://www.indiankey.com/cfajax/examples.asp

So, you use AJAX if you have large amounts of data which are conditionally visible at runtime - such as Help Text, List Items, Maps :-)  - and AJAX will help you to deliver this data in a "Just in Time" manner to help reduce the initial time to load for the page.  This could be a winner for things such as interactive help and certain complex validation logic scenarios.

Another consideration that you should take into account when supplying AJAX interfaces is whether or not the loss of the back button is a good or bad thing.  In some cases I find it extremely useful to be able to "back" navigate through my previous page selections whereas in others (such as complex management screens) I would not miss it at all.

Ever used AJAX in your own applications?  I'd love to hear the thinking behind what went into the decision.

 

posted on 7/8/2005 3:07:45 AM ( 1 Comments )