11

Web API 2 の属性ルーティングに関する記事に従って、URI 経由で配列を送信しようとしています。

[HttpPost("api/set/copy/{ids}")]
public HttpResponseMessage CopySet([FromUri]int[] ids)

これは、規則ベースのルーティングを使用しているときに機能していました。

http://localhost:24144/api/set/copy/?ids=1&ids=2&ids=3

しかし、属性ルーティングでは機能しなくなりました - 404 not found が表示されます。

私がこれを試してみると:

http://localhost:24144/api/set/copy/1

その後、機能します-1つの要素を持つ配列を取得します。

この方法で属性ルーティングを使用するにはどうすればよいですか?

4

1 に答える 1

14

お気づきの動作は、属性ルーティングではなく、アクションの選択とモデル バインディングに関連しています。

「ID」がクエリ文字列から取得されることを期待している場合は、次のようにルート テンプレートを変更します (定義した方法では、URI パスで「ID」が必須になるため)。

[HttpPost("api/set/copy")]

2 番目の質問を見て、URI 自体の中で id のリストを受け入れようとしていますapi/set/copy/[1,2,3]か? はいの場合、Web API にはこの種のモデル バインディングのサポートが組み込まれているとは思いません。

ただし、以下のようなカスタム パラメーター バインディングを実装してそれを実現することもできます (モデルバインダーや値プロバイダーなどを介してこれを実現するための他のより良い方法があると思いますが、私はそれらについてあまり認識していません...したがって、おそらく探索する必要があるかもしれませんこれらのオプションも):

[HttpPost("api/set/copy/{ids}")]
public HttpResponseMessage CopySet([CustomParamBinding]int[] ids)

例:

[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
public class CustomParamBindingAttribute : ParameterBindingAttribute
{
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor paramDesc)
    {
        return new CustomParamBinding(paramDesc);
    }
}

public class CustomParamBinding : HttpParameterBinding
{
    public CustomParamBinding(HttpParameterDescriptor paramDesc) : base(paramDesc) { }

    public override bool WillReadBody
    {
        get
        {
            return false;
        }
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, 
                                                    CancellationToken cancellationToken)
    {
        //TODO: VALIDATION & ERROR CHECKS
        string idsAsString = actionContext.Request.GetRouteData().Values["ids"].ToString();

        idsAsString = idsAsString.Trim('[', ']');

        IEnumerable<string> ids = idsAsString.Split(',');
        ids = ids.Where(str => !string.IsNullOrEmpty(str));

        IEnumerable<int> idList = ids.Select(strId =>
            {
                if (string.IsNullOrEmpty(strId)) return -1;

                return Convert.ToInt32(strId);

            }).ToArray();

        SetValue(actionContext, idList);

        TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
        tcs.SetResult(null);
        return tcs.Task;
    }
}
于 2013-07-22T23:07:17.500 に答える