web-dev-qa-db-ja.com

属性ルーティングの使用中にクエリ文字列が機能しない

System.Web.Http.RouteAttributeSystem.Web.Http.RoutePrefixAttributeを使用して、Web API 2アプリケーションのURLをよりクリーンにします。私のほとんどのリクエストでは、ルーティング(例:Controller/param1/param2)またはクエリ文字列(例:Controller?param1=bob&param2=mary)を使用できます。

残念ながら、私のコントローラーの1つ(1つのみ)で、これは失敗します。ここに私のコントローラーがあります:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{sport}/{drink}")]
    public List<int> Get(string name, string sport, string drink)
    {
        // Code removed...
    }

    [HttpGet]
    [Route("{name}/{drink}")]
    public List<int> Get(string name, string drink)
    {
        // Code removed...
    }
}

ルーティングを使用していずれかにリクエストを行うと、両方とも正常に機能します。ただし、クエリ文字列を使用すると失敗し、そのパスが存在しないことがわかります。

私はWebApiConfig.csクラスのRegister(HttpConfiguration config)関数に(デフォルトルートの前後に)以下を追加しようとしましたが、何もしませんでした。

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

そのため、明確にするために、次の両方を実行できるようにします。

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke

そして、

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke

残念ながら、クエリ文字列のバージョンは機能しません! :(

更新済み

2番目のアクションを完全に削除し、オプションのパラメーターを持つ単一のアクションのみを使用しようとしています。ルート属性を[Route("{name}/{drink}/{sport?}")]に変更しました。Tonyがスポーツをnull可能にするよう提案したが、これによりlocalhost:12345/1/Names/Ted/cokeが何らかの理由で有効なルートにならないようになりました。クエリ文字列の動作は以前と同じです。

更新2コントローラーに特異なアクションがあります:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{drink}/{sport?}")]
    public List<int> Get(string name, string drink, string sport = "")
    {
        // Code removed...
    }
}

ただし、クエリ文字列を使用しても適切なパスは見つかりませんが、ルーティングメソッドを使用すると適切なパスが見つかります。

59
Chris Paton

多くの骨の折れるいじりとグーグルの後に、私は「修正」を思いつきました。これが理想/ベストプラクティス/昔ながらの間違っているかどうかはわかりませんが、それは私の問題を解決します。

すでに使用していたルート属性に加えて、[Route("")]を追加するだけでした。これは基本的に、Web API 2ルーティングがクエリ文字列を許可することを許可します。これは現在、これが有効なルートであるためです。

例は次のようになります。

[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
    // Code removed...
}

これにより、localhost:12345/1/Names/Ted/cokelocalhost:12345/1/Names?name=Ted&drink=cokeの両方が有効になります。

41
Chris Paton

現在のプロジェクトのWeb APIを構築しようとしていたときに、「検索文字列として検索パラメーターを含める方法」という同じ問題に直面していました。グーグルで調べた後、次のことがうまくいきました:

APIコントローラーアクション:

[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]

public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{

}

私が郵便配達員を通して試したURL:

http://localhost/PD/search?categoryid=all-products&ordercode=star-1932

http://localhost/PD is my hosted api
59

属性ルーティングでは、デフォルト値をオプションで指定できるように指定する必要があります。

[Route("{name}/{sport=Football}/{drink=Coke}")]

値を割り当てるとオプションになるため、値を含める必要はなく、指定する値を渡します。

このクエリ文字列はテストしていませんが、同じように機能するはずです。

私はちょうど質問を読み直しましたが、同じパスで2つの動詞を取得していることがわかります。ルーティングはどちらを使用するかわからないので、これは競合を引き起こすと信じています。おそらくオプションのパラメータを使用すると役立ちます。また、nullを指定して、処理方法をメソッドでチェックインすることもできます。

[Route("{name}/{sport?}/{drink?}")]

次に、メソッド内の変数をチェックして、それらがnullであるかどうかを確認し、必要に応じて処理します。

これが役立つことを願っていますか?笑

おそらくこのサイトにはない場合、属性ルーティングに関する詳細があります。

http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

そのサイトからクリップ:

オプションのパラメーターとデフォルト値パラメーターに疑問符を追加することにより、パラメーターがオプションであることを指定できます。

[Route("countries/{name?}")]
public Country GetCountry(string name = "USA") { }

現在、アクションの選択を成功させるためにオプションのパラメーターにデフォルト値を指定する必要がありますが、その制限を解除することを調査できます。 (これが重要かどうかをお知らせください。)

デフォルト値も同様の方法で指定できます。

[Route("countries/{name=USA}")]
public Country GetCountry(string name) { }

オプションのパラメーター「?」デフォルト値は、パラメーター定義のインライン制約の後に表示する必要があります。

17
Tony

私の側からのちょっとしたメモも。 queryString paramsが機能するためには、メソッドパラメータのデフォルト値をオプションにするを指定する必要があります。通常C#メソッドを呼び出すときにも行うように。

[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{

   ...

   [HttpGet]
   [Route("{profileUid}")]
   public IHttpActionResult GetProfile(string profileUid, long? someOtherId) 
   {
      // ...
   }

   ...

}

これにより、次のようにエンドポイントを呼び出すことができます。

/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123
10
Juri

@ bhargav kishore mummadireddy's のわずかな逸脱がありますが、重要な逸脱です。彼の答えは、クエリ文字列値を実際の空でない値にデフォルト設定します。この答えはデフォルトで空になります。

パスルーティングまたはクエリ文字列を使用して、コントローラーを呼び出すことができます。基本的に、クエリ文字列のデフォルト値を空に設定します。つまり、常にルーティングされます。

これは私にとって重要でした。クエリ文字列が指定されていない場合、ASP.NETが「このコントローラーでこのメソッドを見つけられませんでした」エラーを返すのではなく、400(Bad Request)を返すためです。

[RoutePrefix("api/AppUsageReporting")]
public class AppUsageReportingController : ApiController
    {
        [HttpGet]
        // Specify default routing parameters if the parameters aren't specified
        [Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")]
        public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate)
        {
            if (String.IsNullOrEmpty(userId))
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified.");
            }

            if (!startDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified.");
            }

            if (!endDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified.");
            }
        }
    }
4
contactmatt

Route("search/{categoryid=categoryid}/{ordercode=ordercode}")を使用すると、クエリ文字列とmosharaf hossainで応答されるインラインルートパラメーターの両方を使用できます。これをトップアンサーであり最良の方法とすべきであるとしてこのアンサーを書く。複数のGets/Puts/Posts/Deletesがある場合、Route("")を使用すると問題が発生します。

属性ルーティングとして[Route("{name}/{drink}/{sport?}")]を使用しているため、このコードはヒットしません。

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

したがって、ここでは属性[Route("{name}/{drink}/{sport?}")]のみが尊重されます。リクエストlocalhost:12345/1/Names?name=Ted&sport=rugby&drink=cokeには、URLに名前、スポーツ、または飲み物がないため、この属性ルートと一致しません。ルートを照合するとき、クエリ文字列パラメーターは考慮しません。

これを解決するには、属性ルートで3つすべてをオプションにする必要があります。その後、リクエストに一致します。

1
mugdhak

FromUri属性をソリューションとして使用します

[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)
0