Привязка / действие / 1,2,3 к списку <int> - PullRequest
2 голосов
/ 08 марта 2011

В моем API я хотел бы иметь маршруты типа GET /api/v1/widgets/1,2,3 и GET /api/v1/widgets/best-widget,major-widget,bob-the-widget

public class WidgetsController : MyApiController
{
    public ActionResult Show(IEnumerable<int> ids)
    {

    }

    public ActionResult Show(IEnumerable<string> names)
    {

    }
}

У меня настроены маршруты, чтобы привести меня к действию, но я не могу понять, как превратить 1,2,3 в new List<int>(){1, 2, 3} и так далее. Конечно, я мог бы просто взять string и проанализировать его в своем действии, но я бы хотел не идти по этому пути.

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

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

Кстати, у меня тоже была идея реализовать ValueProvider, но я заблудился по схожим вопросам.

Ответы [ 3 ]

2 голосов
/ 08 марта 2011

Я не могу понять, как превратить 1,2,3 в новый List () {1, 2, 3} и т. Д.

Чтобы не загрязнять каждое действие контроллера, которому необходимо получить этот параметр, я бы порекомендовал привязку пользовательской модели:

public class IdsModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = base.BindModel(controllerContext, bindingContext);
        var ids = bindingContext.ValueProvider.GetValue("ids");
        if (ids != null)
        {
            return ids.AttemptedValue
                      .Split(',')
                      .Select(id => int.Parse(id))
                      .ToList();
        }
        return result;
    }
}

и затем зарегистрируйте подшивку модели в Application_Start:

ModelBinders.Binders.Add(typeof(IEnumerable<int>), new IdsModelBinder());

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

public ActionResult Show(IEnumerable<int> ids)
{
    ...
}

и механизм связывания пользовательских моделей позаботится о разборе токена маршрута ids на соответствующее значение IEnumerable<int>.

Вы можете сделать то же самое с IEnumerable<string>, где вы просто удалили бы предложение .Select в соответствующей подшивке модели.

1 голос
/ 08 марта 2011

если бы ваш URL был

/api/v1/widgets/Show?names=best-widget&names=major-widget&names=bob-the-widget

Это бы связывало аккуратно само по себе:)

В этом случае нет необходимости переопределять связующие моделиПеременная querystring names будет привязана к вашему Show-method_

public ActionResult Show(IEnumerable<string> names)

Надеюсь, это поможет!

0 голосов
/ 08 марта 2011

Я относительно новичок в ASP.Net MVC, и поэтому я не уверен, есть ли более простой способ сделать это или нет, однако мой подход будет заключаться в следующем:

public class WidgetsController : MyApiController
{
    public ActionResult Show(string ids)
    {
        List<int> parsedIds = new List<int>();
        foreach (var id in ids.Split(','))
        {
            parsedIds.Add(int.Parse(id));
        }
        return Show(parsedIds);
    }

    private ActionResult Show(List<int> ids);
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...