Some techniques for better managing files in VS 2005 Web Projects
I’ve seen several questions come up in the last few days regarding techniques for structuring project layouts with web projects in VS 2005. In particular, I’ve received several good questions asking for ways to manage large image directories as well as temporary storage directories underneath web project roots. One goal with both questions has been to find ways to avoid these files from showing up in the VS web project solution explorer and cluttering up the web project view, as well as to avoid having these files/directories be prompted to be added to source control during check-in (note: you can just unclick having these files added to source control – but having to-do so can be a pain).
This blog post covers some techniques for handling scenarios like these. Prior to reading further, I’d strongly recommend you read my previous post on managing IIS web projects with VS 2005: http://weblogs.asp.net/scottgu/archive/2005/08/23/423409.aspx. The section on virtual directory mappings and how they are treated will be particularly pertinent to some of the techniques below.
Note that the final release of VS 2005 will have “Exclude File from Build” support to allow you to exclude/include code from being part of a build or publishing operation. The below techniques are about going one step deeper and having files disappear entirely from the solution explorer, as well as to discuss techniques for sharing common directories across multiple projects.
Scenario #1: How to manage a 5,000 item /images directory in a web project
A really good scenario that someone sent my way today was one where they currently have an ecommerce solution that has a 5,000 item product catalog. As part of their solution they have an “images” subdirectory underneath their web root that stores an image for each of the 5,000 products on disk.
When they open up their web project using VS 2005 they are worried about having two problems:
1) They will have a 5,000 picture sub-directory in their heavily developed web project which will add clutter and slow down open/copy operations.
2) Managing this directory with source control will be a real pain – when you check-in or check-out of Visual Source Safe it will verify that these files haven’t changed or have been added to source control which can really take awhile. Ideally there would be someway to manage these image files elsewhere.
A technique to make this experience much better:
For scenarios like these involving directory resources, one technique that you can easily use to better manage these items in web projects is to mark these directories as “virtual directories” in IIS. This does not require any code-changes – it is purely a configuration setting you can manage via IIS.
Making these directories “virtual directories” provides four big benefits:
Benefit #1: Sub-directories marked as “virtual directories” in IIS will automatically be excluded from showing up in a VS 2005 web project. A marker node will still remain in the solution tree to indicate that a virtual sub-directory is present, but no files or sub-directories will be added – and the virtual directory and all of its contents will be excluded from all source control and publish deployment operations.
For example, the below images show the difference when the “images” subdirectory is marked as a normal directory:
And here is the same web project again when the “images” directory is marked as a “virtual directory” in IIS. Note that there is still an “images” node in the hierarchy to denote the presence of a virtual sub-directory – but no content is included underneath it:
Note that the content of the virtual-directory will be automatically excluded from all deployment operations, and will not be included in the source control for the web project (even in cases where the "images" virtual directory is physically stored underneath the web project on disk).
Benefit #2: You can now store these directories anywhere on disk. If you want, you can continue to store them physically underneath the same web app or site directory. You can also then optionally store them elsewhere on disk. This can make some deployment scenarios much easier – since you can now manage these directory trees separately and update and deploy their roots independently. Note that virtual directory views within the solution explorer will be the same regardless of whether the physical images subdirectory is under the project directory or stored elsewhere – it is completely transparent to the active project.
Benefit #3: You can have multiple web projects share the same virtual directories. This can be a very useful and powerful technique when you have shared images, CSS or script libraries that you want to re-use across multiple web sites or web applications (for example: www.site1.com, www.site2.com, www.site3.com, etc). One of the cool new features in the VS 2005 WYSIWYG designer is that it will follow virtual directory paths and load images, CSS files and scripts correctly even when they are stored in virtual directories.
For example: consider a scenario where you are building 3 different sites or applications where you want to share a common CSS design, and common corporate logo images. You could lay out your application structure like this if you wanted to:
C:\CommonVDir\Images
C:\CommonVDir\CSS
C:\CommonVDir\Javascript
C:\Sites\www.site1.com
C:\Sites\www.site2.com
C:\Sites\www.site3.com
You could then map a virtual directory underneath each site to point to the “CommonVDir” shared library directory. Not only will this work at runtime, but when you create a new page underneath the www.site1.com web project and reference the “commonvdir/css/style.css” stylesheet – the VS 2005 web designer will automatically pick up the styles and show things correctly in design-view, even though the actual stylesheet is never checked in or managed in the www.site1.com web project.
When you update a single CSS stylesheet under the c:\CommonVDir\CSS directory, it will immediately show updated in all 3 of the sites -- both at runtime and design-time.
Benefit #4: You can optionally create additional web projects to manage your various virtual directories. This allows you to manage these separate virtual folders using their own development/design team, web project and source control settings. For example, the below screenshot shows one solution with both the web application open, as well as a second and third web project open to manage the “images” and “styles” virtual directories as separate isolated projects (which could be checked-in separately under source control):
Scenario #2: How to dynamically generate and handle temp files in a web project
Another scenario that a few people have asked about is one where they are dynamically generating XML files underneath their web project at runtime, and they want to avoid having these files appear in their solution explorer and source control, and avoid having them be deployed by Visual Studio’s “Publish Web” feature.
A technique to make this experience much better:
For temporary file storage that is dynamically generated underneath a web-project or web-root, you might want to consider using hidden folders.
There are two benefits of this approach:
Benefit #1: Hidden files and folders are automatically excluded from the web project view under solution explorer, and will be excluded from all source control operations.
For example, here is an example web project with a “tempstorage” directory containing XML files:
Here is the same web project except that the “tempstorage” directory has now been marked with a “hidden” bit:
Benefit #2: IIS will by default block requests for content stored in hidden folders. This can be a useful security check to help prevent temporary files from accidentally getting downloaded by unauthorized users.
The below two lines of sample code demonstrate how to dynamically create a new temporary directory, and then mark it as hidden using the System.IO namespace:
Directory.CreateDirectory("tempstorage");
File.SetAttributes("tempstorage", FileAttributes.Hidden);
You can also obviously just create the folder on the file-system yourself using Windows explorer, pull up its properties window, and click the "hidden" attribute too.
Note that whether a folder is hidden or not will not change any code or logic when accessing/writing files underneath it.
Important Note: For maximum security, I would always recommend that you not grant any write access to the directory underneath a web project or application root. If you need to store temporary files somewhere, it is far more secure to store them in a totally non-accessible location. I’ve only included the above section on temporary storage because several people have asked about it.
Scenario #3: How to store non-deployed files in web projects
A final scenario a few people have asked me about is how they might be able to store files within web projects and under source control that can be used during development time (for example: design-docs written in word or visio, or adobe photoshop .psd files for layered images), but will be automatically excluded from any deployment or publishing steps.
A technique to make this experience much better:
ASP.NET 2.0 supports a concept of “build providers”. These are classes that implement the System.Web.Compilation.BuildProvider base class contract, and which can participate in build-operations both in VS 2005 at development-time and ASP.NET at runtime. Developers are free to build and implement their own BuildProviders to add their own custom semantics to processing files within ASP.NET. For example: you could create an .ORM file extension for files that contained XML to declaratively represent an OR mapping database relationship. Your provider could then dynamically generate strongly-typed classes that were included in the web anytime one of these files was added to the project – and you would get both intellisense within VS 2005 at design-time as well as full runtime support.
One of the built-in build providers in ASP.NET 2.0 is a provider called the “IgnoreFileBuildProvider”. Its semantics are that it ignores whatever file extension is mapped to it, and that it will also automatically prevent that file from being deployed during a publish-web or compilation operation.
Developers can then use this feature to add extensions to the web.config file in their local web projects and effectively block any file-type they want from being deployed by VS. For example, if I wanted to prevent all .doc (word), .psd (photoshop) and .vsd (visio) files from ever being deployed, I would add the following section to my web.config file:
<configuration>
<system.web>
<compilation>
<buildProviders>
<add extension=".doc" type="System.Web.Compilation.IgnoreFileBuildProvider" />
<add extension=".psd" type="System.Web.Compilation.IgnoreFileBuildProvider" />
<add extension=".vsd" type="System.Web.Compilation.IgnoreFileBuildProvider" />
</buildProviders>
</compilation>
</system.web>
</configuration>
I am then free to add and check-in these file types anywhere in my project if I so wanted to – and they can be used/modified/accessed throughout the development lifecycle – but will be excluded anytime a build is produced.
Hopefully this helps show some useful techniques you can leverage.
- Scott