2012-12-26 14 views
15

Kiedy próbowałem użyć Selfhosted WebAPI w LINQPad, po prostu ciągle otrzymywałem ten sam błąd, że kontroler dla klasy nie istnieje.Korzystanie z WebAPI w LINQPad?

Czy muszę utworzyć oddzielne złożenia dla WebAPI (Kontrolery/Klasy), a następnie odnieść je do mojego zapytania?

Oto kod używam

#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(); 
    } 
} 

Ten kod działa poprawnie, gdy w odrębnym projekcie konsoli w VS2012.

Zacząłem używać AttributeRouting przez NuGET, gdy nie dostałem "normalnego" routingu WebAPI do pracy.

Błąd mam w przeglądarce było: No HTTP resource was found that matches the request URI 'http://192.168.0.196:8181/players/allPlayers'.

Dodatkowy błąd: No type was found that matches the controller named 'PlayerObject'

+1

wyprodukowałem skrypt LINQ z kodem (wypełnianie brakujących części manekina z niektórych klas/metod) i dodano 'config.Routes.Cast () .LogTo (Console.Out);'. Widzę trasę 'URL: gracze/allPlayers GET, HEAD, OPCJE'. Wygląda więc na to, że trasa jest poprawnie ustawiona. Dostaję "Nie znaleziono typu, który pasuje do kontrolera o nazwie" PlayerObject'. "W przeglądarce, ale to wydaje się być inne niż twój błąd (i prawdopodobnie związane z tym, że moje obojętne klasy są zbyt obojętne). –

+0

Porzuciłem trasy i mogłem zobaczyć, że są zarejestrowane, ale kiedy próbuję wejść na stronę, wciąż mam błąd. Wysłałem nowy kod, który powoduje błąd. – NoLifeKing

+0

@FrankvanPuffelen Otrzymuję ten sam błąd co ty, ale tylko w LINQPad, kiedy przeniosłem to do VS2012, zaczęło działać bez problemów. Zawsze mogłem zacząć używać VS, ale łatwość .Dump() w LINQPad jest dla mnie wiele warta. Ponieważ używam laptopa jako "klienta" dla tego webapi. :) – NoLifeKing

Odpowiedz

16

Web API domyślnie ignoruje kontrolery, które nie są publiczne, a zajęcia LINQPad są zagnieżdżona publicznego, mieliśmy podobny problem w scriptcs

Należy dodać niestandardowy przelicznik kontrolera, który obejmie to ograniczenie i pozwoli ręcznie wykryć typy kontrolerów z zespołu wykonującego.

Zostało to już naprawione (obecnie kontrolery Web API muszą być tylko Widoczne niepubliczne), ale miało to miejsce we wrześniu, a najnowsza stabilna wersja samoobsługującego pochodzi z sierpnia.

więc dodać to:

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(); 
    } 

} 

A potem zarejestrować przed konfiguracji i gotowe:

var conf = new HttpSelfHostConfiguration(new Uri(address)); 
conf.Services.Replace(typeof(IHttpControllerTypeResolver), new ControllerResolver()); 

Oto pełny przykład roboczych, właśnie testowane przed LINQPad. Zauważ, że musisz uruchomić LinqPad jako administrator, w przeciwnym razie nie będziesz mógł słuchać na porcie.

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(); 
    }; 
} 
+10

Istnieje sztuczka, aby zmusić LINQPad do nierozkładania typów: uruchom zapytanie z #define NONEST –

+0

ah, nice! dzięki Joe –

+0

Jestem nieco zdezorientowany, gdzie ten kod idzie? Widziałem twój wpis na blogu i próbowałem dowiedzieć się, czy ten kod jest w LinqPadzie jako "Program C#", czy też jest dostępny w mojej aplikacji Web API? A może w obu? – atconway