ASP.NET - Jon Galloway

ASP.NET

Getting up to speed with Katana

You may have heard some talk about OWIN and the Katana Project over the past few years. Let's get the (kind of boring and abstract) definitions out of the way, then talk about why they're exciting and how you can learn more.

OWIN (Open Web Interface for .NET) defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

The Katana Project provides a set of OWIN implementations for Microsoft servers and frameworks.

In case it's not immediately obvious why those things are actually useful, let's throw some colorful pictures at the problem. Here's how ASP.NET has always worked:

Traditional ASP.NET Hosting Model

In this model, you work in a sandbox that provided you some known extension points. Creating a new ASP.NET application creates a special .NET project which has been tightly wired to the ASP.NET runtime, which in turn is pretty tightly wired to IIS. ASP.NET can be extended via with handlers and modules and the various ASP.NET frameworks (ASP.NET Web Forms, ASP.NET MVC, ASP.NET Web API, etc.) provide hooks that let you override or configure the way things work (IIS provides some extensibility points as well) but you're always aware that you're being hosted by ASP.NET and IIS.

OWIN defines a flexible, pluggable stack with a lightweight interface for web applications.

ASP.NET hosting under OWIN and Katana

Each component in the stack just needs to implement a function which accepts a dictionary (holding the application state) and returning a task. This flexible interface between layers provides a lot of benefits:

  • Fast - This is a really lightweight interface that doesn't need to bring along the whole ASP.NET / IIS party to every request, so it's really tight and can run really, really fast.
  • Pluggable - The middleware section in the above diagram shows more than one component. You can easily plug in lightweight components which modify your how your application runs. Middleware can handle all kinds of scenarios, including authentication and security, optimization, response modification, etc.
  • Flexible - You can mix and match anything that implements the OWIN spec, meaning you could drop ASP.NET applications with Katana on another server or host as well as host other .NET web frameworks (e.g. NancyFx, ServiceStack, Fubu, etc.) on any OWIN compatible server, with the flexibility to use any OWIN compatible middleware.

The Katana team is working to enable several really exciting scenarios, including hosting ASP.NET applications on OWIN hosts and plugging in OWIN middleware to existing ASP.NET applications.

Interested?

Great, because I've got a bunch of fresh, new recommendations on where you can find out more.

Whitepaper: An Overview of Project Katana

We just published a new whitepaper by Howard Dierking on the ASP.NET site: An Overview of Project Katana

Howard goes into a lot more detail about why Project Katana was started, how Project Katana implements OWIN, and how you can get started with Project Katana (complete with a nice walkthrough).

Video overview on Web Camps TV

Brady Gaster and Cory Fowler just interviewed Howard on Web Camps TV (Channel 9) last week. In this 45 minute video, Howard talks about Katana Project, builds out an application showing OWIN self hosting with an ASP.NET Web API application, and explains what's next for Project Katana.

The Katana Project - OWIN for ASP.NET

Podcast

We just interviewed Louis DeJardin (Principal SDE on the Katana team, @loudej, blog) on the Herding Code podcast last month. Detailed show notes are available here.

Download / Listen

Herding Code 164: OWIN and Katana with Louis DeJardin

What are you still doing here?

Go read, watch, and listen!

Posted by Jon Galloway | with no comments
Filed under:

Building Web Apps with ASP.NET Jump Start - Over 6 hours of free ASP.NET video training

Last Friday Microsoft Learning hosted Scott Hansleman, Damian Edwards and me for a full day live video Jump Start event titled Building Web Apps with ASP.NET. We had a nice crowd of about 2,300 attendees joining us during the event - but we were really excited about ending up with a full day of top quality training on ASP.NET 4.5, ASP.NET MVC 4, ASP.NET Web API, SignalR, and Visual Studio - all updated for the ASP.NET and Web Tools 2012.2 release. The Microsoft Learning team has a great studio, event platform, and team, and I think the videos turned out great.

Thanks

This wouldn't have been possible without the heroic efforts of both Scott Hanselman and Damian Edwards. Scott hadn't been feeling well earlier that week, but presented an entire day of training immediately after a full week at the MVP Summit. Damian wasn't originally scheduled for this, but he was free that day and jumped right in - originally Scott and I invited him just to do the SignalR talk, but when we found he was available the whole day we asked him to help on a bunch of other sessions.

Thanks also to the whole Microsoft Learning team, especially Frank Gartland for setting this up. The Microsoft Virtual Academy puts out a lot of great content, including full courses which help you keep up with new releases (and prepare for certification exams if you're interested).

Content and Sample Code

This content was based on the courseware I just helped update for our current Web Camps tour. A lot of the demos are available in the Web Camps Training Kit, available here. We've got a bunch of free, one day Web Camp events going on over the next few months - with several more being added as we finalize dates and locations.

Videos

All nine sessions (over six hours) are up on Channel 9 - you can watch them online (HTML5 video or Silverlight) or download them in a bunch of MP4 or WMV formats. I've got them embedded below, too.

(01) What's New in ASP.NET 4.5

Sections:

[02:51] - Web development overview

This session starts by overviewing what we're going to cover in the series. The only way I can keep up with all the new releases the ASP.NET and Web Tools teams keep cranking out is to work out a mental map of how it all fits together. For the purpose of this day, we broke things into foundations and scenarios. The foundations include One ASP.NET (including ASP.NET Web Forms, ASP.NET MVC, ASP.NET Web API, and SignalR), Visual Studio, NuGet, and Azure - specifically Windows Azure Web Sites). After covering those tools, we look at using using them in some modern web development scenarios, such as social web applications, mobile web development, etc.

[10:48] - ASP.NET Web Forms model binding

ASP.NET 4.5 includes what I consider the biggest, most fundamental and transformative change to Web Forms since it was first released - model binding. I would have loved to have this years ago, and if you're doing ASP.NET Web Forms and not taking advantage of the new data control features, I really think you're both working too hard and writing lower quality code than you should be. The ASP.NET and Web Tools 2012.2 release includes Friendly URLs support, which gives you the full benefits of URL routing - both cleaner URLs and binding of URL values to control data access methods. My demo shows using the models from the MVC Music Store tutorial in an ASP.NET Web Forms application; it's available in the Web Camps Training Kit.

[20:27] - Bundling and Optimization

Bundling and Optimization is built in to ASP.NET 4.5, so it works across the platform. Scott shows a great example demonstrating bundling and optimization extensibility with both CoffeeScript and LESS minification.

[39:53] - Page inspector

The Visual Studio 2012 Page Inspector lets you interact with the output of your web pages inside of Visual Studio. It's conceptually similar to browser dev tools, but since it's integrated to your source it can give you a lot better information and feedback, answering questions like "Which view / partial view / user control / etc. is actually generating this HTML?" I demo'd the basic features, then showed the new live update feature in the ASP.NET and Web Tools 2012.2 release.

[43:58] - Async

ASP.NET 4.5 includes support for Async just about everywhere, including ASP.NET Web Forms, ASP.NET MVC controllers, etc. Scott shows a nice, simple example in which he changes three synchronous operations to run in parallel in an ASP.NET Web Form.

(02) Building and Deploying Websites with ASP.NET MVC 4

Okay, this one was fun up until my demo fail cliff hanger right at the end. I started with File / New Project, built out a simple ASP.NET MVC site, and deployed it to Windows Azure Web Sites.

[01:26] - Intro to ASP.NET MVC

No ASP.NET MVC talk is compete without a few diagrams, so I start with a review of the how ASP.NET MVC works, complete with some fancy animated diagrams.

[03:58] - Creating a new ASP.NET MVC site

In this part of the talk, I show the different ASP.NET MVC project template, tour through the folder structure, show how routing works, explain the standard conventions used in ASP.NET MVC, and show how the controllers and views work together.

[15:19] - Adding a model, controller, view

This part of the presentation shows how to work with data in an ASP.NET MVC application using models and scaffolding, with data backed by Entity Framework Code First. I set up Entity Framework Code First Migrations to keep changes to my data model synchronized with my database over time.

[34:57] - Deploying to Windows Azure Web Sites

With a complete, working application, it's time to deploy. To the cloud! Well, kind of. I was aware that if people are accessing your URL during a first deployment it can cause problems, but I'd never seen it in practice. Someone F5 bombed me and the deploy failed, which, was corrected by redeploying an unchanged web.config file to refresh the site. But, the cool part is that we built and deployed a site - complete with database and migrations - in under an hour. One of our attendees was so inspired that he created another site to encourage Scott to survive the day: http://scottwillpullthrough.azurewebsites.net/

(03) Creating HTML5 Applications with jQuery

[02:31] - Introduction to HTML5

Scott and Damian explain what HTML5 is, and what it means to you as a web developer, including an overview of modern web development features like responsive design.

[13:13] - HTML5 markup

Scott and Damian show how HTML5 semantic tags are included in ASP.NET MVC 4 and ASP.NET Web Forms 4.5 templates and explain why they're useful. They explain why feature detection is preferable to useragent sniffing and show how Modernizr makes doing the right thing easy.

[27:06] - jQuery overview

Scott and Damian show why everyone's using jQuery and overview the basics. Damian showed off a simple demo I put together that's up on jsbin: http://jsbin.com/ijucaq/2/edit (play along at home!)

[48:04] - Visual Studio web tools

Scott shows off a bunch of great new web development features in Visual Studio 2012 (including the 2012.2 updates and the Web Essentials extension) with some cool examples like HTML5 form elements and the new Single Page Application templates.

(04) Building a Service Layer with ASP.NET Web API

This is a whirlwind tour of ASP.NET Web API, including some new features in 2012.2 (Help Pages, Tracing, and OData).

[01:32] - Introduction to Web API

We start by looking at the File / New Project experience for the Web API template, covering Help Pages and Tracing.

[14:40] - Consuming Web API from jQuery

This sample showed using jQuery and the OData query syntax to page through server-side data.

[20:44] - Consuming Web API from Windows 8

One of the key reasons for using ASP.NET Web API is that you're able to work with any client type that can "speak HTTP" - including mobile and desktop applications. In this sample, I demonstrated a Windows Store application that was calling back into an ASP.NET Web API service.

(05) Leveraging Your ASP.NET Development Skills to Build Office Apps

You might not have heard that you can write Apps for Office using web technologies like HTML5, jQuery, and ASP.NET. It's really pretty slick. I thought it was so cool, I squeezed in a quick 15 minute talk to show it off.

[01:25] - HTML5 and jQuery for Office 2013

I start by showing a simple Hello World example, using jQuery to read and write Excel data into a task pane. Note: my demos require the Microsoft Office Developer Tools for Visual Studio 2012.

[07:53] - Adding ASP.NET Web API

This demo goes a bit further by showing an Excel Task Pane app that posts data back to a backing ASP.NET Web API service, then displays the result. Brady Gaster wrote this demo; it's available in the Web Camps Training Kit.

[12:24] - What is an App for Office

After having explained the model, I showed how you can get and sell Apps for Office in the store, then showed where you can find more information.

(06) Building and Leveraging Social Services in ASP.NET

Several people told me this was their favorite session. The scripted part is good - it shows how to let your users log into your ASP.NET applications using OAuth and OpenID, then explains the new Facebook app template in the 2012.2 release.

But our live viewers really liked watching the unscripted part, when Scott and Damian troubleshot a problem with Twitter app setup because Twitter wouldn't allow an authentication callback to Scott's laptop. Hilarity - but also some pretty slick, on the fly troubleshooting - ensued.

03:02] - OAuth flow

