<?xml version="1.0" encoding="utf-8"?><rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0"><channel><title>SharpEdge Software Blog</title><link>http://www.sharpedgesoftware.com/blog/feed</link><description>Sharp opinions, edgy thoughts</description><lastBuildDate>Wed, 13 Jul 2011 21:44:36 +0100</lastBuildDate><item><guid isPermaLink="false">would-be-bettercom-lessons-learned-building-a-site-with-a-social-component</guid><link>http://www.sharpedgesoftware.com/Blog/2011/07/13/would-be-bettercom-lessons-learned-building-a-site-with-a-social-component</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Life, The Universe and Everything</category><category>Would Be Better</category><title>Would Be Better.com: Lessons learned building a site with a social component</title><description>&lt;p&gt;I had no delusions of becoming as popular as Twitter or Facebook with &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt;, at least not right off the bat ;) so it came as no surprise when almost nobody signed up for the site.&lt;/p&gt;  &lt;p&gt;Release early and release often, &lt;a title="Signal vs Noise - 37Signals&amp;#39; company blog" href="http://37signals.com/svn" target="_blank"&gt;you hear them say&lt;/a&gt;. Or, a favourite one of mine, if you’re not ashamed of version 1.0, you didn’t release early enough. And just in case you think I’m being sarcastic or that this is going to be a rant, you’re wrong: I couldn’t agree more with both statements.&lt;/p&gt;  &lt;p&gt;Anyway, so I put &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; up quite early and have been adding features here and there more or less ever since, but how did I drive traffic to it?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Come to me&lt;/h4&gt;  &lt;p&gt;I decided to give &lt;a title="Stumble Upon" href="http://www.stumbleupon.com" target="_blank"&gt;StumbleUpon&lt;/a&gt; campaigns a try, even though I know &lt;a title="Startup Marketing Part 3: The Nine Levels of Traffic Quality" href="http://www.softwarebyrob.com/2010/01/12/startup-marketing-mistake-ignoring-traffic-quality/" target="_blank"&gt;not all traffic has the same quality level&lt;/a&gt;. So it was in any case a conscious choice: let them come en masse, and some might stick, but even counting on the power of sheer numbers not many visitors created an account.&lt;/p&gt;  &lt;p&gt;Which isn’t that surprising at all really: Most users, including you and me dear reader, are fed up with creating new accounts for everything, some of which require you to give irrelevant personal details to sign up; most of which require you to provide a valid email address.&lt;/p&gt;  &lt;p&gt;So the obvious solution is, let them use an account they already have to sign up for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;OpenID to the rescue&lt;/h4&gt;  &lt;p&gt;Most people out there already have an &lt;a title="OpenID Foundation" href="http://openid.net/" target="_blank"&gt;OpenID&lt;/a&gt;-enabled account somewhere, even if they don’t know it. &lt;a title="Gmail - Google Mail" href="http://www.gmail.com" target="_blank"&gt;Gmail&lt;/a&gt;, &lt;a title="Windows Live" href="http://www.live.com" target="_blank"&gt;Windows Live&lt;/a&gt;, &lt;a title="Yahoo Mail" href="http://mail.yahoo.com" target="_blank"&gt;Yahoo Mail&lt;/a&gt;, &lt;a title="Facebook" href="http://www.facebook.com" target="_blank"&gt;Facebook&lt;/a&gt;, &lt;a title="Twitter" href="http://www.twitter.com" target="_blank"&gt;Twitter&lt;/a&gt;, &lt;a title="LinkedIn" href="http://www.linkedin.com" target="_blank"&gt;LinkedIn&lt;/a&gt; are some of the platforms that act as OpenID providers, and there are many more.&lt;/p&gt;  &lt;p&gt;So, &lt;a title="How to add OpenID authentication to your ASP.NET MVC 3 site using Janrain Engage" href="http://www.sharpedgesoftware.com/Blog/2011/02/21/how-to-add-openid-authentication-to-your-aspnet-mvc-3-site-using-janrain-engage" target="_blank"&gt;as you may remember&lt;/a&gt;, the next step was a no-brainer, and armed with an OpenID-enabled &lt;a title="Would Be Better - Sign Up!" href="http://www.wouldbebetter.com/login" target="_blank"&gt;sign up process&lt;/a&gt; I re-enabled the StumbleUpon campaign and waited for the magic to happen. Until, all of a sudden: Nothing.&lt;/p&gt;  &lt;p&gt;Nothing worth mentioning in any case. There was some improvement in the conversion rate, and at least almost all new users had acknowledged my effort by using the OpenID login, but it’s not like potential users were piling up to sign up.&lt;/p&gt;  &lt;p&gt;Most importantly, to this day 95% of the users are one-time posters, never to return again. The other 5% consists of me and people I know well.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;What do people actually want?&lt;/h4&gt;  &lt;p&gt;So what does &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; lack that prevents users from coming back? Well, for one, after taking a deep, hard look at Would Be Better I realised that for a social site there wasn’t much social component to speak of…&lt;/p&gt;  &lt;p&gt;Hah! So that’s why I don’t have whole herds of believers knocking at the Would Be Better doors! People are social beings! They want to interact with each other!    &lt;br /&gt;Piece of cake, right? Wrong.&lt;/p&gt;  &lt;p&gt;I followed the next logical step: enabling comments on suggestions. If people can let their thoughts loose on other people’s suggestions they’ll sure come back to check if there are any replies to their comments or event comments on their own suggestions? Well you’d think so but that didn’t have the desired effect either, and I think I know why.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Your name rings a bell but…&lt;/h4&gt;  &lt;p&gt;People might be social, but they are above all, lazy, busy or absent minded or all three and need to be constantly reminded of their appointments, to-do lists, and, of course, that your app exists.    &lt;br /&gt;Even Facebook, a central part of so many people’s daily lives, does a terrific job of reminding you every now and again that it’s there!&lt;/p&gt;  &lt;p&gt;And that’s where we’re at with &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt;. Would Be Better lets you post suggestions, lets other users comment on your suggestions and it even let’s you mark a suggestion as “Is Better”, allowing you to explain how or why. What &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; does not do, is notify you, dear user, of any activity or news around things you have posted.     &lt;br /&gt;What we were arrogantly expecting of our users, is that they’d make some free time in their busy online agenda, not only to come pay us a visit, but to remember on their own to come and take a look.&lt;/p&gt;  &lt;p&gt;If that’s not being self absorbed I don’t know what is.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Hi! It’s me again!&lt;/h4&gt;  &lt;p&gt;So we’ve seen the light. Again. We’re currently busy bees working on an alert system for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; that’ll let you know right from the moment you log in whether there’s anything worth checking regarding your suggestions and comments. The same alert system will take care to send you an email whenever there’s new activity that might concern you.&lt;/p&gt;  &lt;p&gt;That’s right, we’re becoming less arrogant by becoming annoying.&lt;/p&gt;  &lt;p&gt;But don’t worry, needless to say there’s account settings that allow turning off email notifications and newsletters.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Wait, what newsletter?&lt;/h4&gt;  &lt;p&gt;Exactly. That’s saddest part: there’s been in &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; a mechanism to remind the users of our existence all along! The tricky thing I’ve discovered about newsletters though, is that it’s all very good an well to have a nice system to compose and send newsletters to your users, but you have to actually use it for it to be any good…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;So what’s the lesson?&lt;/h4&gt;  &lt;p&gt;Well, I’ve been spreading all the “lessons learned” all along this post really, but the most important point is probably that it’s all a work in progress, and that assumptions and theories about what might work and what won’t are all very well, but you have to try it:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Let your idea loose “in the wild” &lt;/li&gt;    &lt;li&gt;See if it works &lt;/li&gt;    &lt;li&gt;Adapt &lt;/li&gt;    &lt;li&gt;Rinse and repeat &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Do you have (dis)similar experiences? Care to Share them? &lt;a title="Post a comment" href="#commentinput"&gt;Let me know&lt;/a&gt;!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8a1a7f6d-4bb3-41a8-96ee-ab0474d4ceb7" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-07-13T21:29:04+01:00</a10:updated></item><item><guid isPermaLink="false">usability-round-up</guid><link>http://www.sharpedgesoftware.com/Blog/2011/06/22/usability-round-up</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Life, The Universe and Everything</category><category>SharpEdge Software</category><category>Usability</category><title>Usability round-up</title><description>&lt;p&gt;Those of you who have bothered reading the &lt;a href="http://www.sharpedgesoftware.com/"&gt;landing page&lt;/a&gt; might have noted several references to user friendliness, usability and so forth. I thought it’s time to put our money where our mouth is and talk a little bit about that.&lt;/p&gt;  &lt;p&gt;To start off nice and easy, this post will just be a round-up of interesting links concerning either Usability or User Friendly design, or both.&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Links&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="Usability - Wikipedia" href="http://en.wikipedia.org/wiki/Usability" target="_blank"&gt;Usability according to Wikipedia&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="How C.R.A.P. is your design?" href="http://thinkvitamin.com/design/how-crap-is-your-site-design/" target="_blank"&gt;How C.R.A.P. is your design?&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="Usability First" href="http://www.usabilityfirst.com/" target="_blank"&gt;Usability First&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a title="Usability Blog" href="http://www.usabilityblog.com/" target="_blank"&gt;Usability Blog&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Books&lt;/h4&gt;  &lt;p&gt;Most of those are quite know already so don’t expect to be blown away. Still, might be nice to have them all in a row. None of these are affiliate links, by the way:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="Don’t Make Me Think (by Steve Krug)" href="http://www.amazon.co.uk/Dont-Make-Me-Think-Usability/dp/0321344758/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1308758122&amp;amp;sr=1-1" target="_blank"&gt;Don’t Make Me Think&lt;/a&gt; (by Steve Krug) &lt;/li&gt;    &lt;li&gt;&lt;a title="Rocket Surgery Made Easy: The Do-it-yourself Guide to Finding and Fixing Usability Problems (by Steve Krug)" href="http://www.amazon.co.uk/Rocket-Surgery-Made-Easy-yourself/dp/0321657292/ref=pd_bxgy_b_img_b" target="_blank"&gt;Rocket Surgery Made Easy: The Do-it-yourself Guide to Finding and Fixing Usability Problems&lt;/a&gt; (by Steve Krug) &lt;/li&gt;    &lt;li&gt;&lt;a title="The Inmates Are Running The Asylum (by Alan Cooper)" href="http://www.amazon.co.uk/Inmates-are-Running-Asylum-High-tech/dp/0672326140/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1308758384&amp;amp;sr=1-1" target="_blank"&gt;The Inmates Are Running The Asylum&lt;/a&gt; (by Alan Cooper) &lt;/li&gt;    &lt;li&gt;&lt;a title="About Face 3: Essentials of Interaction Design (by Alan Cooper)" href="http://www.amazon.co.uk/About-Face-Essentials-Interaction-Design/dp/0470084111/ref=pd_bxgy_b_img_b" target="_blank"&gt;About Face 3: Essentials of Interaction Design&lt;/a&gt; (by Alan Cooper) &lt;/li&gt;    &lt;li&gt;&lt;a title="The Design of Everyday Things (by Don Norman)" href="http://www.amazon.co.uk/Design-Everyday-Things-Don-Norman/dp/0465067107/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1308758516&amp;amp;sr=1-1" target="_blank"&gt;The Design of Everyday Things&lt;/a&gt; (by Don Norman) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;That’ll be it for now. If you have any other valuable links, by all means, &lt;a title="Post a comment" href="#commentinput" target="_blank"&gt;Let me know&lt;/a&gt; and I’ll be sure to add them to the list.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:204ce342-ebaa-41fd-af6b-7af1f94d7dca" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-07-13T21:44:36+01:00</a10:updated></item><item><guid isPermaLink="false">simple-time-picker-model-binder-for-aspnet-mvc-3-and-how-to-save-it-to-sql-ce-4-using-ef-41</guid><link>http://www.sharpedgesoftware.com/Blog/2011/06/08/simple-time-picker-model-binder-for-aspnet-mvc-3-and-how-to-save-it-to-sql-ce-4-using-ef-41</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>.NET</category><title>Simple Time Picker model binder for ASP.NET MVC 3, and how to save it to SQL CE 4 using EF 4.1</title><description>&lt;p&gt;There’s plenty of DatePickers out there, like, for instance, the ubiquitous &lt;a title="jQuery DatePicker - Demos &amp;amp; Documentation" href="http://jqueryui.com/demos/datepicker/" target="_blank"&gt;jQuery DatePicker&lt;/a&gt;, but how about Time pickers?     &lt;br /&gt;Well if you’re looking for a fancy, flashy, drop-dead-gorgeous Time picker control… this post isn’t for you. What this post will teach you, dear reader, is how to simply and effectively use two Dropdowns to to model bind hours and minutes to a &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt;&lt;font face="Trebuchet MS"&gt;. This will be the jaw-dropping end result:&lt;/font&gt;&lt;/p&gt;  &lt;p align="left"&gt;&lt;a href="http://www.sharpedgesoftware.com/Blog/Images/image_6001.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://www.sharpedgesoftware.com/Blog/Images/image_thumb_2001.png" width="129" height="74" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h4&gt;The Model and our constraints&lt;/h4&gt;  &lt;p&gt;We’ll set up a very simple model because in this case all I care about is saving the time. Let’s say we have an &lt;font face="Courier New"&gt;Appointment&lt;/font&gt; class, with only an ID, a name and a time:&lt;/p&gt;  &lt;pre class="brush: csharp; toolbar: false;"&gt;using System;
using System.ComponentModel.DataAnnotations;

