Getting “The process cannot access the file because it is being used by another process” when trying to start a website


Today when trying to start a website that was mysteriously stopped on my development machine, I got the following error message:
The process cannot access the file because it is being used by another process. (Exception from HRESULT: 0x80070020)

This is a very misleading error message and I spent some time looking at my running processes and checking with EMCO’s UnlockIT to try figuring out what was locking my files. Looking at the Events log gives a little more accurate error that looks like this:

Source: HttpEvent
Msg: Unable to bind to the underlying transport for [::]:80. The IP Listen-Only list may contain a reference to an interface which may not exist on this machine. The data field contains the error number.
--------------------------------------------------------------
Source: IIS-W3SVC
Msg: The World Wide Web Publishing Service (WWW Service) did not register the URL prefix http://*:80/ for site 1. The site has been disabled. The data field contains the error number.

The actual issue is actually about the binding of the site. It you have any other process using port 80 (or whatever port you assigned to this site), you will get that error message when trying to start it.

To solve this problem, you have 2 options:
1. Change the port number for the problematic site’s binding to any available port
2. Turn off the service using the conflicting port (you can also assign a different port to that service)

All-in-all, this is a very minor problem that can be very easily resolved but the initial error message is leading us down the wrong path.

Hope this will help someone with the same issue

Note: my environment is Windows 7 x86 and running IIS 7.5

Update: Just finally found out that what took over my port 80 was Skype. No idea why and I have no intention on finding out so from now on, Skype is off.

Processing extension-less files with IIS 6.0 and ASP.NET


The problem

As part of a Single Sign-On implementation with a 3rd party system using SAML 2.0, the user was being redirected to a URL looking like https://mydomain.com/Profile/SAML2/Redirect/SSO?SAMLRequest=… which is the standard for a Shibboleth implementation of SAML 2.0.

This is all good if you are using a web server such as Apache which doesn’t really care if files have an extension or not and for which URL rewriting is common and easy to implement. The problem with IIS 6, is that the file will not be served by IIS and even if it was, it couldn’t be processed by the ASP.Net ISAPI filter because it doesn’t have an extension registered with this filter.

Solutions

In both cases, IIS needs to be configured to process extension-less files. However, on the ASP.NET side, there are 2 solutions that can be implemented to solve this problem. The first one uses the URL redirect feature of IIS and the second one uses URL Rewriting in ASP.NET. For the end user, both approaches will have the same result but depending on your situation you may want to pick one or the other depending on the implementation and maintenance constraints.

Security and performance warning

The settings described below have both security and performance implications. Therefore, it is important to apply these changes only on the directories or virtual directories at the lowest level possible and not at the website level (unless really necessary).

Solution 1 – Configuring URL redirect in IIS

If a redirection is not an issue, this is the easiest solution to implement. There are several drawbacks to consider:

  • The URL the end user will end on will be different than the original target URL. This is usually just a cosmetic thing and shouldn’t matter much.
  • Some search engines do not like redirects.
  • If there are a lot of extension-less files that need to be accessible through IIS, this will become a cumbersome process because each individual file needs to be configured in IIS. In our particular case, this wasn’t an issue because we had a single file to handle.

You can accomplish this solution with a few steps:

  1. Create an empty file with the name of the target (e.g. SSO)
  2. Upload the ASP.NET version of the file which will be the one processed by IIS (e.g. SSO.aspx)
  3. Right-click on the file from the IIS management console and open the Properties window
  4. Select the A redirection to a URL radio button
  5. Enter the new URL (https://mydomain.com/Profile/SAML2/Redirect/SSO.aspx$Q) in the Redirect to text box. The $Q part of the URL is explained below in the “Dealing with query strings” section
  6. make sure that The exact URL entered above and A permanent redirection for this resource radio buttons are selected

redirect

Dealing with query strings

In our particular case, the URL our users are being sent to contains a query string. If you just enter the URL of the new page to go to, the query string will be lost. To solve this problem, you just append $Q (dollar sign and capital letter Q) at the end of the URL and IIS will substitute it with the actual query string when doing the redirect.

Solution 2 – URL Rewriting

URL rewriting is a little cleaner from the user’s point of view because there is no redirection or URL change on the browser side. In addition to this, it also allows us to create a catch-all solution to be able to process all extension-less files in a directory with a single configuration change. If we add new files, they will automatically be processed in the same way.

Configuring IIS to serve extension-less files

By default, IIS 6 does not process files that do not have an extension. The first step will be to change this behavior by creating a new MIME type. MIME types are created in the HTTP Headers tab of the directory’s or website’s Properties window:

1. click on the MIME Types… button to view the existing MIME Types
http_header

2. Click on the Add… button to create a new MIME type
mime_types

3. Enter the Extension and MIME Type as shown on the screenshot below
image

4. Click OK to close all the MIME windows

Wildcard Mapping

Now that IIS will process extension-less files, we need to make sure that those files are processed by the asp.net ISAPI filter. To do this, we need to create a wildcard mapping.

  1. On the WebSite or Virtual Directory Properties window, go to the Home Directory tab and click on the Configuration… button.
    image
  2. On the Application Configuration window, make sure you are on the Mappings tab and click on the Insert… button in the Wildcard application maps section
    image
  3. Browse to the aspnet_isapi.dll file for the .Net Framework 2.0. Also make sure that the Verify that file exists checkbox is unchecked
    image
  4. Click OK and we are done with this step

URL Rewriting using an HTTPModule

After setting up the extension mapping, all files in that directory will be passed through the ASP.NET processor before being served by IIS but they will not be treated as ASP.NET files because of their lack of extension. If we were to stop here, the actual inline C# or VB.NET code would be served by IIS instead of being processed by ASP.NET.

To resolve this issue, we are going to use a trick called URL rewriting using an ASP.NET feature called HTTP Modules. For this, we need to create the module and then modify our web.config to add the module to the page lifecycle.

The HTTP Module:

   1: using System.Web;
   2:
   3: public class aspneturlModule : System.Web.IHttpModule
   4: {
   5:     public void Init( System.Web.HttpApplication context )
   6:     {
   7:         context.BeginRequest += new System.EventHandler(this.BaseModuleRewriter_BeginRequest);
   8:     }
   9:
  10:     private void BaseModuleRewriter_BeginRequest(object sender, System.EventArgs e)
  11:     {
  12:         HttpApplication app = (HttpApplication)sender;
  13:         string requestedPage = app.Request.RawUrl;
  14:         string appVirtualPath = app.Request.ApplicationPath;
  15:
  16:         if (requestedPage.Length >= appVirtualPath.Length)
  17:         {
  18:             if (requestedPage.Substring(0, appVirtualPath.Length - 1).ToLower() == appVirtualPath.ToLower())
  19:                 requestedPage = requestedPage.Substring(appVirtualPath.Length);
  20:             else
  21:                 requestedPage = string.Format("{0}.aspx?{1}", app.Request.FilePath, app.Request.QueryString.ToString());
  22:         }
  23:
  24:         HttpContext.Current.RewritePath(requestedPage);
  25:     }
  26:
  27:     public void Dispose()
  28:     {}
  29: }

The code presented above is a very simple version of an HTTP Module doing the URL rewriting for our case. This is just to illustrate how such a module would be created but there are a lot of different scenarios that may need to be handled differently.

After building the module, place the resulting library file (e.g. HTTPModule.dll) in the bin folder of the Website or Virtual Directory. If there is no bin folder, create it.

The web.config

We now need to reference this module in the web.config. Open the web.config file and locate the section about httpModules. Then, add our new module like this:

   1: <httpModules>
   2:     […] (other httpModules if any)
   3:     <add type="HttpModule.aspneturlModule" name="HttpModule" />
   4: </httpModules>

We are all set. As opposed to the first solution presented, there is no need to create an empty file without extension and the user will not be redirected to a .aspx file. It all happens behind the scenes.