Welcome to MSDN Blogs Sign in | Join | Help

Don’t Assume

Just fixed a bug where a query being issued from my service to Azure table storage was returning no rows.  I have Cerbrata’s most excellent Cloud Storage Studio running in another window and when I issued the query in that window, it returned 14 rows.  Why isn’t my app working?

After poking around and trying a couple of things, I decided to issue exactly  the same query from Cloud Storage Studio as my app was issuing.  To do this, I fired up Fiddler and ran the app to capture the GET request from my app; it looks like this:

(((PartitionKey eq 'WSF') and (TerminalFrom eq 'Seattle')) and

(TerminalTo eq ' Bainbridge')) and (Departure ge datetime'2010-02-07T21:23:44.093Z')

which looks like what I was issuing in Cloud Storage Studio and getting back 14 rows.  Hmmm… The parentheses look a bit weird in the one being sent by my app through StorageClient; maybe that’s the problem.

But, no, it turns out that isn’t the problem.  You have to look really closely at the expression to see the problem; I’ll highlight it below:

(((PartitionKey eq 'WSF') and (TerminalFrom eq 'Seattle')) and

(TerminalTo eq ' Bainbridge')) and (Departure ge datetime'2010-02-07T21:23:44.093Z')

it’s the space between the opening quote and the terminal name ‘Bainbridge’.  This was caused by a typo in my code where I took a string like ‘Seattle – Bainbridge’ and split it into two pieces – a classic off-by-one error where I’m including the space in the destination terminal name. 

Lesson (learned over and over): don’t test what you think and firmly believe the program is doing; test what the program is actually doing.  The more you can capture the real data and real queries, the more you will be one with the program you are debugging.

Posted by MikeKelly | 0 Comments
Filed under: ,

Timed Update to a Page

One of the features in my ferry app is to show the time remaining until the next ferry.  This simple feature took me on a winding road through AJAX, System.Timers.Timer, Javascript, etc.  It seems like such a simple thing to do, and eventually I hit on the simple approach which is the META tag. 

The requirements are:

1. The default.aspx page can be in one of two states – either the user is logged in, in which case we know what ferry information to display, or they aren’t.

2. If they are logged in, we show the ferry time like this, with the elapsed time from now until the next sailing:

image

3. The elapsed time – from now until the next sailing – should be updated in an efficient manner.

Obviously, the server adds nothing to updating this value – it’s simply the time from “now” to the next sailing.  The only time we need to hit the server is when the elapsed time crosses zero, in which case we need to get the sailing after that on the page. 

My first take was to just use AJAX and use an UpdatePanel and a Timer (client-side in AJAX) to trigger an update.  This worked fine on PCs, but when I hit the page from my Samsung Windows Mobile phone, I got nothing.  I poked around for a while and found it is unclear whether ASP.Net AJAX is supported by the Mobile IE browser with Windows Mobile 6.1.   I figured it might not be based on what I was seeing, so on to plan (B) – let’s just do it server side (yes, it’s not as efficient but…) and so I created a System.Timers.Timer which would simply call my Page Refresh logic every minute.  Worked fine except the page didn’t refresh.  Doing some debugging, I found the timer was triggering – but the page context wasn’t my page, it was some made up page.   Makes sense – the timer is being triggered server side, not client side, so there is no HTTP request.  OK – maybe plain vanilla JavaScript (rather than the fancier AJAX version) might work.  Found a simple piece of code that looks like this:

<script type="text/javascript">
    var t;
    var timer_is_on = 0;

    function timedCount() {
        window.location.reload( true );
        t = setTimeout("timedCount()", 60000);
    }

    function doTimer() {
        if (document.getElementsByName('LoginStatus2')[0].innerText == "Login")
            return;
        if (!timer_is_on) {
            timer_is_on = 1;
            timedCount();
        }
    }
</script>

<body onload="doTimer()">

Seems straightforward – every 60 seconds, if the user is logged in (based on the text of a login control in the page nav bar), refresh the page, updating the elapsed time.  Problem is that the page refresh happens when you enter timedCount – which causes a page load and a call to doTimer.  But because this is a fresh page load, timer_is_on is set to zero – so timer_is_on is set to 1, timedCount is called, which does a window reload – which causes a page load and a call to doTimer.  But because this is a fresh page load, timer_is_on is set to zero – so timer_is_on is set to 1, timedCount is called, which does a windows reload… you get the picture.  Infinite loop.  Arggh!