public class Appointment
{
    public int ID { get; set; }
    
    public string Name { get; set; }
    
    public long Ticks { get; set; }
    
    [NotMapped]
    public TimeSpan Time
    {
        get { return TimeSpan.FromTicks(Ticks); }
        set { Ticks = value.Ticks; }
    }
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;There’s several things going on here. As you can see, I’ve split the representation of time into two properties. The &lt;font face="Courier New"&gt;Time&lt;/font&gt; property itself is calculated from the &lt;font face="Courier New"&gt;Ticks&lt;/font&gt; property (an inherent property of the &lt;a title="TimeSpan structure - MSDN" href="http://msdn.microsoft.com/en-us/library/system.timespan.aspx" target="_blank"&gt;&lt;font face="Courier New"&gt;TimeSpan struct&lt;/font&gt;&lt;/a&gt;). It is also marked with the &lt;a title="NotMappedAttribute class - MSDN" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.notmappedattribute%28v=vs.103%29.aspx" target="_blank"&gt;&lt;font face="Courier New"&gt;NotMappedAttribute&lt;/font&gt;&lt;/a&gt;, which will instruct Entity Framework to not map this property to the database. Instead, we’ll save the &lt;font face="Courier New"&gt;Ticks&lt;/font&gt; property to the database and reconstruct the &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt; from the ticks every time.&lt;/p&gt;

&lt;p&gt;Why make it so hard? It appears that &lt;a title="SQL Server Compact - Team Blog" href="http://blogs.msdn.com/b/sqlservercompact/" target="_blank"&gt;SQL Server Compact 4&lt;/a&gt; does not declare any datatype to represent a &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt;. Hence our workaround. To be honest, I haven’t tried this in SQL Server (the Big Boy edition, I mean), so it could be that you can get away mapping the &lt;font face="Courier New"&gt;TimeSpan &lt;/font&gt;directly. This will definitely work on all versions though.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;The EditorTemplate&lt;/h4&gt;

&lt;p&gt;Next we’ll define what the standard look of our “time picker” will be. Even though we’re saving the &lt;font face="Courier New"&gt;Ticks&lt;/font&gt; property to the database we’ll use the &lt;font face="Courier New"&gt;Time&lt;/font&gt; property for display. The type of the property is &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt; so that’s how we’ll have to name our &lt;a title="Templates in MVC 2 and above - Brad Wilson" href="http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html" target="_blank"&gt;&lt;font face="Courier New"&gt;EditorTemplate&lt;/font&gt;&lt;/a&gt;. Create a new folder in the &lt;font face="Courier New"&gt;Shared&lt;/font&gt; views folder of your application, call it “&lt;font face="Courier New"&gt;EditorTemplates&lt;/font&gt;&lt;font face="Trebuchet MS"&gt;”&lt;/font&gt; and add a partial view called &lt;font face="Courier New"&gt;TimeSpan.cshtml&lt;/font&gt; (or &lt;font face="Courier New"&gt;TimeSpan.ascx&lt;/font&gt; if you’re using the WebFormsViewEngine instead of &lt;a title="Razor View Engine Syntax and more - Phil Haack" href="http://haacked.com/archive/2010/07/03/razor-view-syntax.aspx" target="_blank"&gt;Razor&lt;/a&gt;). You folder structure should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.sharpedgesoftware.com/Blog/Images/image_9.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://www.sharpedgesoftware.com/Blog/Images/image_thumb_3.png" width="213" height="78" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what &lt;font face="Courier New"&gt;TimeSpan.cshtml&lt;/font&gt; will look like in order to render the 2 Dropdowns depicted above:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;@model TimeSpan

@Html.DropDownList(&amp;quot;&amp;quot;, Enumerable.Range(0, 24)
    .Select(i =&amp;gt; new SelectListItem { Value = i.ToString(), 
    Text = i.ToString(), Selected = Model.Hours == i }))&amp;amp;nbsp;:

@Html.DropDownList(&amp;quot;&amp;quot;, Enumerable.Range(0, 60)
    .Select(i =&amp;gt; new SelectListItem { Value = i.ToString(), 
    Text = i.ToString(), Selected = Model.Minutes == i }))&lt;/pre&gt;

&lt;p&gt;In a nutshell, we make &lt;font face="Courier New"&gt;TimeSpan.cshtml&lt;/font&gt; a partial view typed to &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt;, because that is the type of the &lt;font face="Courier New"&gt;Time&lt;/font&gt; property, then we “generate” 2 DropDownLists, the first one with the values 0 to 23 (24 is the upper bound and is not included) for the hours and 0 to 59 for the minutes.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;&lt;/h4&gt;

&lt;h4&gt;Calling the template&lt;/h4&gt;

&lt;p&gt;In order to tell ASP.NET MVC to render our &lt;font face="Courier New"&gt;Time&lt;/font&gt; property using the &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt; Editor template we just need to use the &lt;font face="Courier New"&gt;EditorFor&lt;/font&gt; Html helper. So suppose we have a view called Add in an &lt;font face="Courier New"&gt;AppointmentController&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;@model Appointment

@using(Html.BeginForm()) {
        
    // more fields here...    
    @Html.EditorFor(model =&amp;gt; model.Time)

    &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Hit me!&amp;quot; /&amp;gt;
}&lt;/pre&gt;

&lt;p&gt;That’s it really. ASP.NET MVC will take care of the dirty work of trying to find an Editor Template that matches the type of the &lt;font face="Courier New"&gt;Time&lt;/font&gt; property. Now we just need to bind the value of the two Dropdowns into a single &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt;.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Black magic&lt;/h4&gt;

&lt;p&gt;Well, not really of course; simple model binding at work. Create a new class and call it, for instance, &lt;font face="Courier New"&gt;TimeBinder&lt;/font&gt;. Our editor template will provide us with 2 values once we post the form, one for each Dropdown. The work of &lt;font face="Courier New"&gt;TimeBinder&lt;/font&gt; will be to get the 2 values and return a&amp;#160; &lt;font face="Courier New"&gt;TimeSpan&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;public class TimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        // Ensure there's incomming data
        var key = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider
            .GetValue(key);

