web-dev-qa-db-ja.com

ASP.NET Core WebApiに複数のクエリ文字列パラメーターを持つ複数のgetメソッドがある

次のように3つのgetメソッドが必要な1つのリソースがあるWebAPIを構築しています。

    [HttpGet]
    [Route("{city}/{streetName}/{streetNumber}/{littera}")]
    public IActionResult GetByAddress([FromQuery]string city, [FromQuery]string streetName, [FromQuery]int streetNumber, [FromQuery]string littera)
    {
        var model = _availabilityService.FindByAddress(city, streetName, streetNumber, littera);
        return Ok(model);
    }

    [HttpGet("{pointId}")]
    public IActionResult GetByPointId(string pointId)
    {
        var model = _availabilityService.FindByPointId(pointId);
        return Ok(model);
    }

    [HttpGet]
    [Route("{xCoordinate}/{yCoordinate}")]
    public IActionResult GetByCoordinates([FromQuery]decimal xCoordinate, [FromQuery]decimal yCoordinate)
    {
        var model = _availabilityService.FindByCoordinates(xCoordinate, yCoordinate);
        return Ok(model);
    }

パラメータ(pointId)が1つしかないgetメソッドは、クエリ文字列ではなくIDとして表示されるため、正常に機能しています。ただし、残りの2つの方法は、ASP.NETのルーターでは区別できないようです。

私はここで本当に途方に暮れていて、なぜそれが機能しないのか理解できません。私が解決できたのは、一方のメソッドを削除すると、もう一方のメソッドは正常に機能するということです。

私が間違っていることについて何か提案はありますか?

参考までに、対応するurl:sは次のようになります。

api/1.0/availabilities?city=Metropolis&streetName=Superstreet&streetNumber=1&littera=A

そして

/api/1.0/availabilities?xCoordinate=34.3444&yCoordinate=66.3422

ありがとう!

7
Kasper P

まず、RouteParametersとQueryParametersを混合します。

この:

[HttpGet]
[Route("{xCoordinate}/{yCoordinate}")]
public IActionResult GetByCoordinates([FromQuery]decimal xCoordinate, [FromQuery]decimal yCoordinate)
{
    var model = _availabilityService.FindByCoordinates(xCoordinate, yCoordinate);
    return Ok(model);
}

コントローラアクションGetByCoordinatesを次のようなルートにマップします。

/api/1.0/availabilities/34.3444/66.3422

ただし、クエリパラメータからxCoordinateyCoordinateがバインドされることを期待していることも指定しています。したがって、上記のURLはアクションと一致しますが、xCoordinateyCoordinateはデフォルト値(この場合は0)にバインドされます。

したがって、目的のルートを取得するには、ルートパラメータを宣言しないでください。

[HttpGet]
[Route("")] // <- no route parameters specified
public IActionResult GetByCoordinates([FromQuery]decimal xCoordinate, [FromQuery]decimal yCoordinate)
{
   // will be matched by e.g.
   // /api/1.0/availabilities?xCoordinate=34.3444&yCoordinate=66.3422
}

これで、目的のルートが一致します。

注:2つのアクションを同じルートにマップすることはできません-ルートミドルウェアはどちらを選択するかを認識しません。したがって、ルートパラメータをGetByAddressから削除すると、両方のアクションが同じルートに効果的にマップされます。

/api/1.0/availabilities?{any=number&of=query&parameters=here}

したがって、たとえば別のルートセグメントでそれらを区別する必要があります。

[HttpGet]
[Route("address")] // <--
public IActionResult GetByAddress([FromQuery]string city, [FromQuery]string streetName, [FromQuery]int streetNumber, [FromQuery]string littera)
{
    // will be matched by e.g.
    // api/1.0/availabilities/address?city=Metropolis&streetName=Superstreet&streetNumber=1&littera=A
}

参考文献:

ModelBinding / ルーティング

クイックヒント:

appsettings.json(標準のAsp.Net Core WebApplicationテンプレートで自動生成)でMicrosftログレベルをDebugに設定すると、ルート選択中のルート選択/エラーに関する非常に役立つ情報が得られます。 kestrelで実行しているときのコンソール出力。

{
  "Logging": {
  "IncludeScopes": false,
  "LogLevel": {
    "Default": "Debug",
    "System": "Information",
    "Microsoft": "Debug"
}

または、StartUp.csからLogLevel.Debugにデバッグロガーを設定すると、VisualStudioのデバッグ出力で同じ情報を直接取得できます。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // ...

        loggerFactory.AddDebug(LogLevel.Debug);

        // ...
    }
15
ypsilo0n