Couple of weeks ago, one of my former coworkers ran across a very weird problem when he was prototyping on some of his ideas with ASP.NET Web API: No HTTP resource was found that matches the request URI. Let's see what this issue was all about and what is the solution.
@ 04-16-2014
by Tugberk Ugurlu


Couple of weeks ago, one of my former coworkers ran across a very weird problem when he was prototyping on some of his ideas with ASP.NET Web API. He was hosting his ASP.NET Web API application on a console application using the Microsoft.Owin.Hosting components and Microsoft.Owin.Host.HttpListener host. His solution structure was also very simple. He put all of his controllers, message handlers, filters, etc. in one class library and all the hosting logic inside the console application. The below structure was pretty similar to what he did:

Screenshot 2014-04-16 10.36.01

Console application also has very little amount of code:

class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:5555/", Start))
        {
            Console.WriteLine("Started listening on localhost:5555");
            Console.ReadLine();
            Console.WriteLine("Shutting down...");
        }
    }

    static void Start(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
        config.Routes.MapHttpRoute("DefaultHttpRoute", "api/{controller}");
        app.UseWebApi(config);
    }
}

As you can see, it's all done by the book. However, he was constantly getting 404 when he fired up the application and sent a request to /api/cars:

Screenshot 2014-04-16 10.41.50

"No HTTP resource was found that matches the request URI". It's pretty strange. After I looked into the issue for a while, I was able to figure what the problem is:

Screenshot 2014-04-16 10.45.50

Let's make this a little bit interesting and have a look at the modules loaded into the AppDomain :)

Screenshot 2014-04-16 10.49.30

Notice that the WebApiStrangeConsoleHostSample.dll was never loaded into the AppDomain because we never used it even if it's referenced. As ASP.NET Web API uses reflection to determine the controller and the action, it never finds the CarsController. To prove our point here, I'll load the assembly manually:

static void Main(string[] args)
{
    Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, "WebApiStrangeConsoleHostSample.dll"));
    using (WebApp.Start("http://localhost:5555/", Start))
    {
        Console.WriteLine("Started listening on localhost:5555");
        Console.ReadLine();
        Console.WriteLine("Shutting down...");
    }
}

The result is a success:

Screenshot 2014-04-16 10.56.56

However, this is not an ideal solution and I bet that you never run into this issue before. Why? Because, you wise developer keep your hosting agnostic bootstrap code inside the same assembly with you core ASP.NET Web API layer and you call this inside the host application. As soon as you call a method from the core layer assembly, that assembly will be loaded into your AppDomain.

public static class WebApiConfig
{
    public static void Configure(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute("DefaultHttpRoute", "api/{controller}");
    }
}
class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:5555/", Start))
        {
            Console.WriteLine("Started listening on localhost:5555");
            Console.ReadLine();
            Console.WriteLine("Shutting down...");
        }
    }

    static void Start(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Configure(config);
        app.UseWebApi(config);
    }
}

There is one other potential solution to a problem which is similar to this one. That is to replace the IAssembliesResolver service as Filip did in this post.




Hi 🙋🏻‍♂️ I'm Tugberk Ugurlu.
Coder 👨🏻‍💻, Speaker 🗣, Author 📚, Microsoft MVP 🕸, Blogger 💻, Software Engineering at Deliveroo 🍕🍜🌯, F1 fan 🏎🚀, Loves travelling 🛫🛬
Lives in Cambridge, UK 🏡