【问题标题】:Using WebAPI in LINQPad?在 LINQPad 中使用 WebAPI?
【发布时间】:2012-12-12 02:34:54
【问题描述】:

当我尝试在 LINQPad 中使用 Selfhosted WebAPI 时,我一直收到相同的错误,即该类的控制器不存在。

我是否必须为 WebAPI(控制器/类)创建单独的程序集,然后在我的查询中引用它们?

这是我正在使用的代码

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

此代码在 VS2012 的单独控制台项目中运行良好。

当我没有让“正常”的 WebAPI 路由工作时,我开始通过 NuGET 使用 AttributeRouting。

我在浏览器中得到的错误是:No HTTP resource was found that matches the request URI 'http://192.168.0.196:8181/players/allPlayers'.

附加错误:No type was found that matches the controller named 'PlayerObject'

【问题讨论】:

  • 我用你的代码生成了一个 LINQ 脚本(用一些虚拟类/方法填充缺失的部分)并添加了config.Routes.Cast&lt;HttpRoute&gt;().LogTo(Console.Out);。我确实看到了路线URL: players/allPlayers GET, HEAD, OPTIONS。所以这似乎表明路线设置正确。我确实在浏览器中收到了No type was found that matches the controller named 'PlayerObject'.,但这似乎与您的错误不同(并且可能与我的虚拟类太虚拟有关)。
  • 我转储了路由,我可以看到它们已注册,但是当我尝试转到该页面时,我仍然收到错误。我发布了一个产生错误的新代码。
  • @FrankvanPuffelen 我确实遇到了与您相同的错误,但仅在 LINQPad 中,当我将其移至 VS2012 时,它开始正常工作。我总是可以开始使用 VS,但是 .Dump() 在 LINQPad 中的易用性对我来说很有价值。因为我也使用我的笔记本电脑作为这个 webapi 的“客户端”。 :)
  • 会不会是反射的类型是System.Collections.Generic.IEnumerable``1[UserQuery+PlayerObject]?也许 WebAPI 无法将 UserQuery+PlayerObject 识别为普通的 PlayerObject 类?
  • 我将PlayerObject 添加到MyExtensions,但错误消息仍然相同。我还将路由添加为常规 Web API,无需更改。恐怕我和你一样被困住了。 :-/

标签: asp.net-web-api linqpad self-hosting attributerouting


【解决方案1】:

Web API 默认会忽略不公开的控制器,而 LinqPad 类是嵌套公开的,我们在 scriptcs 中遇到过类似的问题

您必须添加一个自定义控制器解析器,这将绕过该限制,并允许您手动从正在执行的程序集中发现控制器类型。

这实际上已经修复(现在 Web API 控制器只需要可见不公开),但这发生在 9 月,并且自主机的最新稳定版本是从 8 月开始的。

所以,添加这个:

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

}

然后根据你的配置注册,你就完成了:

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

这是一个完整的工作示例,我刚刚针对 LinqPad 进行了测试。请注意,您必须以管理员身份运行 LinqPad,否则您将无法监听端口。

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

【讨论】:

  • 有一个技巧可以强制 LINQPad 不嵌套类型:使用 #define NONEST 开始查询
  • 我有点困惑,这段代码去哪儿了?我看过您的博客文章,并试图弄清楚此代码是作为“C# 程序”进入 LinqPad 还是进入我的 Web API 应用程序?还是两者兼而有之?
  • 还有一个技巧,只要定义你的命名空间,那么没有任何技巧你就没有嵌套行为
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
相关资源
最近更新 更多