Как отправить массив через URI, используя маршрутизацию атрибутов в Web API?

Я после статья о маршрутизации атрибутов в 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 не найдена.

Если я попробую это:

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

затем он работает - я получаю массив с одним элементом.

как использовать маршрутизацию атрибутов таким образом?

1 ответов


поведение, которое вы замечаете, больше связано с выбором действия и привязкой модели, а не маршрутизацией атрибутов.

если вы ожидаете, что "идентификаторы" будут исходить из строки запроса, измените шаблон маршрута, как показано ниже(потому что способ, которым вы его определили, делает "идентификаторы" обязательными в пути uri):

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

глядя на ваш второй вопрос, вы хотите принять список идентификаторов в самом uri, например api/set/copy/[1,2,3]? если да, я не думаю, что веб-api имеет встроенный поддержка такого рода привязки модели.

вы можете реализовать пользовательскую привязку параметров, как показано ниже, чтобы достичь этого (я предполагаю, что есть другие лучшие способы достичь этого, как через modelbinders и поставщиков значений, но я не очень осведомлен о них...так что вам, вероятно, придется изучить эти параметры тоже):

[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;
    }
}