        if (valueProviderResult == null || 
            string.IsNullOrEmpty(valueProviderResult
                .AttemptedValue))
        {
            return null;
        }

        // Preserve it in case we need to redisplay the form
        bindingContext.ModelState
            .SetModelValue(key, valueProviderResult);

        // Parse
        var hours = ((string[])valueProviderResult.RawValue)[0];
        var minutes = ((string[])valueProviderResult.RawValue)[1];

        // A TimeSpan represents the time elapsed since midnight
        var time = new TimeSpan(Convert.ToInt32(hours), 
            Convert.ToInt32(minutes), 0);

        return time;
    }
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Final setup&lt;/h4&gt;

&lt;p&gt;Now that we have a binder in place we need to instruct the application to use it. Add the following line to the &lt;font face="Courier New"&gt;Global.asax.cs&lt;/font&gt; file, in the &lt;font face="Courier New"&gt;Application_Start&lt;/font&gt; method:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(TimeSpan), new TimeBinder());

    // route registration code here
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;DropDownLists? Meh.&lt;/h4&gt;

&lt;p&gt;I hear you saying, isn’t it more convenient to just &lt;em&gt;type&lt;/em&gt; the hours and minutes yourself? Why use tedious Dropdowns?&lt;/p&gt;

&lt;p&gt;You’re probably right. The beauty of what we’ve just done is that we now only need to change the &lt;font face="Courier New"&gt;TimeSpan.cshtml&lt;/font&gt; partial view to display two TextBoxes instead of DropDownLists &lt;strong&gt;&lt;em&gt;and it will just work!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don’t believe me? Here’s the new &lt;font face="Courier New"&gt;TimeSpan.cshtml&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;@model TimeSpan

@Html.TextBox(&amp;quot;&amp;quot;, Model.Hours)&amp;amp;nbsp;:
@Html.TextBox(&amp;quot;&amp;quot;, Model.Minutes)&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;ASP.NET MVC will give the TextBoxes the same name it gave the Dropdowns, which means our &lt;font face="Courier New"&gt;TimeBinder&lt;/font&gt; will still be able to fetch the values from the &lt;font face="Courier New"&gt;ValueProvider&lt;/font&gt; and parse them. Quite an example of loose-coupling your presentation layer from your business layer if you ask me! &lt;font face="Courier New"&gt;:)&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Of course, without the Dropdown limiting the range of values a user may input you’d better restrict those TextBoxes to numerical values only, otherwise you’re up for some fancy runtime errors &lt;font face="Courier New"&gt;;)&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Any questions? &lt;a title="Post a comment" href="#commentinput"&gt;Let me know&lt;/a&gt;!&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2298582c-03d1-4ec5-8492-84c77261cae4" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-06-10T13:01:19+01:00</a10:updated></item><item><guid isPermaLink="false">using-dynamic-to-unit-test-an-action-method-that-returns-jsonresult-with-mvc-3-and-c-4</guid><link>http://www.sharpedgesoftware.com/Blog/2011/04/07/using-dynamic-to-unit-test-an-action-method-that-returns-jsonresult-with-mvc-3-and-c-4</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>.NET</category><title>Using dynamic to unit test an Action Method that returns JsonResult with MVC 3 and C# 4</title><description>&lt;p&gt;We’ve all been there, haven’t we? We have an action method that we call through &lt;font face="Consolas"&gt;Ajax.ActionLink&lt;/font&gt;, &lt;font face="Consolas"&gt;Ajax.BeginForm&lt;/font&gt; or even with&lt;font face="Consolas"&gt; &lt;/font&gt;&lt;a title="jQuery.ajax documentation" href="http://api.jquery.com/jQuery.ajax/" target="_blank"&gt;&lt;font face="Consolas"&gt;jQuery.ajax&lt;/font&gt;&lt;/a&gt;, and returning a &lt;a title="JsonResult MSDN documentation" href="http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult.aspx" target="_blank"&gt;&lt;font face="Consolas"&gt;JsonResult&lt;/font&gt;&lt;/a&gt; is what makes the most sense. But whatever you pass to a&amp;#160; JsonResult only gets exposed through the &lt;font face="Consolas"&gt;JsonResult.Data&lt;/font&gt; property which, unfortunately, is of type &lt;font face="Consolas"&gt;object&lt;/font&gt;.&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;JsonResult&lt;/font&gt; is meant to be serialized into a &lt;a title="JSON Syntax and Examples - Wikipedia" href="http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example" target="_blank"&gt;string with Json notation&lt;/a&gt; so it doesn’t matter that &lt;font face="Consolas"&gt;Data&lt;/font&gt; is of type &lt;font face="Consolas"&gt;object&lt;/font&gt;, but, &lt;em&gt;how do you access the properties inside the &lt;font face="Consolas"&gt;Data&lt;/font&gt; object when you want to unit test your view?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;The setup&lt;/h4&gt;  &lt;p&gt;We need an action in a controller that returns a &lt;font face="Consolas"&gt;JsonResult&lt;/font&gt;; it doesn’t matter how it gets called from the view or what we’d do with the result, so let’s keep it simple:&lt;/p&gt;  &lt;pre class="brush: csharp; toolbar: false;"&gt;public ActionResult DoSomething()
{
    var ok = Act();

    var message = ok? &amp;quot;All done!&amp;quot; : &amp;quot;Oops!&amp;quot;;

    return Json(new { Message = message });
}&lt;/pre&gt;

