1. Generating a settings class from XML with T4

    March 26, 2010

    I’ve just posted a couple of T4 templates on CodePlex which you can use to generate a Settings class from XML. You get a compiled class which handles type checking, thread safety and loading and saving the settings to your database. You’ll never again have to worry about unloading your application when settings are updated.

    A note about the 2 templates

    There are 2 T4 templates:

    1. one for multiple sites (see Subdomains for a single application with ASP.NET MVC)
    2. and one for single sites. If you’re not sure which one you need, it’s probably the “single site” one :)

    How it works

    The XML:

    <settings>
    	<group name="Appearance">
    		<group name="Colors">
    			<setting name="ContentBG" type="string" default="#FFFFFF" />
    		</group>
    	</group>
    
    	<group name="Authentication">
    		<group name="LDAP">
    			<setting name="Enabled" type="bool" />
    			<setting name="Servers" type="string[]" />
    			<setting name="Domain" type="string" />
    			<setting name="Port" type="int?" default="389" />
    		</group>
    	</group>
    </settings>
    

    What you get

    /* Getting the settings object */
    var settings = Settings.Get(); // for single site
    // var settings = Settings.ForSite(Site.ID); // for multi-site setup
    
    /* getting various settings */
    var color = settings.Appearance.Colors.ContentBG; // var color is now set to a string, containing "#FFFFFF"
    int? ldapPort = settings.Authentication.LDAP.Port; // ldapPort is now 389
    
    /* setting various settings */
    settings.Appearance.Colors.ContentBG = "#CCCCCC";
    color = settings.Appearance.Colors.ContentBG; // color is now set to "#CCCCCC"
    settings.Authentication.LDAP.Port = null; // all the settings values are type-safe
    settings.Authentication.LDAP.Port = 636;
    Comments
  2. Entering and exiting HTTPS with ASP.NET MVC

    March 25, 2010

    I think I’ve found a relatively painless and DRY way to apply SSL/HTTPS selectively to certain actions in an ASP.NET MVC application.

    I’ve looked into several approaches including Steve Sanderson’s self-admittedly hack-ish approach which I won’t go into here because it’s an excellent article revealing why this is a difficult problem with ASP.NET. Steve’s is probably the ideal approach, but shortcomings in System.Web.Routing prevent you from doing it cleanly. It’s well worth the read.

    There are also quite a few other methods which use various methods to generate links with the correct scheme, but they involve changing all your views and generally repeating yourself all over the place - they work but they’re not pretty.

    As you might know, MVC 2 now provides a [RequireHttps] attribute - so entering HTTPS is pretty much a solved problem. The problem with this attribute is that once you’re in HTTPS mode, you stay there. So how to exit?

    My solution is to implement an action filter called [ExitHttpsIfNotRequired] which can be applied to a controller or action and automatically redirects to HTTP if [RequireHttps] isn’t also applied.

    Here it is:

    public class ExitHttpsIfNotRequiredAttribute : FilterAttribute, IAuthorizationFilter {
        public void OnAuthorization(AuthorizationContext filterContext) {
            // abort if it's not a secure connection
            if(!filterContext.HttpContext.Request.IsSecureConnection) return;
    
            // abort if a [RequireHttps] attribute is applied to controller or action
            if(filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;
            if(filterContext.ActionDescriptor.GetCustomAttributes(typeof(RequireHttpsAttribute), true).Length > 0) return;
    
            // abort if a [RetainHttps] attribute is applied to controller or action
            if(filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(RetainHttpsAttribute), true).Length > 0) return;
            if(filterContext.ActionDescriptor.GetCustomAttributes(typeof(RetainHttpsAttribute), true).Length > 0) return;
    
            // abort if it's not a GET request - we don't want to be redirecting on a form post
            if(!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) return;
    
            // redirect to HTTP
            string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
    }
    

    [RetainHttps] is basically an empty attribute which can be used to signal to [ExitHttpsIfNotRequired] to not mess with anything and just leave the scheme as it is. You can apply this to controllers which return dynamic resources embedded in another HTTP or HTTPS page (like CSS and images). So if the requesting page is using HTTPS, the resource controller can apply [RetainHttps] and say “just keep doing whatever you were doing”. Here it is:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class RetainHttpsAttribute : Attribute {
    }
    

    Benefits

    It’s reasonably DRY - you can apply the [RetainHttps] attribute to your base controller class once, and then selectively apply [RequireHttps] and [RetainHttps] where required.

    Also, it’s relatively simple to understand and implement.

    Shortcomings

    Entering and exiting HTTPS is always done with a redirect. Links which are entrance or exit points to HTTPS are shown in the incorrect scheme, and only by following the incorrect link do you end up at the correct one. Not ideal, but it’s not too bad.

    Overall

    I think the relative simplicity of this approach makes it a very good option. I’m also confident enough to use it in a production. I’d be very interested to hear whether or not you think it’s a good approach.

    Thanks for reading!

    Comments
  3. Random word generator

    January 12, 2010

    I wanted to auto-generate passwords that were random but not the sort of unreadable gibberish that comes from just combining letters and numbers (you know, stuff like 8ajOga64asiHip). Something close enough to language that a human can read it and remember it.

    I couldn’t find anything like this, so I came up with my own random word generator which applies some basic rules to get language-like words. Here are some examples of the sort of words it generates:

    • grelleduge
    • paldagrash
    • tecki
    • gaftap
    • rhodebap

    I’ve put up a demo which shows the result. You can also download the C# source code.

    I was aiming to get words that were something like Flanimals names (e.g. mung ungler, gruntloidian mampaddler), but it’s looks more like a cross between Dutch and Polish so far. Turns out Ricky Gervais can’t be replaced by a machine yet. Has anyone else tried this? Not replacing Ricky Gervais with a machine, but generating readable random words?

    Comments
  4. CAS on Windows: localhost setup in 5 mins

    January 4, 2010

    CAS (Central Authentication System) is a simple, secure single sign-on system. In my experience connecting CareerHub to university login systems, I love it when unis use CAS because it’s so elegantly simple to integrate with.

    If you need to test CAS authentication in a Windows development environment, these step-by-step instructions should get you running in about 5 minutes.

    1. Download Tomcat, extract to any folder.
    2. Run [tomcat_folder]\bin\startup.bat to start Tomcat. If you get an error about JAVA_HOME or JRE_HOME, set one of those environment variables, e.g:
      SET JRE_HOME=C:\Program Files (x86)\Java\jre6
      (I added this to my startup.bat file so it isn’t set system wide)
    3. Download the CAS zip file, grab the .WAR file from cas-server-[version]\modules and put it in [tomcat_folder]\webapps - it should take a while to copy and then you should see a new folder appear: [tomcat_folder]\webapps\cas-server-webapp-[version].
    4. Go to http://localhost:8080/cas-server-webapp-[version], you should see a CAS login page.
    5. By default, CAS comes configured to use a simple authentication handler where it accepts any login attempts where the username (NetID) and password are the same - so try logging in with username “test”, password “test” or similar.
    6. If you don’t want to mess around with configuring SSL for Tomcat, disable secure cookies for CAS by editing [cas-webapp]\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml and setting p:cookieSecure="false". You’ll need to shutdown and startup Tomcat for the changes to take effect.

    Done! That’s all there is to it. You can now get busy integrating your application with this test server. If you haven’t integrated a website with a CAS server before, don’t worry - it’s almost a no-brainer.

    If you want to quickly specify some username/password combos, you can replace this SimpleTestUsernamePasswordAuthenticationHandler with one of the generic authentication handlers in [tomcat_folder]\webapps\cas-server-webapp-[version]\WEB-INF\deployerConfigContext.xml.

    Comments
  5. The death of the software training manual

    December 7, 2009

    We recently came into possession of a training manual for a (relatively simple) application used by one of our clients. Wow. 300+ pages of step-by-step instructions for each action that a user might need to perform. What’s amazing is that the software is actually so complex that it would be very difficult to use it without having read the manual.

    It goes without saying that this is an automatic fail. A simple application that requires expert training to use is a sign of programmers trying to get the user to understand the underlying model of the software. What they should have done, is try to understand the user’s model of the task and craft the user interface to fit that as closely as possible.

    Of course, that’s much harder work for the developer.

    But when you get to the point where you’re maintaining a 300 page manual to support your users, you have to wonder if investing a bit of time and consideration in the user experience up front might have been a small price to pay. Not to mention you might have had a user base that was happy, productive and… larger.

    So that leads me to the point of this post: for anything but expert systems, the software training manual is dead. If you’re even thinking about writing a manual for end-user software, just delete all your code and start again. You’ve failed. With the innovative simplicity of the web, people expect to just be able to jump in and use your product. Show them a training manual and they’ll start looking elsewhere.

    Good developers realise this, and they go out of their way to make their products drop-dead easy-to-use. Take this excerpt from the LessAccounting FAQ:

    If you cannot utilize this site by just looking around we haven’t accomplished our goal.

    Don’t make me read

    Any successful end-user application reaches a point where it has some functionality that requires a bit of expert knowledge. And for expert tools like CAD programs and programming tools, it’s a given that you need expert training options up-front.

    How best to train your experts is a difficult question because of different learning styles, but the most recent trend seems to be towards training videos. I do a lot of reading, but when I came across Rob Conery’s training videos for the MVC Storefront suddenly I was watching an expert at work. It was an eye-opening experience for me because I learnt a lot and it was enjoyable.

    So we’re trying out this approach out at work with the CareerHub Training website which is primarily video-based training. It might not be perfect for everyone, but it beats a training manual any day.

    UPDATE: I just came across Screen Steps Live - a tool to create “just in time” documentation. Doing it this way makes sure you’re answering questions your customers actually have.

    Comments
  6. 2 more reasons why you might get a blank page in IIS 7

    October 29, 2009

    I’m still fairly new to IIS 7 and getting used to the blank pages it serves up when it’s not happy with the way you’ve configured a website. It reminds me a bit of the kind of error handling you used to see sometimes in VB6 with

    on error resume next

    I think the philosophy that this sort of error-handling follows is along the lines of “never admit something went wrong!” And a corollary of this is that you never, EVER log what went wrong because that’s a permanent record of your failure as programmer to create the perfect program.

    IIS 7 seems to follow this approach - I haven’t been able to find a helpful log message for any of my blank page responses, so I usually just resort to playing with settings until it works.

    Anyway, here’s a couple of common causes for the blank page in IIS 7 that I’ve come across.

    Please note that some or all of these errors may arise because I like to create separate websites with a DNS entry in etc/hosts, rather than create virtual directories under the default website. This is so I can mimic the production environment of a multi-tenanted app a bit more closely, where I use URLs like “shop1.local” instead of “localhost/shop”.

    File permissions

    If you’re running a website outside the wwwroot folder, you probably need to give the ‘Everyone’ group view and execute permissions on the folder. It doesn’t seem to work with if you do this for the Network Service account.

    CPU architecture differences

    If you’re running a website on an x64 machine but the binaries were compiled for a 32-bit system, you need to enable 32-bit applications.

    This can be done by choosing your application pool > Advanced Settings > Set “Enable 32-Bit Applications” = True.

    Comments
  7. Ruby on Rails editors for Windows

    August 23, 2009

    I’ve recently started learning Ruby and naturally one of the first things I needed to do was to find a good development environment. Notepad2 is great for Hello World applications but for anything more complex it becomes a bit painful. So I began my search for the best Ruby (and Rails) development environment I could find on Windows.

    Of course it’s important to define what I mean by “best”. My criteria for the best Ruby/Rails development environment on Windows are:

    1. Simple
    2. Fast

    Simple I’m a beginner Ruby programmer - I don’t need or want too much complexity in my editor. Syntax highlighting, multi-document “project” support and a nice looking, simple user interface are my main concerns.

    Fast

    My home development machine is 3 years old so it was important to find something lean and mean that wouldn’t make me wait around while it caught up with my (below-average) typing speed.

    The search begins

    I should point out that at this stage, what I really wanted was TextMate for Windows. I would have quickly handed over the $60 or so for it without looking any further if only there was a Windows version.

    Here’s a quick summary of what I tried:

    SciTE - included with the Ruby One-Click Installer for Windows. It’s simple and fast but lacks project support and has that Windows 2000 MFC look to it.

    InType - nice UI, looks very promising but it’s only Alpha status and development progress seems slow and a bit secretive (apparently, testing is limited to an exclusive “shadow community”). I’ll keep an eye on this one though.

    The Java-ish IDEs

    These are some more complete IDEs which all seem to be based on Eclipse. My main complaint with these is the same - they’re all suffer from that enterprise-iness that seems to inflict a lot of Java applications.

    Oh yeah, and they’re slow. An application that takes 60-90 seconds to just to load is an application I’m going to feel pretty good about uninstalling. Not to mention the dynamic intellisense stuff that goes on why I’m working and freezes the UI for a couple of seconds while I’m typing.

    Aptana RadRails - I first heard of this IDE plugin after Rob Conery posted his VibrantInk theme for it. I had to switch to a nightly build straight away because of a warning about “Identical code structures” which I couldn’t set to ignore. Also note the warning about incorrect spelling of “posts” in the screen shot above. There are a ton of other “helpful” features like this which became annoying so fast that I didn’t even get around to installing Rob’s theme.

    NetBeans - there is a Ruby-specific download of this IDE and the UI looks a lot more streamlined than RadRails. If only it didn’t take so long to load and feel so sluggish I would have spent a bit more time on this. When I started looking at customising the fonts and colours, I couldn’t get Consolas to stop looking ugly which was disappointing.

    What I didn’t try

    There are a couple of applications which I didn’t get around to trying but might be worth a look.

    E Text Editor - or simply ‘e’ to its friends, this is the closest thing to TextMate on Windows you can get. There’s one big catch though - it requires cygwin to use TextMate bundles. The way they market this is “The power of UNIX at your fingertips”. I’ve played with Ubuntu, Fedora, SUSE and other Linux distributions and that was fun. But I’m on Windows now and I want something that was designed to work with that OS. According to Wikipedia, a new beta of e allows running TextMate bundles natively in Windows - I’m looking forward to it. JetBrains Ruby Mine - from the people that brought you ReSharper. The ReSharper credentials would definitely appeal to some, but I find that plugin gets in the way more than anything so I feared the same from Ruby Mine - perhaps unfairly. Also it’s $99 and it looks like another Eclipse-like IDE, which I was a bit sick of by this stage.

    RubyDotNet VS integration - started by QUT (in my home town of Brisbane - go Brisbane!). It looks to be a bit abandoned at this point so I didn’t get around to trying it.

    Ruby in Steel

    Finally, I ended up going with Ruby in Steel, Text Edition (above). It’s snappy, theming is customisable enough and the UI is simple and responsive.

    You can install the text edition without a Visual Studio license (it can use the Visual Studio 2008 Shell which is freely distributable) so you can get this running for as little as $49. There is a developer edition available for $199, but the Text edition is more than enough for me.

    The installation is a bit rough around the edges, but once you get it installed it flies along in the VS 2008 shell.

    Comments
  8. ASP.NET MVC 1.0 areas

    June 15, 2009

    Areas (or grouping controllers into subsections of a site) are planned for ASP.NET MVC 2.0, but in the meantime there is a way to get this working with the current release.

    Phil Haack’s nice area prototype hasn’t been updated since the release candidate of ASP.NET MVC, but it still works with version 1.0 by following his instructions.

    But there is one catch that tripped me up - generic views don’t seem to work when they’re outside the ~/Views directory. For example, if you have a view in the ~/{Area}/Views folder with a page directive with a generic type in the Inherits attribute like this:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<list<person>>" %>

    You get the error “Could not load type ‘System.Web.Mvc.ViewPage<list<person»’.

    The way I got around this was to modify the configuration/system.web.pages element in my Web.config to set the pageParserFilterType to use the System.Web.Mvc.ViewTypeParserFilter, like this…

    <pages pageparserfiltertype="System.Web.Mvc.ViewTypeParserFilter">

    …and views in the non-root area that inherit ViewPage work fine.

    From some of Phil Haack’s pages on views with code behind during the development of MVC 1.0, it looked like the MVC ViewTypeParserFilter was the default page parser filter for MVC applications, but it seems this filter is somehow selectively applied to the ~/Views folder. I’d be interested to find out how they do this, but it’s kind of academic at the moment since it’ll probably all be changed for version 2.0.

    UPDATE: Thanks to the commenter who pointed out the way the MVC team did is was by setting the PageParserFilterType in the web.config inside the views folder.

    Comments
  9. Subdomains for a single application with ASP.NET MVC

    June 7, 2009

    Update: Complete source code demonstrating this approach is available on MSDN Code Gallery for MVC1 and MVC2.

    I’ve wanted to use subdomains for sub-sites within a single application for a while now, the way you see the Rails guys doing all the time (e.g. 37 signals, Shopify and LessEverything). Basically, instead of setting up multiple sub-sites like this…

    http://example.com/shop1/
    http://example.com/shop2/

    …I wanted to do this…

    http://shop1.example.com/
    http://shop2.example.com/

    …and still be able to create new sites dynamically without having to reconfigure IIS.

    Why would you want to do that?

    Using a subdomain rather than a path makes it much clearer (to users and search engines) that the sites are separate and distinct. Having separate domains also gives the customer a feeling of ownership - they’re not sharing the domain with anyone else.

    Setting up DNS for the development environment

    First I tried to add wildcard entries to my HOSTS file, but I quickly found out that doesn’t work. Then I started looking for some sort of DNS proxy that would allow me to define a wildcard DNS entry like *.local, so that shop1.local and shop2.local would automatically point to localhost.

    I couldn’t find anything like that, so I settled for manually updating my HOSTS file each time I added a new site. I know in production I can add wildcard DNS entries so I wasn’t too worried about finding a set-and-forget solution here.

    Getting it working in the Visual Studio 2008 ASP.NET Web Server

    The next problem I ran into was the built-in web server in VS2008 always returns “localhost” when you look at the HttpRequestBase.Url.Host property. The workaround I used was to instead look at the Host header from HttpRequestBase.Headers. This will usually come in with a port attached when debugging locally (e.g. “localhost:3308”) so you need to extract it like this:

    string host = requestContext.HttpContext.Request.Headers["Host"].Split(':')[0];

    Quick and testable design

    After playing around with the idea of defining a new Route handler that would look at the host passed in the URL, I eventually went with the idea of a base Controller that is aware of the Site it’s being accessed for. It looks like this:

    public abstract class SiteController : Controller {
        ISiteProvider _siteProvider;
    
        public SiteController() {
            _siteProvider = new SiteProvider();
        }
    
        public SiteController(ISiteProvider siteProvider) {
            _siteProvider = siteProvider;
        }
    
        protected override void Initialize(RequestContext requestContext) {
            string[] host = requestContext.HttpContext.Request.Headers["Host"].Split(':');
    
            _siteProvider.Initialise(host[0]);
    
            base.Initialize(requestContext);
        }
    
        protected override void OnActionExecuting(ActionExecutingContext filterContext) {
            ViewData["Site"] = Site;
    
            base.OnActionExecuting(filterContext);
        }
    
        public Site Site {
            get {
                return _siteProvider.GetCurrentSite();
            }
        }
    
    }

    ISiteProvider is a simple interface:

    public interface ISiteProvider {
        void Initialise(string host);
        Site GetCurrentSite();
    }

    This also allows for customers who want to bring their own domain - the sites don’t have to be subdomains of a default domain.

    Updates (March 5, 2010)

    Ben points out below that you need to do a bit of extra work when it comes to output caching so that output isn’t cached across all subdomains. My preferred method is to use the VaryByHeader=”Host” like this:

    [OutputCache(Duration=10,VaryByHeader="Host",VaryByParam="None")]
    public ActionResult Index() {
        // your code here
    }

    Ben shows how to do it with a VaryByCustom parameter below too.

    Also, here’s a simple example implementation of ISiteProvider, where MyDataContext is a LINQ to SQL data context:

    public class SiteProvider : ISiteProvider {
        MyDataContext _db;
        Site _site;
    
        public SiteProvider(MyDataContext db) {
            _db = db;
        }
    
        public void Initialise(string host) {
            _site = _db.Sites.SingleOrDefault(s => s.Host == host);
        }
    
        public Site GetCurrentSite() {
            return _site;
        }		
    }
    

    Ben gives an example below of how to do it with an in-memory cache of Sites. This will improve performance because it doesn’t have to load the Site from the DB for each request (I’d probably just tweak Ben’s solution to use a Dictionary<string,Site> instead of a List<Site> for the static cache variable).

    Comments
  10. About Me

    June 1, 2009

    I’m a web developer working at Visual Eyes Creative where we create web-based software for universities, like CareerHub and StudyStays.

    In my spare time I work on Studio Styles, Givlist and Anouk Invitations.

    Comments