September 2009 - Posts

PROBLEM: CSS Styles No Longer Apply For Anonymous Users
28 September 09 08:34 AM | Scott Mitchell

I teach two ASP.NET courses as the University of California - San Diego Extension. In the second course students use forms-based authentication and ASP.NET's membership framework to create a web application that supports user accounts. Invariably, at least one student bumps into the following scenario:

  • The website's formatting and layout is defined via CSS rules, which are located in one or more .css files.
  • The URL authorization settings have configured such that web pages on the site can only be accessed by authenticated users. That is, the <authorization> section in the Web.config file in the root folder contains the following markup:

    <deny users="?" />

    Some students lock down the entire site to authenticated users only. Others may have one or more <location> elements that open up access to specific pages to anonymous users, or have a separate folder with its own <authorization> settings that allow anonymous access to the pages within.
  • The website is served using the ASP.NET Development Server, which is the lightweight web server that ships with Visual Studio and is launched when you run a file system-based web application from the IDE.

When the above conditions hold, students find that when visiting their site those CSS formatting and layout rules defined in the .css file(s) are not applied for anonymous visitors. For example, when visiting the login page, the website's colors and fonts and layouts defined in the .css file(s) are not in effect. However, once the visitor signs into the site, the CSS rules take effect.

What's going on here?

The reason the CSS rules are not applied when the site is visited by an anonymous user is because of how the ASP.NET Development Server handles web requests. In a nutshell, every single request that arrives to the ASP.NET Development Server - be it for an ASP.NET page or a CSS file - is dispatched to the ASP.NET engine for processing. Consequently, the URL authorization rules defined in Web.config apply to the CSS files as well as the ASP.NET pages. So when an anonymous user visits, the page includes the <link> elements to the CSS files and the browser requests them, but the web server responds with a redirect response to the login page. As a result, the browser does not get the CSS content and that's why CSS rules do not apply for anonymous users (and why they start applying once the visitor signs in).

The simplest workaround is to configure the URL authorization rules to allow anonymous users to access the CSS files. If you have the CSS files in a separate folder (such as /Styles), then you can simply add a Web.config file to that folder with the following <authorization> settings:

<allow users="*" />

If the CSS files are in the root folder, then you will need to add a <location> element in the root folder's Web.config file for each CSS file and use the above markup to permit anonymous users to access those files. For more on using the <location> element, refer to location Element (ASP.NET Settings Schema).

Finally, keep in mind that the behavior described here only occurs when the web server dispatches requests for CSS files to the ASP.NET engine. As aforementioned, this is the behavior of the ASP.NET Development Server; however, this is not the default behavior of IIS. By default, IIS handles request for static content itself, meaning that ASP.NET's URL authorization rules will not apply to CSS files, JavaScript files, images, ZIP files, and so on, although it is possible to instruct IIS 7 to integrate it's security checks with ASP.NET's configuration via the Integrated Pipeline mode. See Apply ASP.NET Authentication and Authorization Rules to Static Content with IIS 7.0's Integrated Pipeline Feature for more information.

Filed under:
September's Toolbox Column Now Online
10 September 09 08:12 AM | Scott Mitchell

My Toolbox column in the September 2009 issue of MSDN Magazine is available online and includes the following reviews/discussions:

  • Improving Web Application Performance With Distributed Caching - provides an overview of distributed caching for web applications, with discussions on three products: memcached, an open source option that powers many high-profile sites like LiveJournal, Wikipedia, and SourceForge; Velocity, which is Microsoft's foray into the distributed caching market; and third-party commercial implementations, like ScaleOut Software's ScaleOut StateServer and Alachisoft's NCache, which was reviewed in the October 2007 issue.
  • Blogs of Note: Udi Dahan - Udi is a speaker, trainer, and consultant on software architecture and design of distributed systems. He has worked on several large-scale, service-oriented applications for enterprises, and blogs about his experiences building enterprise applications on his blog. Check out the 'First time here?' page on Udi's blog, which has links to his most popular and engaging articles and blog posts.
  • AutoMapper - it's not uncommon to need to transfer objects of one 'shape' into a different shape. This is particularly common when exposing data through a service layer. Internally, you work with your entities in terms of business objects that model your domain, but when exposing this data you may need to return a more appropriate object type that contains fewer properties. These objects used in the service layer are referred to as Data Transfer Objects (DTOs). Writing the domain object to DTO mapping code is tedious. AutoMapper, a free, open source project - helps relieve that tedium by making such object-object mappings as easy as writing two lines of code.

This issue did not include a book review.

Enjoy! -

As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to

Filed under:
A Tool For Querying Multiple Databases
08 September 09 03:15 PM | Scott Mitchell

I recently blogged about different multi-tenant data architectures, comparing and constrasting the Separate Databases and Shared Database, Shared Schema architectures, as well as noting what sorts of questions to ask when trying to ascertain which model to use. One of the disadvantages of the Separate Databases approach is that it can be difficult to view data aggregated across the databases:

Viewing data aggregated across the databases is difficult. I've touched upon this topic in an earlier blog post, Running the Same Query Against Multiple Databases. When you find a bug on one database and need to see whether it affects data in other databases there are not many tools at your disposal. One poor man's tool is sp_msForEachDb, but it's less than ideal.

And reader John Chapman added his two cents in the comments regarding this issue:

For lots of applications you actually have situations where there are users who need to be able to see data from multiple customers at the same time. For example you may have situations where you have external customers who see only their data, but yet have internal liaisons who need to oversee the activities of multiple customers. Therefore necessitating that they see data from multiple customers on a single screen.

I have ran into these situations before, which was a key reason why we used a single database shared schema. The application we replaced used separate databases and was unable to provide this sort of functionality.

Over the years I have created a very (very!) rough tool for querying multiple databases in a Separate Databases architecture. In short, you enter a query, select which databases to query against, and then the tool runs that query against each selected database and combines the results into a single <table> on the page. As you can see from the screen shot below (click for a larger version), the tool includes a multi-line textbox for entering the query to execute and a CheckBoxList of the databases to query. The results are included in a single <table>.

While the above screen shot shows a query that just returns a scalar value (one column, one row), it certainly works with queries that return multiple rows and columns. And with a little bit of legwork the tool could be enhanced to include rollup-type functionality, showing subtotals per database and grand totals across all selected databases for numeric columns.

To learn more about how I created this tool, check out my latest article: Querying a Multi-Tenant Data Architecture.

Filed under:
More Posts


My Books

  • Teach Yourself ASP.NET 4 in 24 Hours
  • Teach Yourself ASP.NET 3.5 in 24 Hours
  • Teach Yourself ASP.NET 2.0 in 24 Hours
  • ASP.NET Data Web Controls Kick Start
  • ASP.NET: Tips, Tutorials, and Code
  • Designing Active Server Pages
  • Teach Yourself Active Server Pages 3.0 in 21 Days

I am a Microsoft MVP for ASP.NET.

I am an ASPInsider.