Могу ли я объявить конечную точку веб-API, которая принимает любые аргументы и позволяет мне проверить их самостоятельно? - PullRequest
1 голос
/ 31 октября 2019

Я работаю над веб-приложением .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 в словаре или аналогичном.

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

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

[Route("call")]
public IHttpActionResult SomeMethod(HttpRequestMessage request)
{
    var dict = new Dictionary<string, string>(ParseQueryStringToDictionary(request));

    // some code here
}

Тогда вам нужно будет проанализировать строку запроса до Dictionary<string, string> используя ParseQueryStringToDictionary метод:

private IDictionary<string, string> ParseQueryStringToDictionary(HttpRequestMessage request)
{
    var queryString = string.Join(string.Empty, request.RequestUri.ToString().Split('?').Skip(1));
    var queryStringValues = System.Web.HttpUtility.ParseQueryString(queryString);
    return queryStringValues.Cast<string>().ToDictionary(x => x, x => queryStringValues[x]);
}

И назовите его: .../call?a=5&b=20&c=800

0 голосов
/ 31 октября 2019

Вы можете принять словарь, как показано ниже:

[HttpPost]
[Route("api/call")]
public void SomeMethod(HttpRequestMessage request)
{
    Dictionary<string,string> requestData= request.Content.ReadAsAsync<Dictionary<string,string>>().Result;
}

Затем вы можете прочитать словарь.

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