15 Aug 2012

Allow MVC to work on ASP.NET 4 / IIS7 with runAllManagedModulesForAllRequests set FALSE

In pipeline mode on IIS 7, all requests for content (including requests for static files) play through the ASP.NET handler unless you set runAllManagedModulesForAllRequests to false in the <system .webserver> part of web.config.

Unfortunately by default that stops MVC 3 working because MVC urls do not have a file extension to give IIS a clue what to do.

Well cheer up, cos MS have issued a hotfix. Woop!

http://support.microsoft.com/kb/980368

For extra info see http://blogs.msdn.com/b/tmarq/archive/2010/04/01/asp-net-4-0-enables-routing-of-extensionless-urls-without-impacting-static-requests.aspx

9 Aug 2012

Visual Studio RegEx for converting old MVC Views to Razor format

This won't fix everything, but does help a lot with converting your old MVC Views to Razor format.

Basically this is RegEx replacement pattern for use in the Visual Studio Find and Replace dialog, for converting out all the old <%: blah %> tags.

Find what:

\<%\::b*{.#}:b*%\>

Replace with:

@\1

Don't forget to Use Regular Expressions in the Find Options.

Some of the resultant code won't work until you put brackets round it e.g. @blah blah needs to be @(blah blah)

Don't forget you may need to convert <%= blah %> tags too - perhaps convert them to @Html.Raw(blah)

Don't forget you may need to convert <% blah %> tags too - perhaps convert them to @{blah}

6 Aug 2012

Wii Skylanders USB dongle problem

Let me cut to the chase!


  • The USB dongle has a tiny red LED on it that glows to show it's working. 
  • The USB  ports on your Wii might be dusty - blow them clean.
  • With the Wii on, plug in the dongle and wobble it around in the USB port until its red LED lights up and stays on.
  • Boot up Skylanders, enjoy peace and quiet!
And if you're seriously bored, the backstory:

---

Phew, almost had a very disappointed birthday kid on my hands there... he got Skylanders for Wii for his birthday which features a plastic castle thing called a Portal Of Power. I didn't realize at first but the Portal contains a usb dongle which you plug into a USB port on the back of the Wii.

Well, I spent about half an hour trying to get the Portal to sync with the dongle, and no dice. The instructions say if the Portal's button is flashing, it hasn't synced with the dongle yet. You're supposed to press the SYNC button in the Portal's battery compartment and then press the button on the dongle to complete the handshake. Well I tried that about a million times but no dice.

Then I figured that the dongle would work on any usb socket so I tried it on my laptop - eureka moment - as soon as I plugged it in, not only did the Portal's button light go solid (indicating successful sync), but a little red light on the end of the dongle lit up. I didn't know the dongle had a light! So I started a-thinking that maybe the porblem was the usb ports on the wii.

I don't know about you, but i've had my Wii for about 5 years and have never used the USB ports before. They're open and collect dust so I blew them out. I plugged the dongle in - no red light. I wiggled the dongle around - RED LIGHT! I wiggled some more - no red light.

Well, seems like the USB ports on my Wii are a bit flakey. After a while I wiggled the dongle into a position where the light stayed on, and then gingerly left it alone. Booted up Skylanders and we got past the Sync screen for the first time.

WOOHOO - kid is happy and I can get on with my "real" job.

1 Aug 2012

Making Asynchronous / Concurrent calls to MVC - requests are synchronized

After a while coding in ASP.NET, I took some things for granted - the Session object for example. It's always there, so useful for storing little tidbits of stuff.

But I never pondered on the DARK SIDE OF THE SESSION, as regards its implication in MVC. Yes, I was vaguely aware that access to session data had to be synchronized (i.e. an exclusive lock placed on the session's data during access) but I didn't figure the duration of the lock. It turns out that in regular use, all MVC Controller Actions lock Session access for the duration of the request, with the reasoning that Session access could occur at any time during the request.

Therefore, if your browser makes several concurrent MVC requests - perhaps a regular View call, a polling AJAX call and an Image-Generation call - they will be run sequentially, NOT simultaneously.

Therefore, if one of your calls is slow to return, the others in the queue are held up in turn!

In old-school ASP.NET, you could turn this off at the Page level by setting EnableSessionState="false" in the @Page directive. But up til version 3, there was no equivalent in MVC apart from the radical step of disabling SessionState in the web.config file. See this post for more info on those strategies.

Well, in MVC 3 we still don't have fine-grained Sesssion control at the Action level, but we do at the Controller level, with the SessionState attribute. This allows us to say if we want to use default behaviour, ReadOnly access (concurrent reads, synchronized writes), or fully disabled Session in our Controller's Actions. With Session Disabled or ReadOnly, we have the asynchronous request ability that we desire, albeit that we have to be careful we make no calls (or at least Writes, in ReadOnly mode) to Session now that we have restricted access.

Usage is like so:

    [Authorize]
    [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
    public class DocumentController : Controller
    {
        public ActionResult ViewDocument(int id)
        {
            var doc = WebApp.MainService.GetDocument(id);

            if (doc == null 
                || !(doc.UploadedBy == WebApp.CurrentUser.UserId 
                    || doc.OwnerUserId == WebApp.CurrentUser.UserId 
                    || WebApp.CurrentUser.IsInRole(Core.Enums.RoleType.Admin, WebApp.CurrentSite.SiteId)))
            {
                throw new Exception("You do not have permission to view this Document");
            }

            ContentDisposition cd = new ContentDisposition { Inline = true, FileName = doc.Filename };
            Response.AppendHeader("Content-Disposition", cd.ToString());
            return File(DocumentService.GetSavedDocumentFileName(doc), FileTools.DetermineContentType(doc.Filename));
        }
    }
If I helped you out today, you can buy me a beer below. Cheers!