Hosting ASP.NET Web API in LinqPad

Β· 514 words Β· 3 minutes to read

Today I stumbled upon an interesting Stackoverflow question, where the user was asking how to go about self-hosting Web API in LinqPad.

The question has gone unanswered since December, and I’m guessing even the OP forgot about it. However, I’d like to elaborate a bit about the topic. You certainly can host Web API in LinqPad, provided you plug in a quick work around - and we actually did hit a similar issue with scriptcs.

Understanding LinqPad πŸ”—

LinqPad is an absolutely terrific tool, which allows you to write complex C# without Visual Studio. To be able to answer our original Web API hosting question, we need to understand what LinqPad does under the hood. Unfortunately, we won’t be able to dig much beyond the rough overview LinqPad offers on its about page, since it’s closed source.

However the page also features a nice chart explaining the high levels of LinqPad. I hope Joseph will take no offense if I hotlink it here:

There is great amount of impressive stuff going on here, including lexical parsing, static code analysis, and ultimately code compilation. My first thought was that LinqPad is compiling in memory into a dynamic assembly, and Web API does not support controller discovery from such assemblies.

However, that is not the case - a quick check uncovered that LinqPad actually does write a DLL to a disk, and stores in the Temp directory:

file:///C:/Users/Filip/AppData/Local/Temp/LINQPad/jtcmlkgf/query_uercmg.dll  

However, it turns out, it also does compile everything as nested classes, wrapping all of your code with a UserQuery class.

And that’s exactly where the problem lies. You can write all the code required to run Web API self host in LinqPad, you can reference Web API DLLs, it will compile fine and execute, but it will not discover your controllers.

Nested controllers πŸ”—

Web API, in the RTM version, requires controller types to be public.

In LinqPad case, the controllers are visible but not public, but nested public. This causes the DefaultHttpControllerTypeResolver to ignore them. This issue was fixed on September 2, 2012, with this commit, but that was already after the release.

We can easily remedy that by writing our own resolver:

public class ControllerResolver : DefaultHttpControllerTypeResolver  
{  
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)  
{  
var types = Assembly.GetExecutingAssembly().GetExportedTypes();  
return types.Where(i => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(i)).ToList();  
}  
}  

In this case, we ignore all the default Web API predicates and simply get all visible types that implement IHttpController (which, by the way, in my opinion should be the only constraint by default as well).

If we now register the controller resolver, we can run Web API self from LinqPad easily:

public class TestController : System.Web.Http.ApiController {  
public string Get() {  
return "Hello world!"  
}  
}

public class ControllerResolver : DefaultHttpControllerTypeResolver  
{  
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)  
{  
var types = Assembly.GetExecutingAssembly().GetExportedTypes();  
return types.Where(i => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(i)).ToList();  
}  
}

void Main()  
{  
var address = "http://localhost:8090"  
var conf = new HttpSelfHostConfiguration(new Uri(address));  
conf.Services.Replace(typeof(IHttpControllerTypeResolver), new ControllerResolver());

conf.Routes.MapHttpRoute(name: "DefaultApi",  
routeTemplate: "api/{controller}/{id}",  
defaults: new { id = RouteParameter.Optional }  
);

var server = new HttpSelfHostServer(conf);  
server.OpenAsync().Wait();  
}  

And there we go!

Web API hosted in LinqPad.

About


Hi! I'm Filip W., a software architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP