Я работаю над веб-приложением .NET 4.6.1 на основе ASP.NET. Наши контроллеры веб-API интенсивно используют атрибуты [HttpGet]
и [HttpPost]
;маршрутизация выполняется с помощью атрибута [Route]
.
Я понимаю, что если несколько методов имеют один и тот же маршрут, ASP.NET различает их по именам параметров (и числу).
Теперь на одном из моих контроллеров я хотел бы предложить один метод (чей маршрут или, по крайней мере, комбинация маршрута + HTTP-глагол является уникальным), который будет принимать любые аргументы в своей строке запроса. Предпочтительно, я хотел бы получить проанализированную строку запроса в виде списка пар ключ / значение, но если бы мне пришлось самому анализировать строку запроса, это бы также помогло.
Как мне этого добитьсяоставаясь верным нашей общей структуре кода (то есть полагаясь на [Route]
для маршрутизации и т. д.)?
Я нашел пару возможных решений, но почему-то что-то всегда отсутствует или, по крайней мере,мои выводы неубедительны из-за отсутствия документации. Например:
- Я знаю, что, вероятно, я могу получить доступ к полной строке запроса через
HttpContext
, но это не решает проблему маршрутизации, что ASP.NET должен сопоставлять запросы с произвольными параметрами моему методуfirst. - Я нашел несколько подсказок о связывателях моделей, но с тех пор, как несколько месяцев назад я внедрил связыватели моделей, казалось, что они всегда могут обрабатывать только один аргумент за раз, а не все из всей строки запроса. ,(Или, может быть, я ошибаюсь по этому поводу и заблудился в лабиринте поставляемых объектов?)
- Я пытался использовать
DictionaryModelBinder<string, string>
, но все, что я получаю от этого - пустой Dictionary<string, string>
.
РЕДАКТИРОВАТЬ: В качестве примера я хотел бы, чтобы моя конечная точка (назовем ее call
) реагировала на любое из следующего:
.../call
.../call?a=5&b=20&c=800
.../call?a=foo&z=bar
BriefОбоснование: Метод находится в абстрактном базовом классе для моих реальных контроллеров. Информация о том, какие параметры URL будут фактически приняты каждым отдельным контроллером, может быть легко извлечена из данных / отражений во время выполнения, поэтому я могу сам вернуть статус 404, если полученные параметры не соответствуют. То, что я делаю , а не , это то, что я хочу сделать, это реализовать метод индивидуально для каждого контроллера - даже если это позволит мне указать разные параметры для каждого контроллера, это создаст неудобную избыточность.
EDIT2Вот сокращенная версия того, как выглядят контроллеры:
Базовый класс:
public abstract class ControllerBase<T, TKey> : ApiControllerBase
{
[Route("call")]
[HttpGet]
public T Call([FromUri(Name = "")] TKey key)
{
// retrieve T from database based on key (for instance)
}
}
И фактический контроллер:
public class Thing
{}
public class ThingKey
{
public int OwnerId { get; set; }
public int Id { get; set; }
}
[RoutePrefix("api/thing")]
public class ThingController : ControllerBase<Thing, ThingKey>
{}
И еще один контроллер:
public class Stuff
{}
public class StuffKey
{
public int Scope { get; set; }
public int Group { get; set; }
public int UniqueKey { get; set; }
}
[RoutePrefix("api/stuff")]
public class StuffController : ControllerBase<Stuff, StuffKey>
{}
Как видно здесь, моя конечная точка call
в настоящее время по-прежнему отображает параметры из строки URL-запроса в свойства объектов, специфичных для контроллера. Я хотел бы покончить с необходимостью предоставления отдельного класса ключей для каждого контроллера и скорее получить аргументы для call
в словаре или аналогичном.