Scott and Damian explain how OAuth works, and how you can use it to enable users to log into your ASP.NET sites without a password.

[06:34] - Demo - OAuth and OpenID

Scott and Damian set up Twitter and Google authentication for an ASP.NET application.

[27:47] - Facebook applications

Scott and Damian explain how Facebook Aps work, then show how the new Facebook app template makes it a lot easier to develop Facebook applications and interact with the Facebook "social graph".

(07) Building for the Mobile Web

Scott shows three options for how to deal with the the ever-growing percentage of mobile browsers: do nothing, change the client (adaptive rendering), or change the server (display modes or using jQuery Mobile)

08:24] - Adaptive rendering - change the client

Scott shows you can use CSS @media queries to adapt the HTML for different display dimensions.

[11:24] - Display modes and jQuery Mobile - change the server

Scott shows how you can use ASP.NET MVC 4 display modes to create generic mobile views or custom, device specific views. He demonstrates how to use mobile browser emulators to test how the display modes will work on the target device. You can find out more about mobile device simulators here: http://www.asp.net/mobile/device-simulators

Scott's walkthrough on working with jQuery Mobile in ASP.NET is really worth watching - he demonstrates how to take advantage of some more advanced jQuery mobile features using the ASP.NET MVC 4 Mobile template. You can find out more about using the some of the techniques Scott demonstrates in this tutorial: ASP.NET MVC 4 Mobile Features.

(08) Real-time Communication with SignalR

SignalR makes it easy to do real-time web applications in ASP.NET. If you want to learn about SignalR - and I'd suggest that you do - Damian is the guy. He and David Fowler started developing SignalrR as an open source library two years ago, and he gives a really clear explanation that's both deeply technical and understandable.

[08:00] - Demo - Move shape

Damian shows a nice visual example with two browsers communicating via a SignalR backend; moving a shape in one browser instantly moves it in the other browser. You can find the code for this demo in the SignalR ASP.NET samples, titled ShapeShare.

[29:18] - Connecting to SignalR with C# and JavaScript clients

Damian demonstrates concurrent connections to the same hub from a WPF client and several different browsers.

[36:56] - Real-time gaming: ShootlR

Damian shows off the ShootR multiplayer HTML5 game, with over 260 live players. He explains the mechanics, including the different game loops and how they optimize for realtime multiplayer games. The code for ShootR is available here.

[44:20] - Chat application: JabbR

Damian shows off the JabbR chat system and talks about scaling with backplanes, then shows off some new features they're working on.

(09) Taking Advantage of Windows Azure Services

[01:20] - Azure signup

I explain the Azure signup process and talk about what you can get for free. Scott and I talked about how little it costs, and talked about how caching can make that even lower.

[05:00] - DevCamps.ms

I talk about how we've been using Windows Azure Web Sites for the DevCamps.ms site, and Scott and I talk about the ability to scale up and down. I also explain how we use separate Windows Azure Web Sites instances for QA and Staging on DevCamps.ms, using Git deploy. Scott and I discuss the ability to be able to roll back to previous Git deployments if needed.

[08:45] - Single serving sites

I show off a quick example of a "single serving" site for quick code demos.

[09:40] - Windows Azure Store

Scott and I talk about services - many free - which are available in the Windows Azure Store. I show off a demo what you get in the free version of New Relic.

[15:36] - Azure command line

Scott shows off all the sites he's running in Windows Azure and demonstrates how he can use the Azure command line to manage his sites. He explains that they're written in JavaScript and run cross-platform; for more information on that, see this tutorial: How to use the Windows Azure Command-Line Tools for Mac and Linux

[20:06] - Wrap-up

Scott, Damian and I wrap up the day with an overview of what we've covered and where you can go for more information.

Guest (and occasional co-host) on Jesse Liberty's Yet Another Podcast

I was a recent guest on Jesse Liberty's Yet Another Podcast talking about the latest Visual Studio, ASP.NET and Azure releases.

Download / Listen:

Yet Another Podcast #75–Jon Galloway on ASP.NET/ MVC/ Azure

Co-hosted shows:

Jesse's been inviting me to co-host shows and I told him I'd show up when I was available. It's a nice change to be a drive-by co-host on a show (compared with the work that goes into organizing / editing / typing show notes for Herding Code shows). My main focus is on Herding Code, but it's nice to pop in and talk to Jesse's excellent guests when it works out. Some shows I've co-hosted over the past year:

Yet Another Podcast #76–Glenn Block on Node.js & Technology in China

Yet Another Podcast  #73 - Adam Kinney on developing for Windows 8 with HTML5

Yet Another Podcast #64 - John Papa & Javascript

Yet Another Podcast #60 - Steve Sanderson and John Papa on Knockout.js

Yet Another Podcast #54–Damian Edwards on ASP.NET

Yet Another Podcast #53–Scott Hanselman on Blogging

Yet Another Podcast #52–Peter Torr on Windows Phone Multitasking

Yet Another Podcast #51–Shawn Wildermuth: //build, Xaml Programming & Beyond

And some more on the way that haven't been released yet. Some of these I'm pretty quiet, on others I get wacky and hassle the guests because, hey, not my podcast so not my problem.

Show notes from the ASP.NET / MVC / Azure show:

  • What was just released
    • Visual Studio 2012 Web Developer features
    • ASP.NET 4.5 Web Forms
      • Strongly Typed data controls
      • Data access via command methods
      • Similar Binding syntax to ASP.NET MVC
      • Some context: Damian Edwards and WebFormsMVP
      • Two questions from Jesse:
        • Q: Are you making this harder or more complicated for Web Forms developers?
          • Short answer: Nothing's removed, it's just a new option
          • History of SqlDataSource, ObjectDataSource
        • Q: If I'm using some MVC patterns, why not just move to MVC?
          • Short answer: This works really well in hybrid applications, doesn't require a rewrite
          • Allows sharing models, validation, other code between Web Forms and MVC
    • ASP.NET MVC
      • Adaptive Rendering (oh, also, this is in Web Forms 4.5 as well)
      • Display Modes
      • Mobile project template using jQuery Mobile
      • OAuth login to allow Twitter, Google, Facebook, etc. login
    • Jon (and friends') MVC 4 book on the way: Professional ASP.NET MVC 4
    • Windows 8 development
      • Jesse and Jon announce they're working on a new book: Pro Windows 8 Development with XAML and C#
      • Jon and Jesse agree that it's nice to be able to write Windows 8 applications using the same skills they picked up for Silverlight, WPF, and Windows Phone development.
    • Compare / contrast ASP.NET MVC and Windows 8 development
      • Q: Does ASP.NET and HTML5 development overlap?
        • Jon thinks they overlap in the MVC world because you're writing HTML views without controls
        • Jon describes how his web development career moved from a preoccupation with server code to a focus on user interaction, which occurs in the browser
        • Jon mentions his NDC Oslo presentation on Learning To Love HTML as Beautiful Code
      • Q: How do you apply C# / XAML or HTML5 skills to Windows 8 development?
      • Q: If I'm a XAML programmer, what's the learning curve on getting up to speed on ASP.NET MVC?
        • Jon describes the difference in application lifecycle and state management
        • Jon says it's nice that web development is really interactive compared to application development
      • Q: Can you learn MVC by reading a book? Or is it a lot bigger than that?
    • What is Azure, and why would I use it?
      • Jon describes the traditional Azure platform mode and how Azure Web Sites fits in
      • Q: Why wouldn't Jesse host his blog on Azure Web Sites?
        • Domain names on Azure Web Sites
        • File hosting options
      • Q: Is Azure just another host? How is it different from any of the other shared hosting options?
        • A: Azure gives you the ability to scale up or down whenever you want
        • A: Other services are available if or when you want them
Posted by Jon Galloway | 4 comment(s)
Filed under: , ,

Adding an Admin user to an ASP.NET MVC 4 application using a single drop-in file

I'm working on an ASP.NET MVC 4 tutorial and wanted to set it up so just dropping a file in App_Start would create a user named "Owner" and assign them to the "Administrator" role (more explanation at the end if you're interested).