&lt;p&gt;And the unit test:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[TestClass]
public class Test
{
    [TestMethod]
    public void DoSomething_Does_Something()
    {
        // Arrange
        var controller = TestFakes.CreateController();
        
        // Act
        var json = controller.DoSomething() as JsonResult;

        // Assert
        Assert.IsNotNull(json.Data.Message); // --&amp;gt; FAIL!
    }
}&lt;/pre&gt;

&lt;p&gt;The test fails not because &lt;font face="Consolas"&gt;Message&lt;/font&gt; is &lt;font face="Consolas"&gt;null&lt;/font&gt;, but because &lt;font face="Consolas"&gt;json.Data&lt;/font&gt; is of type &lt;font face="Consolas"&gt;System.Object&lt;/font&gt; and &lt;font face="Consolas"&gt;System.Object&lt;/font&gt; doesn’t have a &lt;font face="Consolas"&gt;Message&lt;/font&gt; property, obviously.&lt;/p&gt;

&lt;p&gt;What now? Well, I give it away in the title of this post so it’s hardly a cliff-hanger, is it?&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Dynamic to the rescue&lt;/h4&gt;

&lt;p&gt;Thanks to &lt;a title="Understanding the Dynamic Keyword in C# 4" href="http://visualstudiomagazine.com/articles/2011/02/01/understanding-the-dynamic-keyword-in-c4.aspx" target="_blank"&gt;the magic of statically typing as dynamic in c# 4&lt;/a&gt; this should be a piece of cake. Let’s modify the test method:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[TestClass]
public class Test
{
    [TestMethod]
    public void DoSomething_Does_Something()
    {
        // Arrange
        var controller = TestFakes.CreateController();
        
        // Act
        var json = controller.DoSomething() as JsonResult;
        
        // Dynamic magic: just assign the Data property
        // to a variable of type dynamic!
        dynamic data = json.Data;
        
        // And get our message out of it.
        string msg = data.Message;

        // Assert
        Assert.AreEqual(&amp;quot;All done!&amp;quot;, msg); // --&amp;gt; OK!
    }
}&lt;/pre&gt;

&lt;p&gt;It’s that simple: just assign the &lt;font face="Consolas"&gt;Data&lt;/font&gt; object to a variable of type &lt;font face="Consolas"&gt;dynamic&lt;/font&gt;, then access the &lt;font face="Consolas"&gt;Message&lt;/font&gt; property. Note that I cannot declare the variable &lt;font face="Consolas"&gt;msg&lt;/font&gt; as &lt;font face="Consolas"&gt;var&lt;/font&gt;. That’s because&lt;font face="Consolas"&gt; data.Message&lt;/font&gt; is a dynamic expression that will be resolved at run time, so the compiler wouldn’t know what to substitute &lt;font face="Consolas"&gt;var&lt;/font&gt; for at compile time.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Er, it doesn’t work&lt;/h4&gt;

&lt;p&gt;If you actually run this test, you’ll get an &lt;font face="Consolas"&gt;&amp;quot;object does not contain a definition for Message&amp;quot;&lt;/font&gt; error. Oops. Didn’t we convert &lt;font face="Consolas"&gt;json.Data&lt;/font&gt; to a &lt;font face="Consolas"&gt;dynamic&lt;/font&gt; object? Well, yes but…&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Anonymous types are internal&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;&lt;font face="Consolas"&gt;JsonResult&lt;/font&gt;&lt;/code&gt; returns an &lt;a title="Anonymous Types in C# 3.0" href="http://msdn.microsoft.com/en-us/library/bb397696.aspx" target="_blank"&gt;anonymous object&lt;/a&gt; and these are, by default, &lt;code&gt;&lt;font face="Consolas"&gt;internal&lt;/font&gt;&lt;/code&gt;, so they need to be made visible to the tests project.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;The solution&lt;/h4&gt;

&lt;p&gt;This is, fortunately, very very simple to solve. &lt;/p&gt;

&lt;p&gt;Assuming you have your test classes in an assembly called MyProject.Tests,&amp;#160; find the file &lt;code&gt;&lt;font face="Consolas"&gt;AssemblyInfo.cs&lt;/font&gt;&lt;/code&gt; in the &lt;font face="Consolas"&gt;Properties&lt;/font&gt; folder in your MVC project. Open &lt;font face="Consolas"&gt;AssemblyInfo.cs&lt;/font&gt; and add the following line to the end of the file:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[assembly: InternalsVisibleTo(&amp;quot;MyProject.Tests&amp;quot;)]&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Do you know of a better way? Any questions? &lt;a title="Post a comment" href="#commentinput" target="_blank"&gt;Let me know&lt;/a&gt;!&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:1e03ae85-289a-43be-ad89-4773fa9e6b29" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-05-16T19:06:55+01:00</a10:updated></item><item><guid isPermaLink="false">mocking-a-controllercontext-with-authenticated-user-with-moq-for-aspnet-mvc-3</guid><link>http://www.sharpedgesoftware.com/Blog/2011/03/14/mocking-a-controllercontext-with-authenticated-user-with-moq-for-aspnet-mvc-3</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>.NET</category><title>Mocking a ControllerContext with authenticated user with Moq for ASP.NET MVC (3)</title><description>&lt;p&gt;Whenever you are writing unit tests or &lt;a title="BEhaviour Driven Development" href="http://en.wikipedia.org/wiki/Behavior_Driven_Development" target="_blank"&gt;BDD&lt;/a&gt;-style specs for your ASP.NET MVC controllers (you &lt;em&gt;are, right&lt;/em&gt;?) there will come a moment when you actually need to simulate that a user is authenticated to your site.&lt;/p&gt;  &lt;p&gt;Even if you’re familiar with mocking, letting the controller think someone has logged in to your site might not be straight forward. Fear no more.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Mocking&lt;/h4&gt;  &lt;p&gt;I’ll be using &lt;a title="Moq Quick Start" href="http://code.google.com/p/moq/wiki/QuickStart" target="_blank"&gt;Moq&lt;/a&gt; as my mocking framework. I’ve tried &lt;a title="Rhino Mocks" href="http://www.ayende.com/projects/rhino-mocks.aspx" target="_blank"&gt;RhinoMocks&lt;/a&gt; in the pas but I find it personally to verbose, but what I’ll show you here should be very easily translated to RhinoMocks or any other ol’ mocking framework out there.&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;h4&gt;Failing test&lt;/h4&gt;  &lt;div&gt;So let’s say the controller looks like this:&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;pre class="brush: csharp; toolbar: false;"&gt;public class AdminController : Controller
{
    [Authorize]
    public ActionResult ViewProfile()
    {
        // pass the authorized user name to the view
        var username = User.Identity.Name;

        return View(username);
    }
}&lt;/pre&gt;