For the release of this I need to do tomorrow, I’ve decided to bail on the page refresh.   But I have an idea of one thing to try which I found on this blog.

But the really right way to do this is to have Javascript on the client side figure out the elapsed time and update just that control.  If the browser doesn’t support that (as I’m suspecting IE Mobile doesn’t), then you don’t get the auto refresh.  That will my approach next week when I come back to this.  In the meantime, got to get this release out!

Posted by MikeKelly | 0 Comments

Updates to my Azure Ferry App

I’ve been working on getting my ferry times app running and have recently been motivated to step it up.  I’m submitting the app to a contest that Microsoft is running for partners to encourage developing Windows Azure apps.  Here a few random things I’ve learned while I’ve been tuning up the app.

  • The AspProviders sample pretty much works now with the November 2009 PDC release of the platform.  I just downloaded the additional samples, pulled the AspProviders files from the sample directory into a new project in my solution, built it and then incorporated the required goo in web.config to get it hooked up.  I now have login and profiles working against Azure table storage with my app.   The only “tricks” here were:
    • Adding an <appSettings> section within the web.config <configuration> section to give the configuration for AspProviders to use:

      blog appsettings

    • Note that I had to make the storage endpoints use https: or I got an exception when I tried to write to these (there is an alternative to set allowInsecureRemoteEndpoints but that’s a bad idea).  Just change ‘em to use https: and all is good.
    • The I added a section for the membership etc. providers.  This goes in your web.config in the <system.web> section.  It looks like this; you can pretty much take the text out of the AspProvidersDemo web.config in the Azure additional samples.  The only thing you have to change is the name of the application in a couple of places (look for an applicationName property), the cookie name (in roleManager) and the properties you want stored in the profile.

    blog membership

    • Finally, change your authentication mode to “Forms” (mine was “Windows”).
    • I had a problem where even though I had logged in, when returning I sometimes wasn’t authenticated and had to login again.  I tracked this down to the cookieTimeout attribute in the roleManager being 30 minutes – for my application, I want to log people out only rarely, so I increased it to 43200 – which is 30 days.
  • I suspect a lot of people writing apps for Azure will have the problems I’ve run into with time zones.  I think these were masked for me in the CTP releases of the platform because they were running in a data center here in the Pacific Northwest and I live in the Seattle area, so the time zones were all the same.  I first noticed a problem in December when suddenly the times I was getting from an RSS feed here were getting translated into weird times when I persisted them to the Azure table storage.  I poked around a bit and realized that Azure has moved to have all the data centers have GMT (also known as UTC, or universal time) as the time zone.  This makes sense because your application can migrate from data center to data center – this is part of the advantage of Azure – so you can’t count on running in any particular time zone.  I’ve read a good MSDN article on how to deal with time zones which I recommend.  A few observations which I’ve learned only really by playing around.
    • This is one of the ways in which Development fabric differs from Azure cloud fabric – your development fabric will run on your local time zone, making these bugs harder to find, and in fact you need the code to not work correctly in development fabric to work correctly in the cloud fabric, which is confusing.
    • Even web roles have their default local timezone set to GMT,  so dates you receive as input from a web form will be considered to be in GMT unless set otherwise.  This turns out not to be an uncommon problem – here’s a blog post that summarizes it for vanilla ASP.Net apps and here’s one that proposes a custom control to capture the browser time zone and make it available to the server through the custom control properties.  It turns out that for my application, I don’t exactly want the browser time zone – because I want to show the ferry departure in the time zone where the ferry leaves, not where the browser user is (if you are in Chicago, the Bainbridge ferry still leaves at 7:05 AM PST, not at 9:05 AM CST).  So I needed to be able to get the time zone appropriate for this ferry provider and use that to convert the time retrieved from the database from GMT to local time where the ferry operates.  Note that this has to take daylight savings time into account.  The approach I settled on is to include an attribute in the XML file which I use to provide information on the various ferry services I know about.  This attribute gives the standard time zone name for the sailings of that ferry service (note this wouldn’t work if some of the sailings were in different time zones, but I’m willing to live with that restriction for now).  Then when I create a user profile, I have the user select the ferry service they want to get information about and I pull the time zone from the XML for the selected ferry service and store it in the profile.  Then at run time, I can pull that from the user profile and convert from UTC to that time zone using TimeZoneInfo.
