Как отправить массив через URI, используя маршрутизацию атрибутов в веб-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 not found.

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

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

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

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


person SB2055    schedule 22.07.2013    source источник


Ответы (1)


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

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

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

Глядя на ваш второй вопрос, хотите ли вы принять список идентификаторов внутри самого uri, например api/set/copy/[1,2,3]? если да, я не думаю, что веб-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;
    }
}
person Kiran Challa    schedule 22.07.2013
comment
Спасибо Киран. Я просто запутался, потому что api/set/copy/?ids=1&ids=2&ids=3 работал раньше, и тонна моих методов использует этот шаблон:/ - person SB2055; 23.07.2013
comment
Это должно работать и сейчас, если у вас нет идентификаторов, определенных в шаблоне маршрута, например: [HttpPost("api/set/copy")]. Помните, что шаблон маршрута можно использовать только для определения путей uri, а не для запроса строковых данных. - person Kiran Challa; 23.07.2013
comment
Привет! Какова возможность сделать вышеуказанное динамическим, где ids в actionContext.Request.GetRouteData().Values["ids"].ToString() может быть отправлено с каждого контроллера, поскольку у меня есть маршруты, содержащие несколько массивов, т.е. "getsomething/[1,2]/[1,2,3]" - person Mr.GT; 24.05.2016
comment
Можно сделать динамическим. Добавьте свойство ( private string ParameterName { get; set; } ), которое будет установлено равным HttpParameterDescriptor paramDesc.ParameterName. Затем используйте его как string idsAsString = actionContext.Request.GetRouteData().Values[ParameterName].ToString(); - person Mr.GT; 24.05.2016