When I tried to use the Selfhosted WebAPI in LINQPad, I just kept getting the same error that a controller for the class didn't exist.
Do I have to create separate assemblies for the WebAPI (Controllers/Classes) and then reference them in my query?
Here's the code I'm using
#region namespaces
using AttributeRouting;
using AttributeRouting.Web.Http;
using AttributeRouting.Web.Http.SelfHost;
using System.Web.Http.SelfHost;
using System.Web.Http.Routing;
using System.Web.Http;
#endregion
public void Main()
{
var config = new HttpSelfHostConfiguration("http://192.168.0.196:8181/");
config.Routes.MapHttpAttributeRoutes(cfg =>
{
cfg.AddRoutesFromAssembly(Assembly.GetExecutingAssembly());
});
config.Routes.Cast<HttpRoute>().Dump();
AllObjects.Add(new UserQuery.PlayerObject { Type = 1, BaseAddress = "Hej" });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
using(HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Server open, press enter to quit");
Console.ReadLine();
server.CloseAsync();
}
}
public static List<PlayerObject> AllObjects = new List<PlayerObject>();
public class PlayerObject
{
public uint Type { get; set; }
public string BaseAddress { get; set; }
}
[RoutePrefix("players")]
public class PlayerObjectController : System.Web.Http.ApiController
{
[GET("allPlayers")]
public IEnumerable<PlayerObject> GetAllPlayerObjects()
{
var players = (from p in AllObjects
where p.Type == 1
select p);
return players.ToList();
}
}
This code works fine when in a separate Console Project in VS2012.
I started using AttributeRouting via NuGET when I didn't get the "normal" WebAPI-routing to work.
The error I got in the browser was: No HTTP resource was found that matches the request URI 'http://192.168.0.196:8181/players/allPlayers'.
Additional error: No type was found that matches the controller named 'PlayerObject'
In an ASP.NET application, configure Web API by calling GlobalConfiguration. Configure in the Application_Start method. The Configure method takes a delegate with a single parameter of type HttpConfiguration. Perform all of your configuration inside the delegate.
You don't return a View from an API controller. But you can return API data from an MVC controller. The solution would be to correct the errors, not try to hack the API controller.
Web API by default will ignore controllers that are not public, and LinqPad classes are nested public, we had similar problem in scriptcs
You have to add a custom controller resolver, which will bypass that limitation, and allow you to discover controller types from the executing assembly manually.
This was actually fixed already (now Web API controllers only need to be Visible not public), but that happened in September and the latest stable version of self host is from August.
So, add this:
public class ControllerResolver: DefaultHttpControllerTypeResolver {
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver) {
var types = Assembly.GetExecutingAssembly().GetExportedTypes();
return types.Where(x => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(x)).ToList();
}
}
And then register against your configuration, and you're done:
var conf = new HttpSelfHostConfiguration(new Uri(address));
conf.Services.Replace(typeof(IHttpControllerTypeResolver), new ControllerResolver());
Here is a full working example, I just tested against LinqPad. Note that you have to be running LinqPad as admin, otherwise you won't be able to listen at a port.
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(x => typeof(System.Web.Http.Controllers.IHttpController).IsAssignableFrom(x)).ToList();
}
}
async Task Main() {
var address = "http://localhost:8080";
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);
await server.OpenAsync();
// keep the query in the 'Running' state
Util.KeepRunning();
Util.Cleanup += async delegate {
// shut down the server when the query's execution is canceled
// (for example, the Cancel button is clicked)
await server.CloseAsync();
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With