Posted by MikeKelly | 0 Comments
Filed under: ,

Backing up a MacBook Running Both Windows 7 and Mac OS X

I have a MacBook on which I use Boot Camp to dual-boot to Windows 7 and Mac OS X Snow Leopard.  I would like to back up both systems to a single 500 GB USB drive.  I poked around a bit to figure out how to do this, and didn’t find anything (the closest is this post which explains how to do it to a Windows Home Server) so I figured I’d explain how I got this to work.

The problem is that Windows wants the volume to be NTFS for its built in Windows 7 backup program to work, and Mac OS X wants the volume to be a formatted Mac HFS volume – so when I booted into Mac OS X after connecting the volume under Windows 7 and running the first Windows backup, Time Machine saw the volume and prompted me to reformat it as a HFS to be used with Time Machine (the Mac OS X backup program).  Of course, that’s not what I wanted.

The trick is to create two separate volumes on the single external drive – one will be NTFS for Windows 7, one will be HFS for Mac OS X.  You may be able to do this under Mac OS X, but I know the Windows tools better so I did it that way.  Here’s how.

First, attach the drive and boot up to Win7.  Log in to an Administrator account.  Right click on Computer in the Start Menu and select “Manage”.  Click on “Disk Management” in the right panel and you will see a list of disks on your computer.  The first one is probably the built-in MacBook hard drive, which you can see below I have partitioned into one HFS partition which MacOS X runs on and one NTFS partition which is for Windows 7.  The second disk is the USB drive.  Initially, I had a single 465 GB partition.  I right clicked on that, selected “Shrink Volume…” and shrunk the volume down to about half it’s size – this is the portion that will be used for Windows backup and will be an NTFS volume.  Initially, this will show as “Unallocated Space” – basically, it is just free space on the disk now.  I right clicked in the free space portion and selected “New Simple Volume…” which runs a wizard that helps you create a volume in that free space.  I formatted it as NTFS but did not assign a drive letter to it since it won’t be used by Windows, only Mac OS X.

You can see I gave the two separate volumes reasonable names – one is Win7 backup, the other is MacOS X backup.

Disk Management

Now reboot the machine, and hold down the Option key to select to boot up Mac OS X rather than Win7.  This time, Time Machine will see the disk as two separate volumes and will prompt you which one to use for Mac OS X backups:

Screen shot 2010-01-04 at 9.59.24 AM

Select the MacBook OS X Backup partition you created (which is now empty) and click “Use as Backup Disk”.  Time Machine will prompt you if you’re sure you want to erase it – since it has nothing on it right now, that’s fine – click “Erase”:

Screen shot 2010-01-04 at 10.02.03 AM

Time Machine will reformat it as HFS and will start using it for backups.

You just have to remember to keep the USB cable for the external drive plugged into the MacBook when it is on your desk at home so that backup will run.  Remember that Windows backup will run only when Windows is running on the Macbook, and on the schedule you’ve set – so mine runs at 7 PM every Sunday.  I just boot into Windows on the MacBook Sunday afternoon and leave it running on my desk overnight so that it runs the Windows backup for that week.

Posted by MikeKelly | 0 Comments

Everyone I’ve Sent Mail To