There are reasons why this wouldn't fit into most application scenarios:

  • It's not efficient, as it checks for (and creates, if necessary) the user every time the app starts up
  • The username, password, and role name are hardcoded in the app (although they could be pulled from config)
  • Automatically creating an administrative account in code (without user interaction) could lead to obvious security issues if the user isn't informed

However, with some modifications it might be more broadly useful - e.g. creating a test user with limited privileges, ensuring a required account isn't accidentally deleted, or - as in my case - setting up an account for demonstration or tutorial purposes.

Challenge #1: Running on startup without requiring the user to install or configure anything

I wanted to see if this could be done just by having the user drop a file into the App_Start folder and go. No copying code into Global.asax.cs, no installing addition NuGet packages, etc. That may not be the best approach - perhaps a NuGet package with a dependency on WebActivator would be better - but I wanted to see if this was possible and see if it offered the best experience.

Fortunately ASP.NET 4 and later provide a PreApplicationStartMethod attribute which allows you to register a method which will run when the application starts up. You drop this attribute in your application and give it two parameters: a method name and the type that contains it. I created a static class named PreApplicationTasks with a static method named, then dropped this attribute in it:

[assembly: PreApplicationStartMethod(typeof(PreApplicationTasks), "Initializer")] 

That's it. One small gotcha: the namespace can be a problem with assembly attributes. I decided my class didn't need a namespace.

Challenge #2: Only one PreApplicationStartMethod per assembly

In .NET 4, the PreApplicationStartMethod is marked as AllMultiple=false, so you can only have one PreApplicationStartMethod per assembly. This was fixed in .NET 4.5, as noted by Jon Skeet, so you can have as many PreApplicationStartMethods as you want (allowing you to keep your users waiting for the application to start indefinitely!).

The WebActivator NuGet package solves the multiple instance problem if you're in .NET 4 - it registers as a PreApplicationStartMethod, then calls any methods you've indicated using [assembly: WebActivator.PreApplicationStartMethod(type, method)]. David Ebbo blogged about that here:  Light up your NuGets with startup code and WebActivator.

In my scenario (bootstrapping a beginner level tutorial) I decided not to worry about this and stick with PreApplicationStartMethod.

Challenge #3: PreApplicationStartMethod kicks in before configuration has been read

This is by design, as Phil explains. It allows you to make changes that need to happen very early in the pipeline, well before Application_Start. That's fine in some cases, but it caused me problems when trying to add users, since the Membership Provider configuration hadn't yet been read - I got an exception stating that "Default Membership Provider could not be found."

PreApplicationStartMethod fires before config is loaded

The solution here is to run code that requires configuration in a PostApplicationStart method. But how to do that?

Challenge #4: Getting PostApplicationStartMethod without requiring WebActivator

The WebActivator NuGet package, among other things, provides a PostApplicationStartMethod attribute. That's generally how I'd recommend running code that needs to happen after Application_Start:

[assembly: WebActivator.PostApplicationStartMethod(typeof(TestLibrary.MyStartupCode), "CallMeAfterAppStart")]

This works well, but I wanted to see if this would be possible without WebActivator. Hmm.

Well, wait a minute - WebActivator works in .NET 4, so clearly it's registering and calling PostApplicationStartup tasks somehow. Off to the source code! Sure enough, there's even a handy comment in ActivationManager.cs which shows where PostApplicationStartup tasks are being registered:

public static void Run()
{
    if (!_hasInited)
    {
        RunPreStartMethods();

        // Register our module to handle any Post Start methods. But outside of ASP.NET, just run them now
        if (HostingEnvironment.IsHosted)
        {
            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(StartMethodCallingModule));
        }
        else
        {
            RunPostStartMethods();
        }

        _hasInited = true;
    }
}

Excellent. Hey, that DynamicModuleUtility seems familiar... Sure enough, K. Scott Allen mentioned it on his blog last year. This is really slick - a PreApplicationStartMethod can register a new HttpModule in code. Modules are run right after application startup, so that's a perfect time to do any startup stuff that requires configuration to be read. As K. Scott says, it's this easy:

using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;

[assembly:PreApplicationStartMethod(typeof(MyAppStart), "Start")]

public class CoolModule : IHttpModule
{
    // implementation not important 
    // imagine something cool here
}

public static class MyAppStart
{
    public static void Start()
    {
        DynamicModuleUtility.RegisterModule(typeof(CoolModule));
    }
}

Challenge #5: Cooperating with SimpleMembership

The ASP.NET MVC Internet template includes SimpleMembership. SimpleMembership is a big improvement over traditional ASP.NET Membership. For one thing, rather than forcing a database schema, it can work with your database schema. In the MVC 4 Internet template case, it uses Entity Framework Code First to define the user model. SimpleMembership bootstrap includes a call to InitializeDatabaseConnection, and I want to play nice with that.

There's a new [InitializeSimpleMembership] attribute on the AccountController, which calls \Filters\InitializeSimpleMembershipAttribute.cs::OnActionExecuting(). That comment in that method that says "Ensure ASP.NET Simple Membership is initialized only once per app start" which sounds like good advice. I figured the best thing would be to call that directly:

new Mvc4SampleApplication.Filters.InitializeSimpleMembershipAttribute().OnActionExecuting(null);

I'm not 100% happy with this - in fact, it's my least favorite part of this solution. There are two problems - first, directly calling a method on a filter, while legal, seems odd. Worse, though, the Filter lives in the application's namespace, which means that this code no longer works well as a generic drop-in.

The simplest workaround would be to duplicate the relevant SimpleMembership initialization code into my startup code, but I'd rather not. I'm interested in your suggestions here.

Challenge #6: Module Init methods are called more than once

When debugging, I noticed (and remembered) that the Init method may be called more than once per page request - it's run once per instance in the app pool, and an individual page request can cause multiple resource requests to the server. While SimpleMembership does have internal checks to prevent duplicate user or role entries, I'd rather not cause or handle those exceptions. So here's the standard single-use lock in the Module's init method:

void IHttpModule.Init(HttpApplication context)
{
    lock (lockObject)
    {
        if (!initialized)
        {
            //Do stuff
        }
        initialized = true;
    }
}

Putting it all together

With all of that out of the way, here's the code I came up with:

The Verdict: Is this a good thing?

Maybe.

I think you'll agree that the journey was undoubtedly worthwhile, as it took us through some of the finer points of hooking into application startup, integrating with membership, and understanding why the WebActivator NuGet package is so useful

Will I use this in the tutorial? I'm leaning towards no - I think a NuGet package with a dependency on WebActivator might work better:

  • It's a little more clear what's going on
  • Installing a NuGet package might be a little less error prone than copying a file
  • A novice user could uninstall the package when complete
  • It's a good introduction to NuGet, which is a good thing for beginners to see
  • This code either requires either duplicating a little code from that filter or modifying the file to use the namespace

Honestly I'm undecided at this point, but I'm glad that I can weigh the options.

If you're interested: Why are you doing this?

I'm updating the MVC Music Store tutorial to ASP.NET MVC 4, taking advantage of a lot of new ASP.NET MVC 4 features and trying to simplify areas that are giving people trouble. One change that addresses both needs us using the new OAuth support for membership as much as possible - it's a great new feature from an application perspective, and we get a fair amount of beginners struggling with setting up membership on a variety of database and development setups, which is a distraction from the focus of the tutorial - learning ASP.NET MVC.

Side note: Thanks to some great help from Rick Anderson, we had a draft of the tutorial that was looking pretty good earlier this summer, but there were enough changes in ASP.NET MVC 4 all the way up to RTM that there's still some work to be done. It's high priority and should be out very soon.

The one issue I ran into with OAuth is that we still need an Administrative user who can edit the store's inventory. I thought about a number of solutions for that - making the first user to register the admin, or the first user to use the username "Administrator" is assigned to the Administrator role - but they both ended up requiring extra code; also, I worried that people would use that code without understanding it or thinking about whether it was a good fit.

Posted by Jon Galloway | 1 comment(s)
Filed under: ,

Guest on Cloud Cover Show: What's new in Visual Studio 2012, ASP.NET 4.5, ASP.NET MVC 4 and Windows Azure Web Sites

I was the guest star on the Cloud Cover Show this past week talking about what's new for web developers in Visual Studio 2012, ASP.NET 4.5, ASP.NET MVC 4, and Windows Azure Web Sites. As a remote presenter (I recorded my screencast while at ThatConference in Wisconsin Dells), I was given the floating head treatment when first introduced:

