Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using WebAPI in LINQPad?

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'

like image 334
NoLifeKing Avatar asked Dec 26 '12 14:12

NoLifeKing


People also ask

How do I set up Webapi?

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.

Can ApiController return view?

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.


1 Answers

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();
    };
}
like image 60
Filip W Avatar answered Sep 25 '22 08:09

Filip W