403.14 Error When Trying to Access a WebAPI Route

Introduction

No, there’s no flying pigs, and Satan isn’t wearing a woolly hat, but this is a post about WebAPI (boooo!) I hit an “interesting” issue today, and felt a blog post was in order in case anyone else is bitten by this rather annoying “feature”.

I added a very simple route definition:

config.Routes.MapHttpRoute(
  name: "foo",
  routeTemplate: "{controller}/{name}",
  defaults: new { name = RouteParameter.Optional },
  constraints: new { controller = "foos" });

And a very simple controller:

namespace Bar
{
    using System.Web.Http;

    using Bar.Hypermedia;

    public class FoosController : ApiController
    {
        private readonly IFooService fooService;

        public FoosController(IFooService fooService)
        {
            this.fooService = fooService;
        }

        [HttpGet]
        public IEnumerable Root()
        {
            return this.fooService.GetFoos();
        }

        [HttpGet]
        public Foo Root(string name)
        {
            return this.fooService.GetFoo(name);
        }
    }
}

It couldn’t get much more simple – just a controller that returns a collection of Foos, or a single Foo, depending on whether the name of the Foo was specified. I fired up curl and getting a single Foo was fine, but browsing to /foos/ came back with:

HTTP Error 403.14 – Forbidden
The Web server is configured to not list the contents of this directory.

Err.. what?!

The Solution

The solution was easy – just ask a friendly neighbourhood ASP.Net WebAPI MVP to fix it for me 😉 Filip stepped up and confirmed all my code was fine, but after some head scratching noticed that I had my FoosController.cs inside a folder called Foos, and renaming that folder made the route work fine. It seems that if IIS/Asp.Net sees a folder that exactly matches the URL you’re asking for (/foos in this case) then it takes over and ignores any routes you have setup. Renaming folders would be a major pain in the backside, but luckily you can disable this behaviour by adding one line to the global.asax:

public class WebApiApplication : HttpApplication
{
    protected void Application_Start()
    {
        // Stop IIS/Asp.Net breaking our routes
        RouteTable.Routes.RouteExistingFiles = true;

        WebApiConfig.Register(GlobalConfiguration.Configuration);
    }
}

So many thanks to Filip for helping me solve this one – I’m sure I’d have lost time, and hair, trying to figure it out on my own. I’d consider this behaviour to be a bug, but I’m sure it’s actually a feature in someone’s mind. If only there was a better way to write HTTP APIs in .net…. 😉

Strange Problem – Unable to Connect to the ASP.Net WebServer on Localhost

Introduction

This problem appeared out of the blue in Visual Studio 2005 on my work laptop. Google didn’t help with a solution, so I thought a brief blog post was in order.

The Issue

Trying to launch any ASP.Net application on my local machine, either in debug mode or starting without debugging, started the Cassini ASP.Net Webserver just fine, but the browser just threw up an “unable to connect” error. Google seemed to suggest it might be a corrupt webserver exe, but it seemed to be running fine so I ignored that option. I tried manually specifying a port in the project settings, and even using telnet to try access the port on localhost from the command prompt, but even though the webserver was running, nobody was listening!

The Fix

After clutching at random straws for a while I did a “ping localhost” from the command prompt and noticed it was returning replies from ::1 (the IPv6 “loopback” address). I popped open my hosts file (c:\windows\system32\drivers\etc\hosts) and noticed that localhost was mapped to ::1, but not to 127.0.0.1. I have no need for IPv6 on my machine so I commented out that line and added:

127.0.0.1       localhost

Fired up Visual Studio, pressed F5 and voila – all fixed! I’m not sure why this was suddenly a problem, it just appears that Cassini just doesn’t like being accessed via IPv6, but this seems to be the solution if this issues bites you 🙂

Passing Parameters using LoadControl()

Recently I had to put together a SharePoint 2008 Web Part and I wanted to use a User Control for the UI and pass the various Web Part settings into it.  The “standard” way to call LoadControl doesn’t allow us to pass any parameters:

LoadControl

There is an additional overload that takes a Type and a list of parameters but using that doesn’t seem to initialise any of the designer created bits, so referencing any of the sub-controls fails with a null reference exception.

One solution would be to add some public properties to the control, create it using the normal LoadControl, set the properties to the relevant values and display it.  I wasn’t too keen on that approach so instead I created a LoadControl extension method on TemplateControl that provides the following overload:

LoadControlExtension

Extension Method Implementation

The implementation of the extension methoid is very straightforward.  Firstly we take the params we are passed and pull out their types into an array:

Type[] paramTypes = new Type[constructorParams.Length];
for (int paramLoop = 0; paramLoop < constructorParams.Length; paramLoop++)    paramTypes[paramLoop] = constructorParams[paramLoop].GetType();

Once we have the types we can use GetConstructor to lookup the constructor that matches our signature:

var constructor = control.GetType().BaseType.GetConstructor(paramTypes);

Then if our constructor was found, we simply invoke it:

constructor.Invoke(control, constructorParams);

User Control

In our user control code behind we add our required constructor, but we also need to add a default constructor (one with no parameters) or the compiler gets confused and you will get a CS1729 runtime error:

public partial class TestControl : System.Web.UI.UserControl
{    
    public TestControl()    
    {    
    }

    public TestControl(Color color1, Color color2)    
    {       
        Label1.ForeColor = color1;        
        Label2.ForeColor = color2;    
    }
}

And that’s it!  A demo with the extension method class and a sample user control is available here:

LoadControlDemo.zip