For a farewell mail to my colleagues at Microsoft (I’ve decided to move on, but will continue contributing to this blog), I was worried I might miss someone.   Using the arguable presumption that the “important people” were those who I’d sent mail to, I figured I would write an Outlook macro to go through my Sent Items and pull out all the email addresses.  That turned out to be pretty straightforward; here is the code (I don't claim this is the best way to do it, but it does work):

 

Sub GetSentItems()

Dim eml As MailItem
Dim nsMyNameSpace As NameSpace
Dim colSentItems As Items
Dim objItem As Object
Dim fnum As Long

 
fnum = FreeFile()
Open "c:\users\xxxx\documents\recipients.txt" For Output As #fnum


Set nsMyNameSpace = Application.GetNamespace("MAPI")
Set colSentItems = nsMyNameSpace.GetDefaultFolder(olFolderSentMail).Items
For Each objItem In colSentItems
    For Each objRecip In objItem.Recipients
                Write #fnum, objRecip.Name & “;”
    Next
Next
Close #fnum


End Sub

This creates a text file in my documents folder called recipients.txt (note: substitute your user name for “xxxx” in the path).  It then navigates the Outlook namespace to find the Sent Items folder and gets all the items in there (in colSentItems – col for collection).

It then iterates that collection, pulling out from each item (which represents a sent mail message) the recipients collection – remember an email may have been sent to more than one person or group.

It iterates the recipients and pulls out for each the name.

Note that to run this you may have to tweak the Outlook macro security in Tools / Macro / Security… to allow unsigned macros to run (either “warnings for all macros” or the “No security check” (be sure to set this back)).  You’ll have to exit Outlook to get the new security setting to take effect.

Then run it using Tools / Macro / Macros and it will generate the file.

The problem is that you probably have a lot of duplicates since there are some people to whom you send mail frequently.  Excel can help out here.

Open the recipients.txt file in Excel and use Data / Remove Duplicates to eliminate those.  You can then sort the list and go through and pick out any names you don’t want.  I used Column B in Excel to put an “X” in the ones I wanted to send mail to, then when I was done sorted by column B, selected all those items and copied to the clipboard.

Finally, back in Outlook, create an Outlook mail message and just paste all the names you copied from Excel into the BCC field.  Note that there is a “;” at the end of each name to provide a separator for Outlook.

Posted by MikeKelly | 1 Comments
Filed under: ,

Top Ten Things at PDC 2009

I’m sitting at LAX writing this summary of PDC which is just wrapped up.  Although I went “on my own dime” (i.e. I paid my own way), it was definitely worth it for the ten reasons below…

  1. Learning a bunch more about Azure storage and SQL for Azure at Jai Haridas’ session and Brad Calder’s session on blobs, queues and the just-announced xDrive – which allows an Azure page blog to be formatted and mounted as an NTFS virtual drive.
  2. Microsoft Expression Blend’s SketchFlow, which is an amazingly easy-to-use and complete prototyping environment, described by Christian Schormann in a session marred only by his cough, which was very, very loudly amplified throughout the room until the sound guy caught on and reduced the volume when Christian turned from the audience to cough.  This falls into one of those things which I have installed on my machine, booted once and never really spent the time to figure out – now I will.
  3. A very demo-intensive and impressive session on the Bing Maps API by Keith Kinnan. I knew Virtual Earth (now Bing Maps) had an API, but I had no idea how sophisticated it is and how many very cool things can be built quite easily.
  4. Ray Ozzie’s announcement in the Tuesday keynote of a project codenamed “Dallas” which is an ambitious attempt to provide very high-value data sources licensed under a uniform EULA and for minimal or no cost.   There weren’t a lot of details on this, but stay tuned on this one – combined with the ADO.Net RESTful data services, this could be pretty cool.  I didn’t make it to Zach Owen’s session on this but spent some time with the Dallas team members at the Ask the Experts reception Wednesday night and it’s clear they have some ambitious plans for this.  There is more information here.
  5. Eric Lawrence’s great session on Fiddler, which has has an amazing run of success – Eric told me at the reception that night that he’s getting up to 3500 downloads a day of Fiddler!
  6. Matthew Kerner’s session on Azure Diagnostics, Logging and Management APIs, which was a very clear description of this area that I’ve been working in since the pre-PDC bits were dropped in mid-October.  Matt did a great job of summarizing this and clarifying a few things I didn’t 100% get.
  7. The session by Shyam Pather and Chris Anderson on ADO.Net Entity Framework 4. I kind of understood EF before this session, but this dynamic duo – with Shyam narrating and Chris typing away as if he were a voice-recognition and automatic code correction engine – was quite impressive.
  8. A fun session on C++ improvements in VS 2010 – good to remember that the whole world hasn’t moved to XAML and C#!
  9. Pablo Castro’s session on ADO.Net Data Services (formerly code-named Astoria) which was a very lucid and passionate description of why RESTful data services matter so much, and an impressive summary of all the sources being exposed through ADO.Net Data Services (now apparently renamed “WCF Data Services”) and the exposure of this in everything from Excel to Silverlight to Azure.  Very impressive.

And the number one thing about this PDC…  Steven Siinofsky’s announcement at the Wednesday keynote on Windows 7 that the Windows group had partnered with laptop manufacturer Acer to design a laptop optimized for Windows 7 – and that every PDC attendee was being given one!  What a brilliant way to jump-start development for Windows 7 features like location-awareness, multi-touch, etc.

There are still a bunch of sessions I didn’t make it to that I plan to watch online.

Updated 11/24 with some additional information on Dallas.

Posted by MikeKelly | 0 Comments
Filed under: ,

Microsoft Professional Developers Conference (PDC 2009) : Tuesday

This is the first time I’ve been to PDC in a number of years, and it is fun to be back.  Here are some impressions really more than details about the first day.

  • It is big.  Just walking around the LA Convention Center from session to session gives a sense of the thousands of people here (although one regular attendee told me that it seems a bit smaller than a few years ago).  Walking from one session to another can take 5-10 minutes as I traverse elevators, long corridors, etc.
  • The typical room seems to hold about 500 people and most are fairly full.  One session I tried to attend (I arrived ten minutes late for one session this morning and found I couldn’t get in – the room was full to legal capacity).  But since there are 10-12 sessions running in parallel, it wasn’t too hard to find another session to attend.
  • Cool to see my old colleague, Eric Lawrence, talk about Fiddler to a very enthusiastic crowd of users.  This is a really impressive web debugging tool that Eric has developed in his spare time – he noted that his work on it is going down now that he’s engaged to be married!  I learned a bunch of things I didn’t know about Fiddler despite being one of the earlier users when Eric worked for me in Office.
  • A lot of the sessions are pretty code-intensive, rather than slideware overviews, which is really good.  Nothing helps me understand something better than seeing the actual code.  For instance, one problem I’d been having with DataServiceContext became clearer from seeing Chris Anderson type some code using this class in a session on Entity Framework v4.
  • The keynote this morning on Azure featured the White House CIO, Vivek Kundra, trumpet how Azure can be used to help provide more seamless data exchange through a project code-named Dallas.  That and the demo of how blog-provider WordPress is using Azure as an early adopter for part of their site were the highlights for me of the keynote.
  • Lots more on PDC at http://microsoftpdc.com/resources.
Posted by MikeKelly | 0 Comments

Azure – from July CTP to November 2009 PDC Release

Well, the official PDC 2009 release of the Azure SDK is out and there are a lot of changes.  I’m not going to do a release-notes style narrative on changes, but thought it might be interesting to instead focus on changes I had to make to get a simple service that was working with July CTP against cloud table storage to work with the PDC release.

My service is a simple service to display the next departure time for the ferry I regularly use here in Seattle.  The Washington State Ferry makes available an RSS feed of upcoming sailings, which I have a worker role to consume and translate into a more easily manipulated form in an Azure table storage entity.  The web role simply retrieves the next ferry time from the Azure table storage and updates it on the web page every minute.  Very simple.  By the way, I don’t claim that the way I’m doing this is necessarily the best way – part of my goal in writing this was to learn more about Azure and the ADO.Net Data Services so it may be sub-optimal in some cases.

So here goes.

  • The biggest change (for my service) was in StorageClient.  It went from being an “as-is” sample that you included and built with your project to a supported part of the Windows Azure namespace, Microsoft.WindowsAzure.StorageClient.  The way you use StorageClient changed as well in response to feedback from the sample.
    • Note that part of what you need to use StorageClient, CloudStorageAccount (which replaces the StorageAccountInfo in the July CTP bits), is in the Microsoft.WindowsAzure namespace.
  • I’m using ADO.Net Data Services classes to access a simple table entity.  So I have a class, FerryCrossing, which provides the structure of the table storage entity – no changes there.
  • I also have a class, FerryContext, which inherits from the Azure TableStorageContext class.  The constructor here changed from taking no arguments in the July CTP to taking two arguments in the new release (StorageCredentials is a part of the CloudStorageAccount class).

public FerryContext(string baseAddress, StorageCredentials credentials)
    : base(baseAddress, credentials)

  • Finally, I have a class, FerryDB, which provides the public API to the database actions – things like getting a list of crossings, adding a crossing (called from the worker role based on the RSS data, etc.).  This one changed in a number of ways:
    • It can no longer assume that StorageClient will just read the config file to get the information about table storage endpoint and account information (AccountSharedKey, AccountName) as it did in the July sample.  Now those are read by my code and passed in (through the TableStorageContext constructor). 
    • The config format has changed a bit.  To use development storage, you use this in your ServiceConfiguration.cscfg file associated with your Azure service:

<Setting name="DataConnectionString" value="UseDevelopmentStorage=true" />
<!-- Value for Development Storage -->
<Setting name="TableStorageEndpoint" value="http://ipv4.fiddler:10002/devstoreaccount1/">

    • Notice that for the endpoint for local development storage, I’m using a trick that lets me use Fiddler to spy on the traffic; if you don't need this or aren't using Fiddler, just replace ipv4.fiddler with 127.0.0.1 in theURL.
    • Now in my FerryDB code, I read these config settings and pass those to the ctor for FerryServiceContext:

private FerryDB()
{
     _acct = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
     _baseAddr = RoleEnvironment.GetConfigurationSettingValue("TableStorageEndpoint");
     _ctx = null;
     _fBatchUpdateInProgress = false;
}

private FerryContext FerryCtx()
{
     if (!_fBatchUpdateInProgress)
         _ctx = new FerryContext(_baseAddr, _acct.Credentials, TableName);
     return _ctx;
}

In order for this to work, you have to in the startup code for your role initialize a Configuration Setting Publisher; this code goes in the OnStart method.

#region Setup CloudStorageAccount Configuration Setting Publisher

// This code sets up a handler to update CloudStorageAccount instances when their corresponding
// configuration settings change in the service configuration file.
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
     // Provide the configSetter with the initial value
     configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

     RoleEnvironment.Changed += (sender, arg) =>
     {
         if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
             .Any((change) => (change.ConfigurationSettingName == configName)))
         {
             // The corresponding configuration setting has changed, propagate the value
             if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
             {
                 // In this case, the change to the storage account credentials in the
                 // service configuration is significant enough that the role needs to be
                 // recycled in order to use the latest settings. (for example, the
                 // endpoint has changed)
                 RoleEnvironment.RequestRecycle();
             }
         }
     };
});
#endregion

Finally, one of the other big changes I saw was in RoleEntryPoint (you inherit the body of your worker and web role code from this).  RoleEntryPoint's basic interface has changed:

  • Start -> OnStart
  • The body of your role is in the Run method
  • There is an OnStop method
  • You no longer need the GetHealthStatus method
  • There is a mechanism for informing the role of configuration changes and allowing it to respond to those, including potentially asking to be recycled and restarted.

In the July CTP, RoleManager handled diagnostic logging through a very simple API, WriteToLog.  There is now a standard ETW framework diagnostics model.  Instead of invoking RoleManager.WriteToLog, you have the full range of ETW methods in System.Diagnostics; so you can use:

  • Trace.WriteLine
  • Trace.TraceError
  • Trace.TraceInformation
  • Trace.WriteIf
  • etc.

To do this, set up the Azure diagnostics ETW listener to persist your logs.  This is pretty simple; you have a config setting similar to the data connection string (DiagnosticsConnectionString) in the config file for the diagnostics table storage – note that this means you could separate your diagnostics logs from your other app data storage if you want.  Then in the OnStart method for the role, pass this to the DiagnosticMonitor class:

public class WebRole : RoleEntryPoint
{
     public override bool OnStart()
     {
         DiagnosticMonitor.Start("DiagnosticsConnectionString");

Well, I’m sure I’m missing something but those were the big things for me.  Look at the samples for other items.

Posted by MikeKelly | 1 Comments

DevDays Seattle – Scott Hanselman

Lolcode.net – funny site with a domain-specific language that mimics IM syntax.  Actual code

MVC

When you create an MVC project, you get default code for controllers and views but nothing for the model. ASP.Net MVC lets you use nHibernate, Linq to SQL, whatever for your data access.

The URL hierarchy is a form of user interface and in MVC the .aspx extension is gone. MVC uses the URLs to do routing - it's convention over configuration, i.e. there is no big file that defines the URL namespace - it's a convention that the URL is a controller action and there should be a controller named that.

MVC is just built on top of System.Web - there is a transition to System.Web.Mvc. WebForms is still there. It's like the difference between motorcycle and mini-van - one isn't better than the other, they are just different and for different purposes.

In the controller could create a viewmodel that goes to the database and pass that to the view. Framework doesn't require a ViewModel for a Model but it's typical to do it that way.

<%: in the view does an HTML.encode whereas <%= doesn't.

Views can be done using an .aspx extension - but no code behind anymore.

Create a model and can create a view that is strongly-typed linked to the model and will generate the details view for that. Code Templates let you change the default code generated from the wizard - using T4, the VS code generation engine.

www.nerddinner.com - if you hit it from an iPhone, detects that and the controllers and models are the same but the views are different. Code at http://tinyurl.com/aspnetmvc

Posted by MikeKelly | 0 Comments

DevDays Seattle – Joel Spolsky

We get interrupted too much by a computer that has an agenda of its own for ourselves.

Examples:

  • Windows updates
  • Outlook: Any exceptions associated with the recurring appointment will be cancelled. Is this OK? <OK> <CANCEL> but Cancel doesn't mean cancel the appointments, it means cancel the change.
  • Even shutting down your computer involves a decision - shut down, restart, hibernate, sleep, …

Why are these called dialog boxes? They are an imaginary dialog between the programmer and the user. The programmer believes that users care about this dialog, but they don't. What you care about as a programmer is getting the parameter to some function you need to call and the user doesn't really care about giving you that answer. You should just figure it out. You as a programmer never have the right to put up a modal dialog box while the user is trying to do something.

Really comes down to simplicity versus power. Swiss Army knife version of software.

www.columbia.edu/~ss957/whenchoice.html - When Choice is Too Much

When there were 24 flavors of jam to choose among, only 3% purchased a jam. When there were 6 flavors, 30% - ten times as many - bought jam. People abdicate when too many choices are presented.

37signals - getting real - fewer options in software.

My manager at Microsoft, Andrew Kwatinetz, taught me every time you have an option in a dialog box, you're asking someone to make a decision.

Gmail - has a choice "Always display external content (e.g. images) sent by trusted senders." Not sure as a user why they're asking you, but as a programmer I understand the security risk of displaying an image - but even I don't know who are trusted senders.

Software excuses itself so that when someone does something natural that causes a problem, they feel stupid. This is what all these "Are you sure?" dialogs are about - so people blame themselves.

So why isn't software just simple?

When you show the V1 simple software, everyone loves the simplicity - but could they just have this one feature - why isn't there search? Why can't I add a picture to a bug?

What you find is as you solve the customer problems by adding features, you have more sales - so you're adding features to drive those sales. Yes, people only use 20% or so of features, but it's a different 20% for each person.

So how do you solve this conundrum?

Design is the act of making decisions, and designing well is making the right decisions. When you have failed at design, you are punting to the user. A designer knows he has achieved his task not when there is nothing left to add, but nothing left to take away.

A piece of architecture is best when it has the modesty not to draw attention to the obstacles it has overcome.

Nokia E71 phone - four choices for silent: meeting, outdoor, silent, vibrate. The four choices require a complicated menu. If you just have two choices - silent/ring, you can do what the iPhone does and have a physical switch.

We realize we don't need checkout, we can buy now with 1click. We don't need pause/stop - we can just have stop. Pause exists because of reel-to-reel tape where the difference between stop and pause was whether the heads disengaged. In a digital world, we don't need the distinction.

Simple is hard. Think of all the extra work the Amazon codebase has to do to make one-click work. They have to hold the order for 30 minutes in case it was a mistake so it can be cancelled - but proceeding is the mainstream case and the case that is optimized - you only have to do extra things if you want to stop the order.

Posted by MikeKelly | 0 Comments

DevDays Seattle

I’m at DevDays Seattle, an event sponsored by Stack Overflow and Microsoft.  I look at it as a day of seeing “how the other half codes”, i.e. those not using the Microsoft stack (IIS, ASP.Net, Azure, C#, etc.) but more open source tools like jQuery, mySQL, etc.  One of my favorite tech bloggers, Joel Spolsky, is behind this and speaking, which I’m looking forward to.  I’ll post updates during the day; topics include ASP.Net-MVC (after all, Microsoft is a co-sponsor, so I guess it’s not all about “the other half” :)), iPhone apps, Python, and Google App Engine.

Posted by MikeKelly | 0 Comments

Azure Service: Moving Storage from Development (local) to the Cloud

As part of the process of moving my Azure test service from running entirely locally (on what's called "Development Fabric" and "Development Storage", i.e. for development on your local machine) to the Cloud, I followed the steps on MSDN which suggest moving to the Cloud in two steps:

  1. Run your service locally (on "development fabric") connecting to cloud-based storage.
  2. Once that's working, move your service to the cloud fabric.

So how do you get your local service to talk to cloud-based storage?  Turns out the hardest part is getting the storage table created on the Cloud (or is it "in the Cloud"? :))

The old way suggested having a method in your DataContext which you call to check if the tables are created and if not create them.  But a more recent post from Steve Marx points out that this is very inefficient.  He proposes adding a new entry point to do this, but another post from Mark Seemann proposed an even more elegant solution: write a Powershell script to invoke the method to create the table(s) once out of band of any running service code.  Since I'd been meaning to play around a bit with Powershell anyway, this approach had an extra benefit.

Using Mark's script as a model, I eventually got this working and now have my service connected to the cloud storage.

The changes I had to make were:

  • Make sure your Data Context class which inherits from the StorageClient TableStorageDataServiceContext class is public.  Otherwise, the PowerShell script won't be able to load it.
  • Make sure it has two constructors (here are mine:

public FerryContext() : base() { }

public FerryContext(StorageAccountInfo info) : base(info) { }

  • These are needed by the PowerShell script but not by my previous service code.
  • The other customizations are specified in Mark's blog post referenced above.

 

 

Posted by MikeKelly | 0 Comments
Filed under:

MVC and CSS

I've spent some time trying to figure out why my simple MVC site (built on Azure) isn't rendering correctly on my development machine, and of course tracked it down to the CSS file not loading.  I spent time playing around with paths, etc., but finally found a simple solution:

You have to enable "Static Content" for your Internet Information Services for CSS to work on the development machine.

To do this (on Windows 7),

  1. Go to Control Panel
  2. Select Programs.
  3. Select "Turn Windows Features on or off"
  4. Scroll down to the box for "Internet Information Services"; expand it
  5. Expand the box "World Wide Web Services"
  6. Expand the box "Common HTTP Features"
  7. Make sure "Static Content" is checked; if not check it.
  8. Hit OK.

CSS will now work for you. 

Posted by MikeKelly | 0 Comments
Filed under:

Simple Azure Service Experience

I started a couple of days ago working on my first Azure service and have learned a lot.  It's a cliche, but there is a ton of good information on the web on this.  One of the challenges is wading through it all and piecing together the great information in one blog (but which leaves out a key part) and the good information in another (which fills in that missing piece).

A few things that may be obvious, but weren't to me...

  • If you're using Azure storage, you want to get the StorageClient API - it makes it a lot easier to deal with the Azure storage REST APIs and provides a framework for wrapping these as normal ADO.NET objects.
  • I'm planning on using the table storage from both my "worker role" (think traditional background service on Windows) and "web role" (web-based UI) Azure services, so wasn't quite sure how to get that connected.  The idea is that the background "worker role" will populate the data which the web role will read.  There are a bunch of classes you set up just to enable access to table storage, including:
    • One class per entitity (think of this as like a table in SQL) that models the values in the entity and provides each value as a typed property.  This is how rows are delivered to and from the table storage.
    • One class that provides a data context.  which inherits from the Azure StorageClient class TableStorageDataServiceContext.  This is the Azure equivalent of the ADO DataServiceContext class which provides cached state information.
    • Finally, a class which uses these first two to provide high-level CRUD (create, retrieve, update, delete) methods against the table storage.
  • At first, since I was writing the code to populate the tables, I just added these classes to the Azure Worker Role project in my solution, but as I said, I realized this wasn't ideal since I would need to use them from both the worker and the web role.  I then came across Arjan Einbu's blog post on creating a class encapsulating these which would be shared by worker and web role - doh!  Of course that's what I wanted.  With a bit of moving around files, I was able to create a XxxServiceData class project (File / New / Project / Windows / Class Library) in my solution which encapsulates just the data access, then reference that from the Worker and Web role code.

Some good links are (in addition to those above):

Posted by MikeKelly | 0 Comments
Filed under:

PDC 2009

I registered for PDC 2009 today, getting in under the wire for the pre-September 15 discount.  Looking forward to seeing more about the Windows 7 app features and of course Azure.

 

Posted by MikeKelly | 0 Comments
Filed under:
More Posts Next page »
 
Page view tracker