I gave a 20 minute walkthrough, showing the following highlights:

  • File / New Project with ASP.NET 4.5
    • NuGet packages in the default template (and why that's good)
    • Adaptive rendering in the default ASP.NET 4.5 project template
    • A few Visual Studio 2012 web developer features (CSS color picker, fonts, HTML5 snippets)
    • Strongly typed data control
    • Model binding support
    • Note: ASP.NET 4.5 requires .NET 4.5, will be supported in Azure some time after .NET 4.5 GA
  • File / New Project with ASP.NET MVC 4
    • Supports both .NET 4 and .NET 4.5
    • New ASP.NET MVC 4 project types
    • Same template experience as ASP.NET 4.5 Web Forms - adaptive rendering, etc.
    • Code-based configuration moved to App_Start
    • OAuth login support
    • Add new ASP.NET Web API controller
    • Show Web API
  • Deploy MVC 4 Application to Windows Azure Web Sites
    • Create new website in Windows Azure Web Sites portal, download publish profile
    • Visual Studio 2012 Web Publish dialog
    • Publish and demo site

Thanks to Nick and Cory for inviting me on the show. I hope my disembodied head will be invited back on Cloud Cover again soon.

Posted by Jon Galloway | with no comments

ASP.NET 4.5, ASP.NET MVC 4, ASP.NET Web Pages 2, and Visual Studio 2012 for web developers: Part 1

Wow, yesterday was a big day for ASP.NET developers! In addition to some other very cool things, Microsoft announced Visual Studio 2012, ASP.NET 4.5, ASP MVC 4 were released to manufacturing. Hooray! So what now?

Get The Bits

The easiest way to get all the new goodies is to install Visual Studio 2012. You've got a few options there:

We've got the top download links listed for you on the ASP.NET site as well.

Note: Just install what you'll use

As before, my personal recommendation is to just install the Visual Studio components you're expecting to use. If you never do C++ development, installing all the C++ support just means that your install will take longer, take up more space, make service packs take longer to install, increase the Windows Updates you'll encounter, etc. You can always modify the installed features if you need to later. Here's what I'm installing (I'm including Blend because I've been doing a bit of Windows 8 app development - it works with both both XAML and HTML Windows Store apps).

Here's what I've got selected:

Visual Studio 2012 Install

Learning Resources On The New Stuff

There is a ton of new stuff, and it's easy to get overwhelmed. Here's a quick overview of some of the top resources before we dig into specifics:

ASP.NET 4.5

Model Binding and Strongly Typed Data Controls

The Model Binding and Strongly Typed Data Controls in ASP.NET Web Forms are really cool. Damian Edwards (who helped found the Web Forms MVP project before joining the ASP.NET team) and team pulled of an amazing feat: they brought the model binding and strong typing features of ASP.NET MVC into ASP.NET Web Forms in a way that still fits with Web Forms. Essentially, it's something like an object data source approach, but so much smoother.

First, the strongly typed data controls allow you to define a model type for a control. That allows you to replace string-based data binding expressions with strongly typed binding expressions:

Hooray!

Also, notice that the FormView above isn't binding to a data source, it's got methods defined for Select / Insert / Update. The select method looks like this:

public Issue GetIssue([Control("issuesGrid")]int? id)
{
    return _db.Issues.Find(id);
}

The Insert and Update methods take advantage of the binding features in MVC, allowing you to bind to control values, URL and other contextual values, and custom value providers:

public void InsertIssue()
{
    var issue = new Issue();

    TryUpdateModel(issue);

    if (ModelState.IsValid)
    {
        _db.Issues.Add(issue);
        SaveChanges(issue);
    }
}

This eliminates all the tedious and error-prone "this parameter equals that control value, this other parameter equal that other control value, kill me now" type code. Note that TryUpdateModel call (familiar to MVC devs) which will automatically apply any validation rules defined via data annotations on the model class.

I gave a presentation this week at ThatConference looking at the feasibility of mixing ASP.NET Web Forms and MVC in the same project, and my conclusion was that the best way to get started is to get your Web Forms apps on ASP.NET 4.5 so you can start sharing models and converting traditional Web Forms code towards this approach, which is a lot more similar to MVC.

Bundling and Optimization

Bundling and Optimization in ASP.NET 4.5 and ASP.NET MVC 4 is based on an optimization system the MSN team developed called WebGrease. The core has been battle tested (MSN is a top 20 site) and performs really well. The bundling and optimization system optimizes user experience by compressing and combining CSS and JavaScript so your users get a faster experience and you minimize your bandwidth.

You'll see default bundles defined in \App_Start\BundleConfig.cs in an ASP.NET 4.5 Web Forms or ASP.NET MVC 4 application. Here's what it looks like in Web Forms:

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include(
          "~/Scripts/WebForms/WebForms.js",
          "~/Scripts/WebForms/WebUIValidation.js",
          "~/Scripts/WebForms/MenuStandards.js",
          "~/Scripts/WebForms/Focus.js",
          "~/Scripts/WebForms/GridView.js",
          "~/Scripts/WebForms/DetailsView.js",
          "~/Scripts/WebForms/TreeView.js",
          "~/Scripts/WebForms/WebParts.js"));

    bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include(
        "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js",
        "~/Scripts/WebForms/MsAjax/MicrosoftAjaxApplicationServices.js",
        "~/Scripts/WebForms/MsAjax/MicrosoftAjaxTimer.js",
        "~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js"));

    // Use the Development version of Modernizr to develop with and learn from. Then, when you’re
    // ready for production, use the build tool at http://modernizr.com to pick only the tests you need
    bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
        "~/Scripts/modernizr-*"));
}

Now you can just use any of those bundles in your application:

 <asp:PlaceHolder runat="server">        
         <%: Scripts.Render("~/bundles/modernizr") %>
         <%: Scripts.Render("~/bundles/jquery") %>
         <%: Scripts.Render("~/bundles/jqueryui") %>
</asp:PlaceHolder>

One of my favorite parts about this is that we can make bundles that accomodate version numbers in script names, so updating jQuery (maybe via NuGet if you're awesome) doesn't require *any* code / markup changes:

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
            "~/Scripts/jquery-{version}.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
            "~/Scripts/jquery-ui-{version}.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
            "~/Scripts/jquery.unobtrusive*",
            "~/Scripts/jquery.validate*"));

For more on using Bundling and Minification in Web Forms, see Adding Bundling and Minification to Web Forms (Rick Anderson) or either of the following videos:

Quick intro by Scott Hanselman:

Deep Dive by Howard Dierking:

Updated Project Templates (Adaptive Rendering)

Both the new ASP.NET Web Forms and MVC project templates have been redesigned. They don't just look nicer, they leverage web standards to automatically adapt to screen resolution (HTML and CSS only, no JavaScript or server-side code required).

Here's how the default template looks in a wide screen (> 850px):

2012-08-16_16h50_39

Resizing the screen automatically applies new styles via CSS media queries so it's easier to read and navigate:

2012-08-16_16h50_47

I wrote about how this works in pretty gory detail in the context of ASP.NET MVC 4, but it's working exactly the same in ASP.NET Web Forms 4.5.

OAuth and OpenID support

The default project templates now have built-in support for user registration and log in via OAuth and OpenID. They're making use of the excellent DotNetOpenAuth library, included as  a NuGet package so you can update later if you'd like.

Your OAuth and OpenID providers are registerd in \AppStart\AuthConfig.cs. Initially there are some examples that are all commented out (this is something you should do explicitly, and OAuth providers require you fill in an app id and app secret):

public static void RegisterOpenAuth()
{
    // See http://go.microsoft.com/fwlink/?LinkId=252803 for details on setting up this ASP.NET
    // application to support logging in via external services.

    //OpenAuth.AuthenticationClients.AddTwitter(
    //    consumerKey: "your Twitter consumer key",
    //    consumerSecret: "your Twitter consumer secret");

    //OpenAuth.AuthenticationClients.AddFacebook(
    //    appId: "your Facebook app id",
    //    appSecret: "your Facebook app secret");

    //OpenAuth.AuthenticationClients.AddMicrosoft(
    //    clientId: "your Microsoft account client id",
    //    clientSecret: "your Microsoft account client secret");

    //OpenAuth.AuthenticationClients.AddGoogle();
}

Uncommenting and filling in the key / secret information for OAuth clients changes your Log In screen to allow users to access your site as members without creating an account:

2012-08-16_16h59_15

For more information on configuring specific clients, see Pranav's blog post: OAuth/OpenID Support for WebForms, MVC and WebPages.

And much more...

There's of course a lot more, these are just some of my favorite features. Let's move on to ASP.NET MVC 4!

ASP.NET MVC

Mobile Features

ASP.NET MVC 4 has several great options to help you build sites that work well on mobile devices. Here's a diagram that helps illustrate it:

2012-08-16_19h10_27

I talked about all three of these and overviewed ASP.NET MVC 4 mobile features at aspConf:

We've already talked about adaptive rendering in Web Forms, it works the same here.

Display Modes allow you to create views which are served to mobile devices, and you can create your own display modes to target specific devices. Since the display modes are defined in code, they can be based on any logic you want - database queries, user cookies, day of the week, whatever. Here's how a display mode is defined:

DisplayModeProvider.Instance.Modes.Insert(0, new 
DefaultDisplayMode("iPhone") 
{ 
    ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf 
        ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0) 
 });

Finally, the mobile template (based on jQuery Mobile) makes it easy to create web applications that are optimized for mobile users.

To learn more about what you can do using the Mobile Project Template, see Rick Anderson's tutorial: ASP.NET MVC 4 Mobile Features.

K. Scott Allen did a great presentation on the Mobile Project Template and jQuery Mobile at NDC 2012:

Scott Allen - ASP.NET MVC and jQuery Mobile from NDCOslo on Vimeo.

Async Support

ASP.NET MVC has had async support since MVC 2, but it was hard. It gets a lot easier in MVC 4 due to async and await. Once again, I'll refer to Rick Anderson's excellent tutorial: Using Asynchronous Methods in ASP.NET MVC 4. Here's an example of an async controller method that calls three long running services and returns to the user when all three are complete:

public async Task<ActionResult> PWGasync() 
{ 
    ViewBag.SyncType = "Asynchronous"; 
    var widgetService = new WidgetService(); 
    var prodService = new ProductService(); 
    var gizmoService = new GizmoService(); 
 
    var widgetTask = widgetService.GetWidgetsAsync(); 
    var prodTask = prodService.GetProductsAsync(); 
    var gizmoTask = gizmoService.GetGizmosAsync(); 
 
    await Task.WhenAll(widgetTask, prodTask, gizmoTask); 
 
    var pwgVM = new ProdGizWidgetVM( 
       widgetTask.Result, 
       prodTask.Result, 
       gizmoTask.Result 
       ); 
 
    return View("PWG", pwgVM); 
}

OAuth and OpenID support

Yes, already mentioned before in Web Forms, but it's also in MVC 4, and it's really cool.

The ASP.NET MVC 4 Release Notes cover these and other features in more detail.

ASP.NET Web API

ASP.NET Web API is officially released! I did a series of screencasts earlier this year that introduce ASP.NET Web API. They're slightly out of date on a few technical details (I'll be updating them soon) but explain what it is and why you'd use it; here's the first in the series:

[Video and code on the ASP.NET site]

The team wrote some great posts on recent features:

Wow, that's a lot, and we didn't even get into Visual Studio 2012 features for Web Developers! Looks like it's time for a break, with a part 2 to follow...

ASP.NET MVC Authentication - Customizing Authentication and Authorization The Right Way

We're continuing the ASP.NET Authentication series (yes, I'm doing a few overlapping series, and yes, it's making me dizzy). The previous post covered Global Authentication and Allow Anonymous. This one continues with a simple tip that can be summed up as follows: keep it simple by extending rather than rewriting.

I see a lot of questions that involve unnecessary complications, and very often it's due to customizing authentication and authorization. For example, developers see that the AuthorizeAttribute won't work for their case, so they start to write a lot of code - using HttpModules, custom view engines, injecting authentication services and sprinkling authorization service calls throughout their controllers, etc.

Sometimes that's necessary, but it's rare. Most of the time you can handle things with either a custom membership provider, a subclassed AuthorizeAttribute, or both. Craig Stuntz summed this up well in a blog post back in 2009:

If you are developing a web application which requires authentication or security features not included in the regular ASP.NET membership feature, you might decide to implement these features yourself. But it seems as if the first instinct of many ASP.NET MVC developers is to do this by customizing their Controllers, because they’ve decided that AuthorizeAttribute can’t possibly serve their needs. They will decide that the way to do this is to write some sort of parent Controller type which examines the currently logged-in user when an action executes and changes the result of the action based on who they are. Others will try to re-implement AuthorizeAttribute without ever examining the source code for the original.

These are very bad approaches, for two important reasons:

  1. They don’t work. If your action result is cached by ASP.NET, then the action will not even run the next time it is requested. AuthorizeAttribute handles this correctly. Code you write in a Controller cannot handle this. Code you write in a custom action filter could work, if you cut and paste the implementation from AuthorizeAttribute. But AuthorizeAttribute is unsealed, so why cut and paste, when you can subtype?
  2. The modularity is wrong. You should aim to develop MVC sites which can be used with any authentication (or role) provider, whether it is ASP.NET membership, domain authentication, OpenId, or a custom membership provider. Wiring authentication concerns into a Controller makes this extremely difficult.

Craig recommends the same thing I'll be recommending - leverage the existing security systems in ASP.NET and ASP.NET MVC.

ASP.NET MVC's authorization system runs directly on top of the existing ASP.NET security system, and both have well established and tested extensibility points.

  • If you need to customize the way ASP.NET MVC integrates with the underlying ASP.NET security system, subclass the AuthorizeAttribute
  • If you need to customize the way the underlying ASP.NET membership system works, leverage the existing ASP.NET security provider system

I'll throw in one more - make sure you really need to customize anything at all.

Step Zero: Do you need to customize anything?

I've seen some examples that use the techniques below to implement authorization features... which didn't need implementing because they were already built in. AuthorizeAttribute, for example, already includes support for role-based authorization, but I've seen sample code that "adds in" role checking.

I've also seen examples which were built because the author assumed that AuthorizeAttribute only worked with Forms Authentication. That's not true - it just verifies if the user (1) is authenticated (2) is in the listed users and/or roles (if any are set). The same AuthorizeAttribute works with other authentication methods - the same attribute is also used with Windows Forms in the Intranet Application template, as well.

The AuthorizeAttribute has a pretty narrowly defined job, so it doesn't take much work to verify whether it already does what you need - check first.

Quick Note: Authentication and Authorization

Any sufficiently long article on web security must eventually devolve into distinguishing between authentication and authorization, so here goes:

  • Authentication is the act of establishing who the user is.
  • Authorization is the act of determining if that user should have access to a resource.

A user may be authenticated but not authorized to access a resource - e.g. a simple user isn't authorized to access site administration pages. A user may be authorized, but not authenticated - e.g. a site which allows anonymous access, a site which controls access using an API / access key, etc.

Customizing ASP.NET MVC's Interaction with ASP.NET Authorization by subclassing AuthorizeAttribute

Subclassing an AuthorizeAttribute is pretty straightforward. In most cases you just create a class that inherits form AuthorizeAttribute and override AuthorizeCore. Here's a very simple example: a key based login.

A simple key based AuthorizeAttribute

In this example, we'll be setting up a custom authorization scheme based on a key which will be validated using a very simple algorithm. This isn't secure for any number of reasons, but with some minor modifications (e.g. expiring a key once it is used) it would be sufficient for things like simple beta program for a pre-release website.

We'll accept a parameter called X-Key and validate that it's a number that passes a simple check.

To start with, we'll create a new class called KeyAuthorizeAttribute that inherits from AuthorizeAttribute:

public class KeyAuthorizeAttribute : AuthorizeAttribute  
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string key = httpContext.Request["X-Key"];
        return ApiValidatorService.IsValid(key);
    }
}

public static class ApiValidatorService
{
    public static bool IsValid(string key)
    {
        int keyvalue;

        if (int.TryParse(key, out keyvalue))
        {
            return keyvalue % 2137 == 7;
        }
        return false;
    }
}

This AuthorizeCore method checks a value (via header, querystring, form post, etc.) and calls into a service to validate it. In this case, validation is a simple static method that runs our validation algorithm. In your case, you'd probably want to check against a list of pre-issued keys in a database, call out to an external service, etc. AuthorizeCore returns a boolean value - pass or fail.

We can then slap that [KeyAuthorize] attribute on any action or controller in the site, or register it globally (as shown in my previous post).

This request would be allowed: http://localhost:8515/?X-Key=26381272 (because 26381272 mod 2137 equals 7)

This request would be denied: http://localhost:8515/?X-Key=12345

Handling Authorization Failures

AuthorizeAttribute is based on Forms Authentication, so when a request fails a call to the AuthorizeCore method of an applicable AuthorizeAttribute, it will by default redirect to the login page so that, hopefully, the user can get authorized. I walked through the mechanics of this redirection process in a previous post.

The default login page doesn't make any sense in a lot of scenarios, including the example above. If someone comes to my site with a missing or incorrect API key, the login page isn't going to help them. For that specific case, I'd perhaps want to redirect them to a page that tells them how to apply for an access key.

If you need to change what happens when users fail authentication, you've got a few options:

  1. If you want to change the site-wide redirection URL for when a request fails authorization, you can change the authentication/forms/loginUrl setting in web.config. Keep in mind, though, that this affects all authentication redirects for your entire application.
  2. If you want to run custom logic - including but not limited to redirecting to a URL - you can override the AuthorizeAttribute's HandleUnauthorizedRequest method.

Many more examples

This is a very simple example. You can find a lot more by searching on the override code above, e.g. "override authorizecore httpcontextbase". Some examples:

Note: The last one on the list implements the base AuthorizeAttribute interfaces rather than subclassing AuthorizeAttribute, which bears some discussion.

Subclass AuthorizeAttribute or Implement FilterAttribute, IAuthorizationFilter?

If you just look at the AuthorizeCore code in the AuthorizeAttribute, you may think it's so trivial you might as well just build your own IAuthorizationFilter from scratch. The problem with that idea is that it's very easy to do that incorrectly. A large amount of the code in the AuthorizeAttribute is there to make sure it works correctly with caching. If you get this wrong, you can very easily open yourself up to this scenario:

  1. Authorized user accesses an action and is correctly granted access.
  2. The action uses output caching, so the output is cached for future views.
  3. Unauthorized user accesses the action. Since it was cached, the restricted (or user-specific) content is served to the unauthorized user.

The AuthorizeAttribute has ensured that the code in the CacheValidateHandler and OnCacheAuthorization methods interact correctly with ASP.NET's caching system. Unless you really know what you're doing, it's a much better idea to start by subclassing AuthorizeAttribute.

Using AuthorizeAttribute with ASP.NET Web API

