web-dev-qa-db-ja.com

整数のリストをwebapi 2 getリクエストに送信する方法は?

ID(整数)のリストをWeb api 2getリクエストに送信する必要があるこのタスクを実行しようとしています。

だから私はいくつかのサンプルを見つけました ここ そしてそれはサンプルプロジェクトさえ持っています、しかしそれは機能しません...

これが私のWebAPIメソッドコードです:

[HttpGet]
[Route("api/NewHotelData/{ids}")]
public HttpResponseMessage Get([FromUri] List<int> ids)
{
    // ids.Count is 0
    // ids is empty...
}

これが私がフィドラーでテストしたURLです:

http://192.168.9.43/api/NewHotelData/?ids=1,2,3,4

ただし、リストは常に空であり、どのIDもメソッドに渡されていません。

問題がメソッドにあるのか、URLにあるのか、またはその両方にあるのか理解できないようです...

では、これをどのように達成できるのでしょうか。

7
Liran Friedman

これを機能させるには、カスタムモデルバインダーが必要です。作業を開始できる簡略化されたバージョンは次のとおりです。

public class CsvIntModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var key = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
        if (valueProviderResult == null)
        {
            return false;
        }

        var attemptedValue = valueProviderResult.AttemptedValue;
        if (attemptedValue != null)
        {
            var list = attemptedValue.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).
                       Select(v => int.Parse(v.Trim())).ToList();

            bindingContext.Model = list;
        }
        else
        {
            bindingContext.Model = new List<int>();
        }
        return true;
    }
}

そしてそれをこのように使用します(ルートから{ids}を削除します):

[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([ModelBinder(typeof(CsvIntModelBinder))] List<int> ids)

{ids}をルートに保持する場合は、クライアント要求を次のように変更する必要があります。

api/NewHotelData/1,2,3,4

別のオプション(なしカスタムモデルバインダー)は、getリクエストを次のように変更しています。

?ids=1&ids=2&ids=3
12
Aleksey L.

コメントで提案されているようにカスタムモデルバインダーを使用することは、これを行うための適切な方法です。ただし、次のようにすばやく汚い方法で行うこともできます。

[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([FromUri] string ids)
{
    var separated = ids.Split(new char[] { ',' });
    List<int> parsed = separated.Select(s => int.Parse(s)).ToList();
}

まず、uri ids文字列を分割し、次にLinqを使用してそれらを整数のリストに変換します。これにはサニティチェックがなく、引数の形式が正しくない場合は期待値がスローされることに注意してください。

あなたはそれをこのように呼びます:http://192.168.9.43/api/NewHotelData?ids=5,10,20

更新:個人的には、このような単純なことにモデルバインダーを使用するのは過剰設計だと思います。この単純な作業を行うには、多くのコードが必要です。モデルバインダーで使用するコードは、実際には 非常によく似ています です。メソッド引数の構文がより適切になります。整数解析をtry-catchブロックにラップし、形式が正しくない場合に適切なエラーメッセージを返すと、このアプローチを使用しない理由がわかりません。

7
Honza Kalfus

どうやらこれは箱から出してうまくいく可能性があります:

http://192.168.9.43/api/NewHotelData/?ids=1&ids=2&ids=3&ids=4

つまり、異なる値でパラメーター名を繰り返します。しかし、これらのIDが巨大になり、それらを多数含める必要があり、URLが長くなりすぎる可能性がある場合はどうなるでしょうか?

ただそれをPOSTリクエストにして、それで済ませたほうがきれいだと思います。あなたはneedリクエストをGETであり、 POSTですが、なぜですか?POSTを使用して物事を取得することは、AJAXリクエストのコンテキストでは完全に受け入れられます。

1
s.m.

これは粘着性が高すぎるかもしれませんが、次のようなこともできます。
。NETクラス(モデル)内:

public class TackyList
{
     public IEnumerable<int> myIntList {get; set;}
}

クライアント側では、投稿を行います。つまり、{myIntList: [4,2,0]}

これで、コントローラーのアクション/メソッドは次のようになります。

public void myApiMethodThatDoesSomethingWith(TackyList tl)
{
   // here you should be able to do something like:
   if(tl != null && tl.Count > 0) // blah
}
1
E.P
[HttpGet]
[Route("api/getsomething")]
public HttpResponseMessage Get([FromUri] params int[] ids)
{
}

使用法:http GET localhost:9000/api/getsomething?ids = 1&ids = 5&ids = 9

0
Pujubuju