9

ASP.NET Web APIヘルプページと関連するMVC.ApiExplorerを使用している場合、http経由でアクセスできる有効なルートがありますが、ApiExplorerでは検出されません。これらのルートは、一般的なルーティングルールが使用されている場合にのみ検出されます。より具体的なルールを(一般的なルールと組み合わせて)使用すると、ApiExplorerからルートが隠されるようです。

3つのルールの例では、2つのルートがコントローラーメソッドのGETアクションとPOSTアクションに関連しており、クエリパラメーターはMIAに送信されません。

public class SomeControllerController : ApiController
{
    [HttpPost] public HttpResponseMessage Post(PostObject value) { ... }
    [HttpGet] public IEnumerable<DisplayObject> GetAll() { ... }
    [HttpGet] public DisplayObject GetById(string id) { ... }
}

のルーティングルールを使用する場合

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

ルートは、ApiExplorerによって適切に検出されます。

  • POST:api / SomeController
  • GET:api / SomeController
  • GET:api / SomeController / {id}

しかし、あまり一般的ではなく、より意味のあるルールを追加する場合

routes.MapHttpRoute(
    name: "ApiSomeControllerDefault",
    routeTemplate: "api/somecontroller/{id}",
    defaults: new
              {
                controller = "SomeController",
                id = RouteParameter.Optional
              }
    );

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

ApiExplorerはのみを返します

  • GET:api / somecontroller / {id}

一部のルートが見つからない原因は何ですか?

ApiExplorerプロジェクトページの問題レポートへのリンクを編集

4

2 に答える 2

5

あなたが見ているのは、ApiExplorer の既知のバグだと思います。何が起きているかというと、ApiExplorer はルート コレクション内のルートを調べて、コントローラーとそのアクションを解決できるかどうかを確認します。

この場合、たとえば、アクション「GetById」は上記の両方のルートで探索できますが、ApiExplorer はあいまいな一致が原因で競合が発生していると誤って想定し、重複するアクションを除外しようとします。フィルタリング/削除するアクション。このバグは ApiExplorer (メインの WebAPI コアの一部) にあるため、残念ながらすぐに修正することはできません。

于 2013-01-25T01:51:24.133 に答える
5

このバグは ASP.NET Web API チームによって修正されていませんが、私は独自のばかげた修正を使用しています。

私の拡張メソッドは、クラスの元の実装IApiExplorerと同じことを行っていますが、異なるルートの重複したアクションを削除する代わりに、異なる ID (HTTP メソッド + ルート) を持つアクションを返すだけです。したがって、ルート数に関係なく、宣言されたすべてのアクションを返します。ApiDescriptionsApiExplorer

そして、はい、恥知らずにリフレクションを使用してプライベート メソッドを呼び出します。

public static class WebApiExtensions
{
    public static Collection<ApiDescription> GetAllApiDescriptions(this IApiExplorer apiExplorer, HttpConfiguration httpConfig)
    {
        if (!(apiExplorer is ApiExplorer))
        {
            return apiExplorer.ApiDescriptions;
        }

        IList<ApiDescription> apiDescriptions = new Collection<ApiDescription>();
        var controllerSelector = httpConfig.Services.GetHttpControllerSelector();
        var controllerMappings = controllerSelector.GetControllerMapping();

        if (controllerMappings != null)
        {
            foreach (var route in httpConfig.Routes)
            {
                typeof(ApiExplorer).GetMethod("ExploreRouteControllers",
                    bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
                    binder: null,
                    types: new[] {typeof(IDictionary<string, HttpControllerDescriptor>), typeof(IHttpRoute), typeof(Collection<ApiDescription>)},
                    modifiers: null
                ).Invoke(apiExplorer, new object[] {controllerMappings, route, apiDescriptions});
            }

            apiDescriptions = apiDescriptions
                .GroupBy(api => api.ID.ToLower())
                .Select(g => g.First())
                .ToList();
        }

        return new Collection<ApiDescription>(apiDescriptions);
    }
}

使い方は簡単です:

var apiDescriptions = apiExplorer.GetAllApiDescriptions(httpConfig);

HttpConfigurationテスト容易性のためにパラメータが追加されました。気にしない場合は、パラメーターを削除してGlobalConfiguration.HttpConfiguration、拡張メソッドで直接使用してください。

于 2013-03-17T19:28:05.813 に答える