&lt;p&gt;If we want to test the &lt;font face="Consolas"&gt;ViewProfile&lt;/font&gt; action, the unit test will fail:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[Subject(&amp;quot;AdminController&amp;quot;)]
public class When_the_profile_page_is_requested
{
    static AdminController controller;
    static string username;

    Establish context = () =&amp;gt;
    {
        controller = new AdminController();
        username = &amp;quot;Sergi&amp;quot;;
    }

    Because of = () =&amp;gt; result = controller.ViewProfile();

    It should_know_the_username = () =&amp;gt;
        result.Model&amp;lt;string&amp;gt;().ShouldEqual(&amp;quot;Sergi&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;I’m using &lt;a title="Machine.Specifications (MSpec)" href="https://github.com/machine/machine.specifications" target="_blank"&gt;MSpec&lt;/a&gt; with &lt;a title="James Broome’s Machine.Specifications.MVC extensions" href="http://jamesbroo.me/introducing-machinespecificationsmvc/" target="_blank"&gt;James Broome’s Machine.Specifications.MVC extensions&lt;/a&gt; for the specs (tests) here. If you’re not familiar with MSpec, don’t panic, just know that the &lt;font face="Consolas"&gt;Establish&lt;/font&gt;, &lt;font face="Consolas"&gt;Because&lt;/font&gt; and &lt;font face="Consolas"&gt;It&lt;/font&gt; correspond to &lt;a title="Arrange, Act and Assert" href="http://www.arrangeactassert.com/why-and-what-is-arrange-act-assert/" target="_blank"&gt;Arrange, Act and Assert&lt;/a&gt; of traditional TDD.&lt;/p&gt;

&lt;p&gt;But this spec will obviously fail because we’ve marked our action with the &lt;font face="Consolas"&gt;&lt;a title="AuthorizeAttribute class on MSDN" href="http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx" target="_blank"&gt;Authorize &lt;font face="Trebuchet MS"&gt;attribute&lt;/font&gt;&lt;/a&gt;&lt;/font&gt; and even if we hadn’t we’re trying to get the logged in username through the controller’s &lt;font face="Consolas"&gt;User&lt;/font&gt; property, which will be &lt;font face="Consolas"&gt;null&lt;/font&gt; when no user has logged in.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Getting it to pass&lt;/h4&gt;

&lt;p&gt;So how do we set our controller up?&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[Subject(&amp;quot;AdminController&amp;quot;)]
public class When_the_profile_page_is_requested
{
    static AdminController controller;

    Establish context = () =&amp;gt;
    {
        controller = new AdminController();

        var controllerContext = new Mock&amp;lt;ControllerContext&amp;gt;();

        // Just fake the name of the user we want to
        // &amp;quot;authenticate&amp;quot;
        controllerContext.SetupGet(x =&amp;gt; 
            x.HttpContext.User.Identity.Name).Returns(&amp;quot;Sergi&amp;quot;);

        // And tell the controllerContext that, sure,
        // we've logged in allright...
        controllerContext.SetupGet(x =&amp;gt; 
            x.HttpContext.User.Identity.IsAuthenticated)
            .Returns(true);

        controllerContext.SetupGet(x =&amp;gt; 
            x.HttpContext.Request.IsAuthenticated)
            .Returns(true);

        // now that we've set up the controllerContext
        // pass it to the controller
        controller.ControllerContext = controllerContext.Object;
        
        // As a bonus, we initialize the Url helper
        // property of the controller as well
        var context = 
            new Mock&amp;lt;HttpContextBase&amp;gt;(MockBehavior.Strict);

        controller.Url = 
            new UrlHelper(new RequestContext(context.Object, 
            new RouteData()), new RouteCollection());
    }

    Because of = () =&amp;gt; result = controller.ViewProfile();

    It should_know_the_username = () =&amp;gt;
        result.Model&amp;lt;string&amp;gt;().ShouldEqual(&amp;quot;Sergi&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;A controller exposes the current &lt;font face="Consolas"&gt;HttpContext&lt;/font&gt; through the &lt;font face="Consolas"&gt;ControllerContext&lt;/font&gt; property. Here we tell Moq to set up only certain properties of &lt;font face="Consolas"&gt;ControllerContext&lt;/font&gt;; only the ones we’re going to use. &lt;/p&gt;

&lt;p&gt;That’s what the &lt;font face="Consolas"&gt;SetupGet&lt;/font&gt; method does. 

  &lt;br /&gt;For instance on line 13 we’re saying: “when someone calls &lt;font face="Consolas"&gt;ControllerContext.HttpContext.User.Identity.Name&lt;/font&gt;, return the value we’re specifying,&amp;#160; “Sergi” in this case”.&lt;/p&gt;

&lt;p&gt;The User property on the Controller class actually exposes this same &lt;font face="Consolas"&gt;ControllerContext.HttpContext.User&lt;/font&gt; object.&lt;/p&gt;

&lt;p&gt;When all is set up we need to pass the &lt;font face="Consolas"&gt;ControllerContext&lt;/font&gt; to the &lt;font face="Consolas"&gt;Controller&lt;/font&gt;; that’s what happens on line 28. Why are we actually calling &lt;font face="Consolas"&gt;controllerContext.Object&lt;/font&gt;? Well, if you look where we initialize the controllerContext variable we really create a &lt;font face="Consolas"&gt;Moq.Mock&amp;lt;T&amp;gt;&lt;/font&gt; object. &lt;font face="Consolas"&gt;Mock&amp;lt;T&amp;gt;&lt;/font&gt; exposes the real object &lt;font face="Consolas"&gt;T&lt;/font&gt; through the &lt;font face="Consolas"&gt;Object&lt;/font&gt; property, which is exactly what out controller needs.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;I hope this helps. Any questions? &lt;a title="Post a comment" href="http://www.sharpedgesoftware.com/Blog/2011/02/27/dealing-with-javascript-or-json-result-after-and-ajax-call-with-ajaxactionlink-unobtrusive-ajax-and-#commentinput"&gt;Let me know&lt;/a&gt;!&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:95f037a6-64e2-455f-a0ad-75523a25f677" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-03-14T22:25:41Z</a10:updated></item><item><guid isPermaLink="false">dealing-with-javascript-or-json-results-after-an-ajax-call-with-ajaxactionlink-unobtrusive-ajax-and-</guid><link>http://www.sharpedgesoftware.com/Blog/2011/02/27/dealing-with-javascript-or-json-results-after-an-ajax-call-with-ajaxactionlink-unobtrusive-ajax-and-</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>.NET</category><title>Dealing with javascript or JSON results after an AJAX call with Ajax.ActionLink, unobtrusive AJAX and MVC 3</title><description>&lt;p&gt;I’ve recently updated an MVC 3 project to use &lt;a title="Brad Wilson on unobtrusive ajax" href="http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-ajax.html" target="_blank"&gt;unobtrusive ajax&lt;/a&gt;. If you create a new ASP.NET MVC 3 project unobtrusive ajax will be enabled by default, but this was a project I had once migrated from MVC 2. Instead of physically adding the unobtrusive ajax JavaScript file to my solution I got it from the &lt;a title="Microsft Ajax Content Delivery Network" href="http://www.asp.net/ajaxlibrary/cdn.ashx#ASPNET_MVC_Releases_on_the_CDN_7" target="_blank"&gt;Microsoft Ajax CDN&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The unobtrusive ajax libraries not only leave your html cleaner by using the HTML 5 compatible “data-” attribute, but return a much clearer set of results objects from the controller.&lt;/p&gt;  &lt;p&gt;The latter was, for me, a great relief, because I always ended up taking care of responses to ajax calls in several different ways within one application. Do I return strings from the controller action or do I go with Json? Or should I always return a &lt;font face="Consolas"&gt;HttpStatusCodeResult&lt;/font&gt;?     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;I’ve finally found a pattern, for lack of a better word, that I find clean, clear and consistent. Here’s how.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Calling the controller&lt;/h4&gt;  &lt;p&gt;Imagine we want to make an ajax call to a controller to, say, change the status of an order. In our view we simply do:&lt;/p&gt;  &lt;pre class="brush: js; toolbar: false;"&gt;@Ajax.ActionLink(&amp;quot;Set to pending&amp;quot;, &amp;quot;setstatus&amp;quot;, &amp;quot;order&amp;quot;, 
    new { id = Model.ID, status = 0 }, new AjaxOptions 
        { OnFailure = &amp;quot;Error&amp;quot;, OnSuccess = &amp;quot;StatusChanged&amp;quot;, 
            HttpMethod = &amp;quot;POST&amp;quot; })&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Two things to notice in the AjaxOptions object:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I explicitly set the HttpMethod to POST. We will be returning a Json object from the controller and the unobtrusive ajax library “encourages” us to avoid going to the server with a GET request for security reasons. You’ll know you have this problem because an exception will be thrown saying “&lt;font size="2" face="Consolas"&gt;This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.&lt;/font&gt;” &lt;/li&gt;

  &lt;li&gt;I’ve defined two callback methods, one for error and another for success. These methods will be passed a default set of arguments by the unobtrusive ajax library which we will be able to use from our action method to return the status of the operation and any meaningful messages we deem necessary. These are the method signatures:&amp;#160; &lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="brush: js; toolbar: false;"&gt;function Error(response, status, error) {
}

function StatusChanged(response, status, data) {
} &lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Action&lt;/h4&gt;

&lt;p&gt;We want our action to give a meaningful error message when things go wrong, and to return for instance the id and new status of the order if everything goes OK.&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false;"&gt;[HttpPost]
public ActionResult SetStatus(int id, int status)
{
    try
    {
       // Code to update the order status here

        return Json(new
        {
            ID = id, 
            NewStatus = order.StatusDescription
        });
    }
    catch
    {
        return new HttpStatusCodeResult(418, 
            &amp;quot;Couldn't change the status of the order&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;font face="Trebuchet MS"&gt;Notice how we’ve marked our action to accept&lt;/font&gt; &lt;font face="Consolas"&gt;HttpPost&lt;/font&gt;&lt;font face="Trebuchet MS"&gt; request only? This is of course because we specified POST as the HttpMethod in our ActionLink to solve &lt;font face="Consolas"&gt;JsonReuqestBehavior&lt;/font&gt; problem mentioned above. Another solution is to ignore the Http verbs and methods altogether and add &lt;font face="Consolas"&gt;JsonRequestBehavior .AllowGet&lt;/font&gt; as second parameter of the Json result.&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Dealing with the results&lt;/h4&gt;

&lt;p&gt;Imagine we’ve just changed the status successfully; our action method returns a Json result containing an anonymous type with two properties, ID and NewStatus. We can define these with whatever name we like, or even create a property that is itself an anonymous type. It will all be serialized to Json by ASP.NET MVC. How do we use these on the view? Quite easy really:&lt;/p&gt;

&lt;pre class="brush: js; toolbar: false;"&gt;function StatusChanged(response, status, data) {
    alert(&amp;quot;order #:&amp;quot; + response.ID + &amp;quot;has a new status: &amp;quot; 
        + response.NewStatus);
}&lt;/pre&gt;

&lt;p&gt;Of course, you’d want to do something a tad more meaningful with your results, but the essence of it is this: The properties you defined in your anonymous type are directly available through the &lt;font face="Consolas"&gt;response&lt;/font&gt; parameter. Had you defined a property that was itself an anonymous type, named for instance &lt;font face="Consolas"&gt;Extras&lt;/font&gt;, with other properties in it, you’d simply do &lt;font face="Consolas"&gt;response.Extras.WhateverProperty&lt;/font&gt;.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;And if things go south?&lt;/h4&gt;

&lt;p&gt;As you can see we have a nice &lt;font face="Consolas"&gt;try..catch&lt;/font&gt; in our action. When an exception is thrown or there’s an error we want to signal we need make it known in the response. That basically means returning a status code other than 200 (“OK”). Here I’m returning the &lt;a href="http://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol" target="_blank"&gt;Http Status Code 418: “I’m a&amp;#160; teapot”&lt;/a&gt; :þ I promise it is a valid http status code; if you don’t believe me, &lt;a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes" target="_blank"&gt;check Wikipedia&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Anyway, when returning a status code other than 200 our Error function will be called. How doe we deal with the error message? As easy as before:&lt;/p&gt;

&lt;pre class="brush: js; toolbar: false;"&gt;function Error(response, status, error) {
    alert(&amp;quot;Oops! &amp;quot; + response.statusText);
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;So there you have it. Do you know of a better/different way? &lt;a href="#commentinput"&gt;Let me know&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e65c8344-3a60-421d-a782-ce236af02022" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-03-21T20:41:22Z</a10:updated></item><item><guid isPermaLink="false">how-to-add-openid-authentication-to-your-aspnet-mvc-3-site-using-janrain-engage</guid><link>http://www.sharpedgesoftware.com/Blog/2011/02/21/how-to-add-openid-authentication-to-your-aspnet-mvc-3-site-using-janrain-engage</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>.NET</category><category>Would Be Better</category><title>How to add OpenID authentication to your ASP.NET MVC 3 site using Janrain Engage</title><description>&lt;p&gt;Well, I finally took the time to implement OpenID/Social network log-in functionality to &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/"&gt;Would Be Better&lt;/a&gt; and although I had anticipated a much more troublesome process, it wasn’t entirely clear how I had to proceed on several of the steps either. I’d like to share my experiences with you.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Why.&lt;/h4&gt;  &lt;p&gt;After reading Rob Conery’s &lt;a href="http://blog.wekeroad.com/thoughts/open-id-is-a-party-that-happened"&gt;horror story about OpenID&lt;/a&gt; support for &lt;a href="http://www.tekpub.com/"&gt;Tekpub&lt;/a&gt;, whay on earth did I decide to go ahead with implementing it for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/"&gt;Would Be Better&lt;/a&gt;? Well, I figured that people would not quite enjoy the idea of having to create yet another account, with it’s corresponding username and password just to be able to use my puny site. At this point I have to remove all possible entry barriers as it is hard enough getting potential users to sign up, so I assumed that allowing people to sign up/in with their &lt;a href="http://www.facebook.com/"&gt;Facebook&lt;/a&gt;, &lt;a href="http://www.live.com"&gt;Windows Live&lt;/a&gt; or &lt;a href="http://www.gmail.com"&gt;Gmail&lt;/a&gt; account might help things along.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;How.&lt;/h4&gt;  &lt;p&gt;I’m sure there are various ways to allow your users to sign in to your site with openID but having seen several sites using the &lt;a href="http://www.janrain.com/products/engage"&gt;Janrain Engage&lt;/a&gt; widget, including Tekpub, I thought I’d take a look. It turns out they have a &lt;em&gt;free&lt;/em&gt; Basic plan for up to 2500 users, and since the day that Would Be Better actually has 2500 users is for now only a wet dream I went ahead and signed up.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Initial setup&lt;/h4&gt;  &lt;p&gt;The URL where Janrain Engage will send the authentication response is set up when generating the code for the widget. So, Imagine we have an ASP.NET MVC application call MyMVCApp (-1 for originality, I know), and in there we have an Account controller, and we want the Authenticate action to handle Janrain’s response. This is how our widget generation page looks like right now:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.sharpedgesoftware.com/Blog/Images/image_thumb3_thumb_2001.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image_thumb3_thumb" border="0" alt="image_thumb3_thumb" src="http://www.sharpedgesoftware.com/Blog/Images/image_thumb3_thumb_thumb001.png" width="612" height="480" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you follow the instructions on the page and “place the code directly in the page where you’d like widget to appear you’re good to go. Almost.    &lt;br /&gt;You’ll have to choose some providers next. Some of them require some rather annoying set up, and it is rather unfortunate that a couple of the most popular providers are among those. Would you wanna implement social network login in your site without actually offering Facebook or Windows Live (Hotmail)? Didn’t think so.&lt;/p&gt;  &lt;p&gt;In case you’re wondering, these are the providers we chose for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/"&gt;Would Be Better&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.sharpedgesoftware.com/Blog/Images/image_thumb5_thumb_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image_thumb5_thumb" border="0" alt="image_thumb5_thumb" src="http://www.sharpedgesoftware.com/Blog/Images/image_thumb5_thumb_thumb.png" width="352" height="193" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Facebook requires you to create a Facebook app, and Janrain requires you to register an application with Windows Live. The latter can be a bit confusing, because you’ll have to provide the Janrain domain (something like https://mymvcapp.rpxnow.com/) &lt;em&gt;instead of your own domain&lt;/em&gt; when registering the Windows Live app. This makes it impossible for Windows Live to “verify your app”, but it turns out it’s not necessary for the widget to work properly.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Receiving Data&lt;/h4&gt;  &lt;p&gt;Finally, what you, in all likelihood, came here for; it’s time to get this baby to talk back to us.&lt;/p&gt;  &lt;p&gt;First, get the &lt;a title="C# Helper Class" href="https://github.com/janrain/Janrain-Sample-Code/blob/master/c-sharp/csharp-helper-class.cs" target="_blank"&gt;C# helper class&lt;/a&gt; provided by Janrain, called Rpx, and add it to your Visual Studio solution. Now we can create the action method Janrain will talk to: go to your AccountController and add the following action:&lt;/p&gt;  &lt;pre class="brush: csharp; toolbar: false;"&gt;public ActionResult Authenticate(string token)
{
    if(!string.IsNullOrEmpty(token))
    {
        var rpx = new Rpx(&amp;quot;Insert Janrain API key here&amp;quot;, 
            &amp;quot;https://mymvcapp.rpxnow.com/&amp;quot;);
        var response = rpx.AuthInfo(token);

        var parser = new RpxResponseParser(response);

        if (parser.Status == RpxReponseStatus.Ok)
        {
            var responseUser = parser.BuildUser();
            return AuthAndRedirect(responseUser);
        }
    }

    ViewBag.Message = &amp;quot;There was a problem signing you in.&amp;quot; 
        + &amp;quot;Verify your credentials and try again.&amp;quot;;

    return RedirectToAction(&amp;quot;create&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;OK, so what’s going on here? Janrain will post a response to our action including an authentication token. We simply get the token and use it to call the AuthInfo method on the Rpx helper class we got from Janrain, which will return a nicely formatted XmlElement with some information about the user that has just logged in.&lt;/p&gt;

&lt;p&gt;And that &lt;em&gt;RpxReponseParser&lt;/em&gt;? That’s just a small helper class I put together that uses LINQ to XML to help me parse the xml response and return a User object with the Username, email, openID and display name filled in. If you want, &lt;a title="RpxResponseParser class" href="http://www.sharpedgesoftware.com/Downloads/RpxResponseParser.zip" target="_blank"&gt;download the RpxReponseParser class, along with the RpxReponseStatus enumeration&lt;/a&gt;, but remember you’ll have to create the User class yourself.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h4&gt;Wrapping up&lt;/h4&gt;

&lt;p&gt;As you might have gathered, this code is, with minor adjustments to post it here, straight from the &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/" target="_blank"&gt;Would Be Better&lt;/a&gt; codebase. So what’s up with the AuthAndRedirect method? Well, at Would Be Better we support both traditional username/password accounts and, recently, openID/social network login account. 

  &lt;br /&gt;Since we added social network login support much later that regular username/password accounts, we actually wanted to enable anyone to be able to login with both types of account because, let’s face it, one-click login with &lt;a href="https://www.myopenid.com/" target="_blank"&gt;MyOpenID&lt;/a&gt; is that much easier that typing your username and password. To avoid people with duplicate accounts , once you login with whichever method we try and synch user accounts based (mainly) on e-mail address. That little bit of black magic happens in the AuthAndRedirect method.&lt;/p&gt;

&lt;p&gt;I hope this helps. 
  &lt;br /&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8512deb5-9e6f-44e1-91e5-72a6f2bbd98d" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-02-23T07:56:10Z</a10:updated></item><item><guid isPermaLink="false">moving-wouldbebettercom-away-from-windows-azure-to-traditional-hosting</guid><link>http://www.sharpedgesoftware.com/Blog/2011/02/17/moving-wouldbebettercom-away-from-windows-azure-to-traditional-hosting</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Life, The Universe and Everything</category><category>Would Be Better</category><title>Moving WouldBeBetter.com away from Windows Azure to traditional hosting</title><description>&lt;p&gt;It just happened; the Name Server changes appear to have definitely propagated a couple of minutes ago. Why did I decide to abandon &lt;a title="Windows Azure" href="http://www.microsoft.com/windowsazure/windowsazure/" target="_blank"&gt;Windows Azure&lt;/a&gt; in favour of a traditional hosting for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/"&gt;Would Be Better&lt;/a&gt;? There is one reason and one reason only: Money.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Hard facts&lt;/h4&gt;  &lt;p&gt;I’m not going to name any figures, but when looking through the Windows Azure invoices of the last couple of months I realised I could buy a year of traditional hosting &lt;em&gt;including 2 SQL Server database &lt;/em&gt;for &lt;strong&gt;2 months worth of Azure! &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This was yesterday. That’s right; it took me all of 5 minutes to reach a conclusion, and the only thing that stopped me from migrating the site yesterday already is that the new hosting provider, &lt;a href="http://www.discountasp.net"&gt;DiscountASP.Net&lt;/a&gt; (the same one hosting &lt;em&gt;this&lt;/em&gt; site) needed an hour or 2 to activate the new account.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Being fair&lt;/h4&gt;  &lt;p&gt;Is Windows Azure a bad platform? No, of course not. It is extremely cool if you ask me and I’m really happy I even took the time to deploy a live app on it. I just think it doesn’t make sense for &lt;a title="Would Be Better.com - Everything can be improved!" href="http://www.wouldbebetter.com/"&gt;Would Be Better&lt;/a&gt;&amp;#160;&lt;em&gt;yet&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;And in all fairness, it could be I was doing lots of things wrong and driving the price up unnecessarily, but even reducing the number of databases (3: the main db, one for reporting and one for membership. yeah, yeah, I got carried away. Maybe. :þ), or choosing Extra Small Instances (yes, plural, your need at least to instances to comply with the SLA) would not make up for the &lt;em&gt;hundreds of €’s &lt;/em&gt;I’ll save per year by moving to regular hosting.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;Ever going back to Azure?&lt;/h4&gt;  &lt;p&gt;I most definitely hope I have to, but it will only happen when it makes sense. When is that? Well, I think Azure could be a terrific investment if you have, for instance, large hardware needs. It would probably be cheaper to pay for an Azure subscription than buying equivalent hardware (plus you spare yourself some system administration work if you go the Azure route, of course).&lt;/p&gt;  &lt;p&gt;If Would Be Better generated huge amounts of traffic, or even better, money, I would have quite definitely stayed on Windows Azure; unfortunately, both things are quite a long way away.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;What I’ll miss&lt;/h4&gt;  &lt;p&gt;Easy. Two things mainly: &lt;/p&gt;  &lt;p&gt;1) The incredible Staging/Production environments: That’s right, with every Azure subscription you get the ability to deploy your app to a Staging environment, and when you decide it’s stable, promote it to production &lt;strong&gt;&lt;em&gt;with no downtime&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;2) Being able to say I’ve got an app hosted on Windows Azure &lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://www.sharpedgesoftware.com/Blog/Images/wlEmoticon-winkingsmile_2.png" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;What I won’t miss&lt;/h4&gt;  &lt;p&gt;This one’s easy too: Having to wait 10 to 20 minutes (10 to 20!) for a deployment to complete, plus another 5 when you want to promote it to production. This one just drove me insane every time. Imagine what happens when you realize you have a typo in one of your views, or discover a small error in a JavaScript file. Despair, that’s what.&lt;/p&gt;  &lt;p&gt;And being fair again, I’ve seen de deployment times go down over the last couple of months so it could just be that &lt;a href="http://www.wouldbebetter.com/suggestion/20/windows-azure-deployment/would-be-better-if-it-didnt-take-so-ridiculously-long" target="_blank"&gt;somebody is listening&lt;/a&gt;… &lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://www.sharpedgesoftware.com/Blog/Images/wlEmoticon-smile_2.png" /&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d0e7ed91-a824-46c3-9ba6-b155c049a096" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-02-17T15:35:20Z</a10:updated></item><item><guid isPermaLink="false">would-be-bettercom</guid><link>http://www.sharpedgesoftware.com/Blog/2010/12/06/would-be-bettercom</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Development</category><category>SharpEdge Software</category><category>Would Be Better</category><title>Would Be Better.com!</title><description>&lt;p&gt;The world is full of great, even wonderful things; be it material things, emotions, states of mind... but Everything can be improved. We knew that much, and although we certainly don't know how to improve everything, we know you do. &lt;a href="http://www.wouldbebetter.com"&gt;Would Be Better&lt;/a&gt; is the place where you suggest how to improve the world; one thing at a time... &lt;/p&gt;  &lt;p&gt;That's right, we've launched &lt;a href="http://www.wouldbebetter.com"&gt;Would Be Better.com&lt;/a&gt;, a micro community site were everybody can make a suggestion on how to improve anything that comes to their minds. Head over there, create an account and start making suggestions. &lt;/p&gt;  &lt;p&gt;And while you're there, bask and rejoice in the beauty of the great job the folks at &lt;a href="http://www.pixeo.be"&gt;Pixeo&lt;/a&gt; have done again at styling the site ; )&lt;/p&gt;  &lt;p&gt;Remember, &lt;em&gt;Everything can be improved!&lt;/em&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:a1d751d9-a4af-4f40-b41f-7c615d38501d" class="wlWriterSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-02-15T23:54:45Z</a10:updated></item><item><guid isPermaLink="false">eternal-debate-20-will-the-web-replace-the-desktop</guid><link>http://www.sharpedgesoftware.com/Blog/2008/01/17/eternal-debate-20-will-the-web-replace-the-desktop</link><a10:author><a10:name>Sergi Papaseit</a10:name></a10:author><category>Life, The Universe and Everything</category><category>SharpEdge Software</category><title>Eternal Debate 2.0: Will the Web replace the Desktop?</title><description>&lt;p&gt;It started somewhere in the (very) late ’90, faded away in shame for a while after the Big Burst and, what do you know, it came back with a good dose of supervitamin A(jax) and superminerals provided by the advent of Web 2.0: The Web will make the Desktop a thing of the past. Again.&lt;/p&gt;  &lt;p&gt;Now, I know I’m not touching a super &lt;i&gt;hot&lt;/i&gt; issue here, but since I only ever read about it from known and sometimes even respected Web 2.0 developers/companies who have, naturally enough, an extremely biased view on the matter, I decided to approach it form the other side: The view of an anonymous Windows &lt;b&gt;&lt;i&gt;and&lt;/i&gt;&lt;/b&gt; Web developer who disagrees with them. &lt;/p&gt;  &lt;p&gt;(Side Note: no Web 2.0 developers, respected or otherwise will be (really) damaged during this rant.) &lt;/p&gt;  &lt;p&gt;First off, I don’t even &lt;i&gt;know&lt;/i&gt; why such a debate should ever even arise. Twice. I don’t know what it is with the Web and internet, but It seems as though every new thing, &lt;i&gt;every step forward&lt;/i&gt;, triggers some as of yet undiscovered testosterone reservoir in tech journalists’ brains that makes them claim that this time&lt;i&gt; &lt;/i&gt;hell will &lt;i&gt;really&lt;/i&gt; break loose, the end of the world as we know it! And god forbid you miss that train because it is the last one! &lt;/p&gt;  &lt;p&gt;“Now departing: Last train out of Stoneageville! Last train! LAST train! Will you just hop in?!?” &lt;/p&gt;  &lt;p&gt;What I consistently fail to understand is this need to confront these two environments that for all I know coexist in perfect harmony when left be.    &lt;br /&gt;Of course, there are some people out there, by which I mean Google, who would just totally love it if the Desktop, by which I mean Microsoft, would disappear. Mind you, that might be what drove them to revolutionise the web landscape with &lt;a href="http://maps.google.com"&gt;Google Maps&lt;/a&gt; in the first place. &lt;/p&gt;  &lt;p&gt;Google Engineer #1: I know! Let’s get rid of Microsoft! And Apple! And Linux! Let’s get Rid Of The Desktop!    &lt;br /&gt;Google Engineer #2: Cool! But… er… how are we actually going to develop &lt;i&gt;anything&lt;/i&gt; after that?     &lt;br /&gt;GE #1: Oh, don’t worry; we’re halfway through Google OS. Beta.     &lt;br /&gt;GE #2: What about BeOS?     &lt;br /&gt;GE #1: Shut up. &lt;/p&gt;  &lt;p&gt;So, for the big one: Will the Web, the thin client, make the thick client a thing of the past? I think that’s a right pile of bullshit. Period. &lt;/p&gt;  &lt;p&gt;Don’t get me wrong here, I am, by no means, criticising Web applications. I think there’s a bunch of &lt;i&gt;really cool&lt;/i&gt; web apps out there, and many kudos to &lt;a href="http://www.37signals.com"&gt;37Signals&lt;/a&gt;, &lt;a href="http://www.gmail.com"&gt;Gmail&lt;/a&gt;, &lt;a href="http://www.digg.com/"&gt;Digg&lt;/a&gt;, &lt;a href="http://www.litmusapp.com"&gt;Litmus&lt;/a&gt; (formerly SiteVista), and many others I’m forgetting, I just think people need to get a grip because some things are plain far fetched. &lt;/p&gt;  &lt;p&gt;Someone, somewhere, even theorised (or proposed?) that the future operating systems would shrink immensely and become just a platform for running our highly evolved, super capable web browsers. Puh-lease! I think someone should try and &lt;i&gt;leave&lt;/i&gt; his web browser alone from time to time.     &lt;br /&gt;And why is it always the “web” side of the story that has murderous thoughts about its fatter relative and not the other way around? For all I know the Desktop has always embraced the web; recognised the potential of cooperation. Per la &lt;i&gt;Familgia&lt;/i&gt;. &lt;/p&gt;  &lt;p&gt;I understand the underlying thought, that the new web applications help build an ever connected world where you data is accessible from anywhere, at any moment, by any Google employee.    &lt;br /&gt;But to say we’ll be going back to thin clients, back to terminal era...     &lt;br /&gt;    &lt;br /&gt;- But why would you &lt;i&gt;need&lt;/i&gt; anything else if your browser can provide everything you need and your data is stored in servers that are permanently available to you from &lt;i&gt;anywhere&lt;/i&gt;?     &lt;br /&gt;- And what about confidential data? Stuff you’d rather keep an eye on at all times?     &lt;br /&gt;- Well, you could always save it on your Hard Drive, I suppose…     &lt;br /&gt;- On what &lt;i&gt;file system&lt;/i&gt;?     &lt;br /&gt;- Er… &lt;/p&gt;  &lt;p&gt;And that might be quite a simplistic rebate, I know, but so is their theory.    &lt;br /&gt;What seems obvious to me is that both environments, both worlds complement each other and are meant to share some space in our digital lives. Deal with it.&lt;/p&gt;    &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:187841bf-2cfb-4845-87be-59bdc459f829" class="wlWriterEditableSmartContent"&gt;&lt;/div&gt;</description><a10:updated>2011-02-15T13:10:14Z</a10:updated></item></channel></rss>