ASP.NET Web API uses the same AuthorizeAttribute scheme. It works the same way - drop an attribute on actions, API controllers, or globally, and you're set. All good so far.

But, if you use System.Web.Mvc.AuthorizeAttribute (or a subclassed attribute) on an Action Controller, nothing will happen. ASP.NET Web API uses a very similar, but different AuthorizeAttribute, found in the System.Web.Http namespace. There are some important differences (beyond the scope of this post), but a good place to look is at how the two AuthorizeAttributes handle unauthorized requests:

This reflects the difference between the target focus of both systems - ASP.NET MVC primarily focuses on HTML code that's viewed by people in a browser, and ASP.NET Web API primarily focuses on HTTP traffic that's handled by code. In ASP.NET Web API, you don't tell someone they're not authorized with a login page, you return the appropriate HTTP status code.

Fluent Security

If you have complex authorization requirements - particularly around configuration - you might want to look at Fluent Security. It provides a fluent, code-based configuration system, which lets you do define your application's authentication requirements in one place, like this:

SecurityConfigurator.Configure(configuration =>
{
    // Let Fluent Security know how to get the authentication status of the current user
    configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);

    // Let Fluent Security know how to get the roles for the current user
    configuration.GetRolesFrom(() => MySecurityHelper.GetCurrentUserRoles());

    // This is where you set up the policies you want Fluent Security to enforce
    configuration.For<HomeController>().Ignore();

    configuration.For<AccountController>().DenyAuthenticatedAccess();
    configuration.For<AccountController>(x => x.ChangePassword()).DenyAnonymousAccess();
    configuration.For<AccountController>(x => x.LogOff()).DenyAnonymousAccess();

    configuration.For<BlogController>(x => x.Index()).Ignore();
    configuration.For<BlogController>(x => x.AddPost()).RequireRole(BlogRole.Writer);
    configuration.For<BlogController>(x => x.AddComment()).DenyAnonymousAccess();
    configuration.For<BlogController>(x => x.DeleteComments()).RequireRole(BlogRole.Writer);
    configuration.For<BlogController>(x => x.PublishPosts()).RequireRole(BlogRole.Owner);
});

GlobalFilters.Filters.Add(new HandleSecurityAttribute(), 0);

Customizing ASP.NET MVC Authorization using the existing ASP.NET Security systems

ASP.NET has been around for a long time. It's been beaten on pretty hard, and the existing systems have undergone a huge amount of real-world testing. When you run into a constraint that pushes you towards writing some custom code, the best approach is to make sure you understand how the existing systems work and integrate with them as closely as possible.

Since ASP.NET has been around for a long time, there is a good amount of existing information on the security system. It's a big topic. I'm just going to (try to) summarize, pointing out the best extension points from an ASP.NET MVC point of view.

Extending the Forms Authentication provider

As mentioned earlier, authentication is the process of establishing who the user is. It doesn't say anything about what access you've got, it just verifies that you are who you claim to be. ASP.NET has some built in systems to handle that - the Forms Authentication provider handles browser based login and account management, and there's a Windows Authentication provider which integrates with the Windows authentication. If you need to modify how authentication works, you'll almost certainly be working with the Forms Authentication provider.

You might assume that you extend authentication by plugging in a new Authentication Provider, but that's not the case. There are two in the box Authentication Providers, and you can't add new ones. That's pretty much never an issue, though, because the Forms Authentication provider gives you plenty of hooks for extension.

Warning: The next paragraph is exceptionally nerdy, but it sets some important background for interfacing with Forms Authentication.

Forms Authentication uses a Forms Authentication Ticket to track your identity - essentially your authenticated username. The ticket is stored in an encrypted Forms Authentication Cookie.  There's support for cookieless authentication, which automatically appends cookie information via an encrypted querystring value. There are two main components that make Forms Authentication work - the FormsAuthetication class which sets the authentication cookie for authenticated users, and a FormsAuthenticationModule which checks for the cookie, authenticates you and sets your identity in the HttpContext. Since FormsAuthenticationModule is an HTTP module, it runs for every request, way at the beginning of the pipeline. That's an important part - a secure authentication system needs to check authentication at the beginning of the request.

This is all underlying machinery - the important part is that when someone logs in, something in your application calls FormsAuthentication.SetAuthCookie(). That sets the Authentication Cookie, which is then checked by the FormsAuthenticationModule on each request. You can see an example of how the default ASP.NET MVC AccountController Login method uses it:

[AllowAnonymous]
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

A good example is DotNetOpenAuth, which adds OpenID, OAuth, and InfoCard authentication to ASP.NET by integrating with the ASP.NET Forms Authentication ticket. You can see how this works in the DotNetOpenAuth OpenAuthAuthenticationTicketHelper.cs class, and in the OpenIdRelyingPartyMvc sample's UserController.

The important points here:

  • While it's tempting to look at your custom authentication needs as completely unique, most can be handled by determining who a user is (your code) and then telling ASP.NET Forms Authentication to track them.
  • If you decide that you'd rather just handle authentication outside of ASP.NET, you've got a lot to think about. You'll be writing a lot of new code which hasn't gone through near the security testing, beating, improvements, etc., that Forms Authentication has.

The ASP.NET Roles and Membership System

The above authentication discussion was completely independent of where and how the actual user information was stored, and that's important. Forms Authentication doesn't handle passwords, logins, user roles, etc., it just tracks users once it's been told about them.

ASP.NET Membership

The default system for managing user and is ASP.NET Membership. There's a SqlMembershipProvider that runs against a SQL Server database, but the provider system allows you to plug in your own custom Membership Provider for managing users. Your login process can use your membership provider to validate the user's credentials, and you can use the membership system to store user information if you want. More on that in a bit.

ASP.NET Role Management

For some sites, authorization and authentication are nearly synonymous - the only goal of authorization is to prevent anonymous access. But for many sites, you've got different roles - users, administrators, superadministrators, and omegasupremeadministrators. For those cases, you need something that maps users to roles, and that's what Role Management Providers do. In most cases, roles and membership are managed together - the same system that tracks who your users are controls what rights they have. You'll often see role and membership providers in one big package, but they're two separate things.

Customizing Membership in ASP.NET

As before, the zeroth rule of customizing membership is to reconsider if you need to. There are plenty of hooks into the existing flow, such as overriding OnAuthorization and just adding some information to HttpContext.Items, Session, etc.

If you really do need a custom user management system, the first thing to do is look to see if someone's already written it. There are membership providers for a lot of backing systems. A quick search shows tons of them:

Implementing your own Membership Provider

If you don't find a Membership Provider that works for you, it's not difficult to write your own. Remember that you're taking more responsibility for your system's security. Matt Wrock wrote a great overview: Implementing custom Membership Provider and Role Provider for Authenticating ASP.NET MVC Applications.

There's plenty of information on MSDN as well, for example: Implementing a Membership Provider

Simple Membership

You'll notice that a lot of Matt's overview of creating Membership and Role Providers included a lot of System.NotImplementedException, because the ASP.NET Membership Provider system shows some underlying assumptions around user data going in relational databases. You can just ignore those parts and use what you want, but if you find the whole thing a little too complex and are tempted to throw it all out, I'd recommend looking at SimpleMembership from ASP.NET Web Pages.

Matthew Osborn wrote an overview of what SimpleMembership is and how it works in ASP.NET Web Pages. Although it was originally written for ASP.NET Web Pages, it can be readily adapted to ASP.NET MVC using the SimpleMembership.Mvc NuGet package.

Wrapping Up

ASP.NET MVC gives you a huge amount of flexibility, and it's tempting to want to write a lot of custom code. If you understand the underlying security systems that ASP.NET MVC uses, though, you can usually integrate with what's in place. You'll be saving yourself a lot of unnecessary code, along with the added costs of testing, debugging and maintenance. More important, though, you'll be using a system that's undergone a huge amount of security testing over the past decade.

For further study:

Posted by Jon Galloway | 4 comment(s)
Filed under: ,

Upcoming Web Camps

We've got some great, free Web Camps headed your way!

Web Camps are free, fun, no-fluff events for developers, by developers. Show up for the day, leave infused with a crazy amount of web dev info. Did I mention these are free?

My teammate Brady Gaster has put together some phenomenal new content, and I'm really looking forward to presenting at some of these.

Web Camps Locations

So far the following locations have been announced:

Location Date Registration Notes
Brussels, Belgium 3-May-12 Register Here With Brady Gaster and Matthew Osborn... and there's still room!
Waltham, MA 10-May-12 Register Here I'll be here! Also starring Chris Bowen and Jim O'Neil!
Mountain View, CA 14-May-12 Register Here With the amazing Doris Chen!
Denver, CO 18-May-12 Register Here Also Doris Chen!
Phoenix, AZ 25-May-12 Register Here Also Doris Chen! Wow, she's busy!
Mountain View, CA 29-May-12 Register Here I'll be here! Maybe someone else, too.

There are a bunch more that are in the works but not quite ready to be announced yet - I'll update here, but the best place to keep up to date is at http://www.devcamps.ms/web

Oh, and I believe there's still room at the Web Camp in Brussels on May 3.

Web Camps Content

I've reviewed and contributed a bit to the Web Camps content that Brady's put together, and it's really, really good. There's a ton of information packed in. Here's an overview of the agenda (see the registration link for the exact agenda at each location):

  • Welcome Back to the Microsoft Web Stack
  • Integrating Your Site with Internet Explorer 9
  • Top 10 Things You Didn't Know about WebMatrix 2
  • Creating Rich HTML 5 Experiences
  • Building Web Sites Using ASP.NET 4.5
  • Building a Service Layer with ASP.NET Web API
  • Deploying ASP.NET Apps to the Cloud

