ASP.NET Core Pass Перечислимое количество объектов для получения действия на контроллере. - PullRequest
3 голосов
/ 07 июня 2019

Я пытаюсь определить Действие контроллера в ASP.NET Core 2.2.

Сложность в том, что я предпочитаю, чтобы это была конечная точка GET , а данные, которые она должна получить, - это коллекция пользовательских объектов . Вот мой пример кода:

[Route("api/example")]
[ApiController]
public class ExampleController : ControllerBase
{
    [HttpGet("getData")]
    [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetMarketData([FromQuery] MyObject[] queryData)
    {
        return this.Ok(0);
    }
}

public class MyObject
{
    public int A { get; set; }

    public int B { get; set; }
}

Я ожидаю, что это будет связано с чем-то вроде

http://localhost/api/example/getData/?queryData=[A=1,B=1],queryData=[A=2,B=2]

Однако я не могу заставить его работать.

(отправка запроса на URL, не анализирует объекты, и я получаю пустой массив в моем контроллере)

Я не уверен, что это лучший способ подойти к этому, и, возможно, мне нужно изменить место, откуда я связываю данные?

Единственное, что меня волнует, - это возможность получить массив (или некоторую коллекцию ) MyObject , который я могу обработать и вернуть ответ. Я также предпочел бы, чтобы это был GET запрос, поскольку, в конце концов, я пытаюсь запросить этот API и получить от него данные.

Я знаю, что могу заставить его работать с использованием атрибута [FromBody] , но, насколько я знаю, GET-запросы не должны использовать тело .

Любая помощь приветствуется.

Ответы [ 3 ]

2 голосов
/ 07 июня 2019

Ваш запрос GET должен быть построен следующим образом:

GET: /api/example/getData?queryData[0].A=1&queryData[0].B=2&queryData[1].A=3

Очень похоже на привязку модели при использовании <form> s:)

1 голос
/ 07 июня 2019

Ваша строка QueryString должна выглядеть следующим образом:

/TestMe?queryData[0].A=1&queryData[0].B=1&queryData[1].A=2&queryData[1].B=2

Если ваш код выглядит так:

public class MyObject
{
    public int A { get; set; }

    public int B { get; set; }
}

[Route("/TestMe")]
public IActionResult TestMe([FromQuery] MyObject[] queryData)
{ 
    return Json(queryData);
}

Обратите внимание, что [FromQuery] даже не требуется.

0 голосов
/ 07 июня 2019

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

// generic array model binder
public class ArrayModelBinder<TType> : IModelBinder {
    public Task BindModelAsync(ModelBindingContext bindingContext) {
        if (bindingContext.ModelMetadata.IsEnumerableType) {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
            if (!string.IsNullOrEmpty(value)) {
                var elementType = typeof(TType); 
                var typeConverter = TypeDescriptor.GetConverter(elementType);
                var splittedValues = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                var values = splittedValues.Select(t => typeConverter.ConvertFromString(t.Trim())).ToArray();
                var typedValues = Array.CreateInstance(elementType, values.Length);
                values.CopyTo(typedValues, 0);
                bindingContext.Model = typedValues;
                return SuccessBinding(bindingContext, typedValues);
            }
            return SuccessBinding(bindingContext, null);
        }
        return FailedBinding(bindingContext);
    }

    private static Task SuccessBinding(ModelBindingContext bindingContext, Array typedValues) {
        bindingContext.Result = ModelBindingResult.Success(typedValues);
        return Task.CompletedTask;
    }


    private static Task FailedBinding(ModelBindingContext bindingContext) {
        bindingContext.Result = ModelBindingResult.Failed();
        return Task.CompletedTask;
    }

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


public async Task<IActionResult> GetMarketData([ModelBinder(BinderType = typeof(ArrayModelBinder<object>))] MyObject[] queryData)
{
    return this.Ok(0);
}

У меня есть источник этой реализации и другие вещи в репозитории моей собственной библиотеки, не стесняйтесь проверить его CcLibrary.AspNetCore

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