配列をASP.NETMVCコントローラーアクションパラメーターとして受け入れるにはどうすればよいですか?


84

Designs次の署名を持つアクションを持つASP.netMVCコントローラーが呼び出されました。

public ActionResult Multiple(int[] ids)

ただし、URLを使用してこのアクションに移動しようとすると、次のようになります。

http://localhost:54119/Designs/Multiple?ids=24041,24117

idsパラメータは常にnullです。MVCに?ids=URLクエリパラメーターをアクションの配列に変換させる方法はありますか?アクションフィルターの使用についての話を見てきましたが、私が知る限り、配列がURL自体ではなく、要求データで渡されるPOSTでのみ機能します。

回答:


150

デフォルトのモデルバインダーは、次のURLを想定しています。

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

正常にバインドするには:

public ActionResult Multiple(int[] ids)
{
    ...
}

また、これをコンマ区切りの値で機能させたい場合は、カスタムモデルバインダーを作成できます。

public class IntArrayModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (value == null || string.IsNullOrEmpty(value.AttemptedValue))
        {
            return null;
        }

        return value
            .AttemptedValue
            .Split(',')
            .Select(int.Parse)
            .ToArray();
    }
}

次に、このモデルバインダーを特定のアクション引数に適用できます。

public ActionResult Multiple([ModelBinder(typeof(IntArrayModelBinder))] int[] ids)
{
    ...
}

または、Application_Startin Global.asax:内のすべての整数配列パラメータにグローバルに適用します。

ModelBinders.Binders.Add(typeof(int[]), new IntArrayModelBinder());

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

public ActionResult Multiple(int[] ids)
{
    ...
}

2
私は行方不明でした[FromUri]public ActionResult Multiple([FromUri]int[] ids) {} (GET)
C0d1ngJammer 2017年

1
@Darinは、カスタムバインディングをグローバルに適用する方法はありますが、特定のアクションを無視するだけですか?私はそれを行うための方法を見つけることができませんでした:stackoverflow.com/questions/45379040/...を
AKD

15

Darin Dimitrovの答えを拡張するために、あなたが回避できることstringは、URLパラメーターで単純なものを受け入れ、それを自分で配列に変換することです。

public ActionResult Multiple(string ids){
  int[] idsArray = ids.Split(',').Select(int.Parse).ToArray();
  /* ...process results... */
}

これを実行中に解析エラーが発生した場合(誰かが不正な形式の配列を渡したため)、エンドポイントが見つからない場合にMVCが返す400 Bad Requestデフォルトのより404 Not Foundわかりにくいエラーの代わりに例外ハンドラーがエラーを返すようにすることができます。


9

このURL形式を使用することもでき、ASP.NETMVCがすべてを行います。ただし、URLエンコードを適用することを忘れないでください。

?param1[0]=3344&param1[1]=2222

6

GrokyのURL文字列がどこから来たのかはわかりませんが、コントローラー/アクションを呼び出すJavaScriptで同じ問題が発生しました。null複数選択リストから、1、または多数の「ID」のURLを作成します(これは、共有するソリューションに固有です)。

ダリンのカスタムモデルバインダーをコピーして貼り付け、アクション/パラメーターを装飾しましたが、機能しませんでした。私はまだnull評価されましたint[] ids。私が実際に多くのIDを持っていた「安全な」場合でも。

最終的にjavascriptを変更して、次のようなASP.NETMVCフレンドリーなパラメーター配列を生成しました。

?ids=1&ids=2

私はいくつかの愚かなことをしなければなりませんでしたが

ids || []                 #=> if null, get an empty array
[ids || []]               #=> if a single item, wrap it in an array
[].concat.apply([], ...)  #=> in case I wrapped an array, flatten it

だから、完全なブロックは

ids = [].concat.apply([], [ids || []])
id_parameter = 'ids=' + ids.join('&ids=')

面倒ですが、JavaScriptでこのようにハックしなければならなかったのは初めてです。


1
その最後の文の「初めて」の前に「not」が欠落しているかどうかだけが気になります。そうでなければ、幸運です!
DCShannon 2015年

1
@DCShannon:はは、あなたの主張がわかります!でも、これが初めてでした。この種のことが正常なのか、それとも船外に出るのかはわかりません。
Anthony Mastrean 2015年

0

.Net Core Answer

最近ここに来る人のために、あなたは.NetCoreでこれをすることができます:

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

そして:

public ActionResult Multiple([FromQuery] int[] ids)
{
    ...
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.