You can read more about those topic at http://www.devcamps.ms/web/agenda.

Infomercial!

Now if you're almost convinced, but on the edge, and you need a video to push you over the top, you watch Brady and me announcing the Web Camps tour on Web Camps TV a few weeks ago:

Yes, if you read my blog you'll have noticed that this video is a repeat. That's how infomercials work.

Posted by Jon Galloway | with no comments
Filed under:

Juice UI: Open source ASP.NET Web Forms components for jQuery UI widgets

This morning at MVP Summit, Scott Hunter just announced a new open source project from appendTo called Juice UI. Juice UI is a collection of Web Forms components which make it incredibly easy to leverage jQuery UI widgets in ASP.NET Web Forms applications. You can start using it right away by adding the JuiceUI NuGet package to your app, and you're welcome to go nuts with the source, which is dual licensed under MIT and GPL.

What Juice UI does

jQuery UI is a library that's built on top of jQuery. It's got a lot of great widgets for common scenarios - things like date pickers, dialogs, and tabs - and they're all built on a really solid widget platform from some of the sharpest Javascript developers in the field. You've always been able to make use of these libraries using jQuery and jQuery UI, but the new Juice UI controls make it that much easier.

Example:

<asp:TextBox runat="server" ID="_Restrict" />
<Juice:Datepicker 
    runat="server" 
    TargetControlID="_Restrict" 
    MinDate="-20" 
    MaxDate="+1M +10D" />

Gives you this:

2012-02-28 09h16_03

Included controls and behaviors

Juice UI is launching with 14 widgets and behaviors. You can see the whole list of controls at http://juiceui.com/controls, and they've all got interactive examples.

2012-02-28 09h17_29

Here's the full list, linked to the documentation:

Walkthrough

Add the JuiceUI NuGet package

I'm going to start with a new ASP.NET 4 Web Forms project. I'll right click on the References folder, select Manage NuGet Packages..., and search for "juiceui"

2012-02-28 08h10_11

The JuiceUI namespace

The NuGet package adds the JuiceUI namespace to my web.config, like this:

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <pages>
      <controls>
        <add assembly="JuiceUI" namespace="Juice" tagPrefix="juice" />
      </controls>
    </pages>
  </system.web>
</configuration>

If needed, I remove that and use the <@Import Namespace="JuiceUI" /> directive to bring that namespace at the page level.

Using the Juice UI controls

You'll first need an <asp:ScriptManager> - you can add one to a page, or you can add one to your site's Master page.

<asp:ScriptManager id="_Script" runat="server" />

Now I can just start using the controls. These are extender controls, so you use the TargetControlID property to point the Juice UI behavior at an Web Forms server control. Here's a stripped down example that hooks up a DatePicker behavior to a TextBox:

<asp:TextBox runat="server" ID="DateSample" />
<Juice:Datepicker runat="server" TargetControlID="DateSample" />

And just because it's fun, I'll add a Draggable behavior that's pointed at a Panel:

<asp:Panel runat="server" ID="DragBox" Style="border:1px solid; width:100px;">
        Hi. You can drag me around.
</asp:Panel>
<Juice:Draggable runat="server" TargetControlID="DragBox" />

Note: I'm keeping this really simple for illustration here - of course the style would go in CSS, etc. There are more sophisticated examples in the Juice UI samples included with the source code.

Running this page shows I've got just what you'd expect - a date picker on the textbox, and a draggable panel.

2012-02-28 10h34_32

Here's the complete markup for that page:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="Juice_Sample._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">

    <asp:ScriptManager id="_Script" runat="server" />

    <asp:TextBox runat="server" ID="DateSample" />
    <Juice:Datepicker runat="server" TargetControlID="DateSample" />

    <asp:Panel runat="server" ID="DragBox" Style="border:1px solid; width:100px;">
        Hi. You can drag me around.
    </asp:Panel>
    <Juice:Draggable runat="server" TargetControlID="DragBox" />

</asp:Content>

And, in case you're interested, the widgets are hooked up using HTML5 data- attributes:

<input name="ctl00$MainContent$DateSample" type="text" 
        id="MainContent_DateSample" 
        data-ui-widget="datepicker" />

<div id="MainContent_DragBox" 
        data-ui-widget="draggable" 
        style="border:1px solid; width:100px;">
    Hi. You can drag me around.
</div>

This seems familiar...

It's a very similar experience to the Ajax Control Toolkit, but using jQuery UI as an underpinning. That is, create Web Forms extender and script controls for all the widgets and effects in jQuery UI. Don't read anything into this - work is still continuing on Ajax Control Toolkit (in fact, there have been quite a few updates lately). The ASP.NET team's long term direction for client side scripting is jQuery, though, and Juice UI helps you to integrate with that really easily.

Finding out more

The best place to find out more about Juice UI is on the Juice UI site, which has interactive examples and documentation.

The source (including a sample project) is in the GitHub repository.

I'd recommend getting help either on StackOverflow (using the juiceui tag) or in the ASP.NET jQuery forum.

10 Things ASP.NET Developers Should Know About Web.config Inheritance and Overrides

The ASP.NET configuration system is build around the idea of inheritance:

Each Web.config file applies configuration settings to the directory that it is in and to all of the child directories below it. Settings in child directories can optionally override or modify settings that are specified in parent directories. Configuration settings in a Web.config file can optionally be applied to individual files or subdirectories by specifying a path in a location element.

The root of the ASP.NET configuration hierarchy is the systemroot\Microsoft.NET\Framework\versionNumber\CONFIG\Web.config file, which includes settings that apply to all ASP.NET applications that run a specific version of the .NET Framework. Because each ASP.NET application inherits default configuration settings from the root Web.config file, you need to create Web.config files only for settings that override the default settings.

For a lot of sites, you don't really need to know about that - you can get by with one Web.config file for the site. But, knowing how the inheritance works - and how to control it - can really help out.

I've noticed that a lot of the questions I answer questions on forums, StackOverflow, and internal e-mail lists can be solved by better understanding how ASP.NET configuration inheritance and overrides work. And so, a bunch of tips about how ASP.NET configuration inheritance and overrides work! I'll start with some basics, but there are some towards the end I'll bet most ASP.NET developers don't know.

Tip 1: Using Web.config files in site subfolders

And ASP.NET website's Web.config is part of an inheritance chain. Your website's subfolders can have Web.config - an example is the Web.config file in an ASP.NET MVC application's View folder which does things like preventing directly viewing the View templates:

2012-01-12 23h57_09

This allows for setting general settings at the site level and overriding them when necessary. Any settings in the base Web.config that aren't overridden in the subfolder stay in effect, so the "child" Web.config can be pretty small. You can continue to nest them, so sub-sub-subfolders can get their own Web.config if needed. Some of the most common uses of subfolders are to restrict permission (e.g. requiring authentication or restricting access to resources), but you can also use them to do things like include default namespaces in Views, toggle handlers, etc.

Tip 2: Understand how your site Web.config inherits its settings

But there's an inheritance chain above the site, too. Here's a simplified version from the MSDN docs:

Configuration level

File name

File description

Server

Machine.config

The Machine.config file contains the ASP.NET schema for all of the Web applications on the server. This file is at the top of the configuration merge hierarchy.

IIS

ApplicationHost.config

ApplicationHost.config is the root file of the IIS 7.0 configuration system. It includes definitions of all sites, applications, virtual directories, and application pools, as well as global defaults for the Web server settings. It is in the following location:

%windir%\system32\inetsrv\config

Root Web

Web.config

The Web.config file for the server is stored in the same directory as the Machine.config file and contains default values for most of the system.web configuration sections. At run time, this file is merged second from the top in the configuration hierarchy.

Web site

Web.config

The Web.config file for a specific Web site contains settings that apply to the Web site and inherit downward through all of the ASP.NET applications and subdirectories of the site.

ASP.NET application root directory

Web.config

The Web.config file for a specific ASP.NET application is located in the root directory of the application and contains settings that apply to the Web application and inherit downward through all of the subdirectories in its branch.

ASP.NET application subdirectory

Web.config

The Web.config file for an application subdirectory contains settings that apply to this subdirectory and inherit downward through all of the subdirectories in its branch.

So your website's configuration's actually inherited a bunch of settings that were set at the server level. That's nice for a few reasons:

  1. It allows the ASP.NET / IIS teams to migrate settings that aren't commonly modified from the project template Web.config files to server defaults, keeping your Web.config files smaller and more readable. For example, ASP.NET 4 migrated a bunch of handler registrations to Machine.config, so the Empty ASP.NET Application Web.config is slimmed down to about 8 lines.
  2. You can override things at the server level as needed, and they'll take effect for all applications. For example, you can set <deployment retail="true"> on production servers to disable trace output and debug capabilities.
  3. You can find a lot of useful information in the Machine.config default settings since they're stored in plain text. For example, the ASP.NET Membership Provider has some defaults set for password requirements and the membership database, and you can look them up by looking in the appropriate .NET framework version's Machine.config. For a default installation of ASP.NET 4, that's found in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config with a quick search for <membership>.

Tip 3: Understand how your Web.config inherits IIS configuration settings

This overlaps a bit of Tip 2, but it bears repeating. Long-time ASP.NET developers (myself included) are prone to thinking of ASP.NET and IIS configuration separately, but that all changed with IIS 7. This is all pretty old news, as IIS 7 has been out for a while, but it hasn't been completely absorbed by ASP.NET developers.

CarlosAg summed this up well in a post from 2006(!) which explained The New Configuration System in IIS 7.  I'm not going to rehash his post here - go read it. Some important takeaways are that both the ApplicationHost.config and Machine.config feed into the configuration settings in your site's Web.config, as shown in Carlos' diagram:

In addition to the understanding how things work part of it, this is also good to know because - based on the info in Tip 2 - you can see what the base settings are, and how you can override them in your application's Web.config. This is why you can do pretty advanced things like configure rules on for the URL Rewrite Module in your application's web.config.

Of course, server administrators don't necessarily want to allow any application on the server to modify settings via Web.config, so there are configurable policies in the ApplicationHost.config which state whether individual applications can override settings. There's also an Administration.config file which controls things like Module registration.

There's one kind of new update to this list - using aspnet.config for Application Pool tuning. It's found in the same directory as Machine.config, and it's been around since .NET 2.0. However, as of ASP.NET 4 it's been expanded to handle things like concurrency and threading, as explained in Scott Forsyth's post, Setting an aspnet.config File per Application Pool. While not something most ASP.NET developers will need to use, it's good to know that you can control things like maxConcurrentRequestsPerCPU, maxConcurrentThreadsPerCPU and requestQueueLimit at the application pool level.

Tip 4: Location, location

While it's nice to be able to override settings in a subfolder using nested Web.config files, that can become hard to manage. In a large application, it can be difficult to manage settings because you can't see the effective permissions in one place. Another option is to use the <location> element to target settings to a specific location. For example, I previously showed how to use this to allow large file uploads to a specific directory in an ASP.NET application using the location element:

<location path="Upload">
    <system.web>

        <httpRuntime executionTimeout="110" 
                     maxRequestLength="20000" />
    </system.web>
</location>

Tip 5: Clearing parent settings when adding to a collection

Sometimes you want to remove all inherited settings and start fresh. A common place you'll see this is in handler, module, connection string and provider registration - places where configuration is used to populate a collection. Scott Guthrie blogged about an example in which just adding a new Membership Provider causes problems, because you end up with two providers - the default, and the one you just added. It's important to clear the collection before adding your new provider using the <clear/> element, like this:

<membership>
      <providers>
          <clear/>
          <add name="AspNetSqlMembershipProvider"
              type="System.Web.Security.SqlMembershipProvider, 
                    System.Web, Version=2.0.0.0, 
                    Culture=neutral, 
                    PublicKeyToken=b03f5f7f11d50a3a"
              connectionStringName="MyDatabase"
              enablePasswordRetrieval="false"
              (additional elements removed for brevity)
          />
      </providers>
</membership> 

As Scott explains, failure to <clear/> the collection first results in both providers attempting to handle membership, which probably isn't what you intended.

Tip 6: Locking settings with with allowOverride and inheritInChildApplications

You may need to prevent sub-applications from overriding or extending settings. You can do that with the allowOverride attribute, which does exactly what the name suggests - the same way a sealed class prevents changes via a derived class. The MSDN documentation summarizes this well:

You can lock configuration settings in ASP.NET configuration files (Web.config files) by adding an allowOverride attribute to a location element and setting the allowOverride attribute to false. Then within the location element, you can define the configuration section that you want to lock. ASP.NET will throw an exception if another configuration file attempts to override any configuration section that is defined within this locked location element.

Using a location element with an allowOverride=false attribute locks the entire configuration section. You can also lock individual configuration elements and attributes using lockItem, lockElements, lockAttributes, lockAllAttributesExcept, and lockAllElementsExcept.

That last part there - using attributes on sections - works because those lock attributes are among the general attributes inherited by section elements.

Tip 7: Disinheriting your child applications with inheritInChildApplications="false"

If you've got settings that should only apply to the parent application and shouldn't be inherited, you can use the inheritInChildApplications attribute on any section or location element. That makes the settings at the current level, but inheriting applications and subfolders don't have to bother with clearing and rebuilding configuration just to remove those settings.

This came up in a recent question on StackOverflow:  Unloading parts of a web.config file from a child application

Since Web.config is so heavily built on the concept of inheritance, it's not surprising that turning it off for a section can have some side effects. The aptly self-named "Run Things Proper Harry," a.k.a. rtpHarry, has written up two good posts covering usage and important things to be aware of.

Tip 8: Use configSource to separate configuration into separate files

While I've been discussing modification of Web.config settngs through inheritance, it only makes sense to mentions some useful ways to handle overriding Web.config settings.

Any Web.config section can be moved to a separate file by setting the configSource attribute to a file reference. I've mostly used this for handling connection strings, since it allows you a lot more flexibility over versioning and and deployment. Instead of having different Web.config files for each environment ("Oops! Just deployed the staging Web.config to production!!!"). It looks like this:

<configuration>
  <connectionStrings configSource="connectionStrings.config" />
  ...

Then your connectionStrings.config file only needs to change between environments, and can contain specific settings. It holds the contents of the element you're referring to, so it looks like this:

<connectionStrings>
  <add name="subtextData"
    connectionString="Server=.;Database=staging;Trusted_Connection=True;" />
</connectionStrings>

Another way I've seen this done is to have differently named connection strings config files for each environment (e.g. dev.config, staging.config, production.config). That allows you to check them all in to source control and not worry about getting files with the same name but different contents mixed up, but the tradeoff is that your Web.config in each environment needs to be updated to point to the right config source.

So, this is a handy trick, but isn't quite perfect. A better option is to use Web.config File Transformations.

Tip 9: Use Web.config Transforms to handle environmental differences

I don't hear as much about Web.config Transforms as I'd expect. Maybe they just work and everyone just quietly uses them and doesn't talk about it. But from the questions I see coming up over and over again, I'm not sure that's the case.

I love Web.config Transforms. At my first ASP.NET MVP summit, I was part of a feedback group discussing frustrations with deploying ASP.NET applications. Two themes that came up over and over were difficulties with packaging and managing configuration. That team later produced Web Deployment Packages (a nice format that packages files and settings for a site in a way that can be inspected and modified during installation) and Web.config Transforms.

All the new ASP.NET projects have Web.config transforms already set up - if you expand the Web.config node, you'll see that it's configured to create different settings for Debug and Release mode.

2012-01-17 14h51_29

It's really easy to use - your main Web.config has the base settings for your site, and whenever you build, the transforms for the appropriate build configuration (e.g. Debug or Release) are automatically applied. If you had a Test database that you wanted to use by default, but wanted your Release builds to run against the Production database, you could set it up so that your base Web.config connection string points to the Test Database connection string, like this:

<connectionStrings>
  <add name="ApplicationServices"
      connectionString="[TestDatabase]" />
</connectionStrings>

Then your Web.Release.config overwrites that to point at the Production database, like this:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings>
    <add name="ApplicationServices" 
        connectionString="[ProductionDatabase]" 
        xdt:Transform="Replace" xdt:Locator="Match(name)"/>
  </connectionStrings>
</configuration>

The syntax is pretty straightforward, but you don't need to worry about that because the comments in the Web.Release.config file already show how to do that.

To be clear: unlike the other examples, this is something that happens at build time, not runtime.

I recently ran into an issue where I wanted to deploy something to AppHarbor and wanted to switch between a local SQL Compact database and the hosted database server, and Web.config Transforms worked just great there.

There's a lot more to talk about with Web.config Transforms that's beyond the scope here, such as:

  • You can create as many build configurations as you want, with different transforms for each configuration. This makes it simple to switch between different settings in your development environment - say, switching between several development databases or other application settings.
  • You can use the configuration transformation system with any XML file using the SlowCheetah Visual Studio extension. Scott Hanselman's written a post with more information on that here: SlowCheetah - Web.config Transformation Syntax now generalized for any XML configuration file
  • Sayed (the Microsoft developer who's worked on both Web.config Transforms and the SlowCheetah extension) has also built a Package Once Publish Anywhere NuGet package which allows you to defer running the transforms until later, using a PowerShell command. That means you can build one Web Deployment Package with all the transforms included, and run them when you're going to deploy to a specific environment.

There's some good information on MSDN about Web.config Transforms:

Tip 10: Managing Application Restarts on Configuration Changes

There are a lot of moving parts in figuring out the configuration for a website, as illustrated above. For that reason, ASP.NET computes the effective settings for the site and caches them. It only recomputes them (and restarts the application) when a file in the sites configuration hierarchy is modified. You can control that on a section by section level using the restartOnExternalChanges property.

One place where configuration changes don't automatically get recomputed is for external config files set using configSource (as shown in Tip 8). You can control that by setting restartOExternalChanges="true" for that section. There's an example on MSDN that shows this in more detail by creating an external configuration file which is loaded via the configuration API (not referenced via configSource), then toggling the restartOnExternalChanges property and showing the differences in operation.

Summary

The ASP.NET Configuration system does quite a bit - I didn't even mention big topics like using the API for reading and writing values to both local and external config files or creating custom configuration sections. This post focuses on one aspect: getting things done by understanding and leveraging inheritance and overrides. Hopefully this gives you both some new tools for effectively handling configuration and some background that helps in troubleshooting when configuration is working as you'd like.

Are there any essential tips that I missed?

Posted by Jon Galloway | 57 comment(s)
Filed under:
More Posts Next page »