Как настроить маршрутизацию в ASP.NET CORE 3.0 для использования метода перегрузки [HttpGet] с параметрами [FromQuery]?

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

Итак, у меня есть 2 метода: первый - получить все элементы списка, а второй - получить все элементы списка, однако во втором методе есть параметр запроса, который я использую для фильтрации, а второй - Метод также возвращает объект, отличный от первого. Поскольку у меня есть 2 метода Http get, которые идут по одному и тому же маршруту, когда я вызываю один из методов, которые я получаю:

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: запрос соответствует нескольким конечным точкам. Матчи: .....

Как мне решить эту проблему без объединения двух методов, использования дополнительных параметров или изменения пути к одному методу? если возможно??

пример кода:

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<ICollection<Data>>> GetAll()
{
    return Ok(await Service.GetAll());
}

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<Data2>> GetAll([FromQuery]int parameter)
{
    return Ok(await Service.GetAll2(parameter));
}

Внутри метода настройки у меня есть:

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

Изменить: попытался, как было предложено в комментариях, использовать действия в такой конфигурации ...

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("default", "{controller}/{action}/{id?}");
});

Это не сработало, потому что когда я делаю запрос на получение, например, для первого метода getall, вызывается неправильный метод: api / resources / getall, метод ниже запускается, вместо этого вызывая ошибку, поскольку getall не является int ...

// GET: api/Resources/5
[HttpGet("{id}")]
public async Task<ActionResult<Data>> GetById(int id)
{
    return Ok(await Service.GetById(id));
}

пример воспроизведения ›› https://drive.google.com/open?id=15EB1_kK-c_qyhRS0QvVlKnhuUbFjyN12


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

[Route("api/[controller]/[action]")]
[ApiController]
public class ResourcesController : ControllerBase
{
    // GET: api/Resources/GetAll
    [HttpGet]
    public ActionResult<ICollection<string>> GetAll()
    {
        return Ok(new List<string>() { "foo", "bar" });
    }

    // GET: api/Resources/GetAll2?parameter="bar"
    [HttpGet]
    public ActionResult<string> GetAll2([FromQuery]string parameter)
    {
        return Ok(parameter);
    }

    // GET: api/Resources/GetById/5
    [HttpGet("{id}")]
    public ActionResult<int> GetById(int id)
    {
        return Ok(id);
    }
}

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

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

Обновление 2. Спустя почти год я решил найти ограничения параметров запроса и наткнулся на этот вопрос в stackoverflow, с ответом, что это невозможно, хотя вопрос довольно старый, поэтому ...


person Noob    schedule 10.12.2019    source источник
comment
Ну ваша проблема с маршрутизацией, а не с методами. Не могли бы вы предоставить конфигурацию вашего веб-API? По умолчанию у него есть этот api / {controller} / {id}, что может быть очень проблематичным. Поскольку, если у вас есть два метода внутри вашего веб-API с одним и тем же контроллером параметров, вы получаете двусмысленность, другими словами, вашу ошибку,   -  person panoskarajohn    schedule 10.12.2019
comment
Взгляните на ответ на этот вопрос - ›stackoverflow.com/questions/59157364/   -  person panoskarajohn    schedule 10.12.2019
comment
@panoskarajohn, значит, я должен использовать действие? нет другого выхода?   -  person Noob    schedule 10.12.2019
comment
К сожалению нет. Тем точнее вы подходите к маршруту. Тем меньше у вас будет двусмысленности. Поскольку api игнорирует действия, неоднозначность между двумя методами - не редкость. Вам нужно переосмыслить дизайн вашего веб-API. Дополнительную информацию можно найти в документации - ›docs.microsoft.com/en-us/aspnet/core/tutorials/   -  person panoskarajohn    schedule 10.12.2019
comment
@panoskarajohn знает, как заставить действия работать в .NET Core 3.0? Я пробовал: app.UseEndpoints (endpoints = ›{endpoints.MapControllerRoute (по умолчанию, {controller} / {action} / {id?});}); но не сработало.   -  person Noob    schedule 10.12.2019
comment
Что ты пробовал? Пожалуйста, обратитесь к упомянутому выше переполнению стека. У вас должна быть конфигурация маршрута в вашем startup.cs.   -  person panoskarajohn    schedule 10.12.2019
comment
@panoskarajohn да, я проверил это, к сожалению, это не работает, вероятно, потому что я использую asp.netcore 3.0, а не asp.net   -  person Noob    schedule 11.12.2019
comment
Это неверно, я тестировал .NET Core 3, и он отлично работает. Пожалуйста, покажите свою работу. Я имею в виду показать конфигурацию вашего маршрута для веб-API и действий вашего контроллера. Приведите небольшой воспроизводимый пример.   -  person panoskarajohn    schedule 11.12.2019
comment
@panoskarajohn создает пример проекта банкомата ...   -  person Noob    schedule 11.12.2019
comment
@panoskarajohn добавил пример репродукции ...   -  person Noob    schedule 11.12.2019


Ответы (2)


В качестве справки я создал новый проект web api asp.net core 3.

Также предположим, например, что у вас есть маршрут по умолчанию, зарегистрированный в вашем Startup.cs. endpoints.MapDefaultControllerRoute();

Добавление

[Route("api/[controller]/[action]")]
[ApiController]

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

Этого также нельзя добиться, если Id является необязательным параметром. Вы получите двусмысленность. Поскольку GetAll () и GetAll (параметр int) абсолютно одинаковы, поскольку мы объявили параметр как необязательный. Вот почему вы получаете сообщение об ошибке.

using Microsoft.AspNetCore.Mvc;

namespace WebApiTest.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ResourceController : ControllerBase
    {

        [HttpGet]
        //api/Resource/GetAll
        public IActionResult GetAll()
        {
            return Content("I got nth");
        }

        //GET: //api/Resource/GetAll/2
        [HttpGet("{parameter}")]
        public IActionResult GetAll(int parameter)
        {
            return Ok($"Parameter {parameter}");
        }

    }
}

Также обратите внимание, что во втором GetAll () я добавил в свой HttpGet параметр.

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

Для получения дополнительных параметров вы можете сделать что-то вроде этого. [HttpGet({parameter}/{resourceId})].

Тогда ваш маршрут будет работать аналогично этому api / Resource / GetAll / 2/4.

person panoskarajohn    schedule 11.12.2019
comment
Хорошо, я обновил пример воспроизведения ›› drive.google.com/open?id=15EB1_kK -c_qyhRS0QvVlKnhuUbFjyN12 Казалось, что маршрутизация attibute в контроллере была моей проблемой, теперь она работает, спасибо. - person Noob; 12.12.2019

Как мне решить эту проблему без объединения двух методов, использования дополнительных параметров или изменения пути к одному методу? если возможно??

Если вы хотите, чтобы он работал без объединения этих двух действий или указания имени действия в маршруте, вы можете попробовать использовать Http[Verb] attributes, чтобы ваше второе действие принимало параметр из данных маршрута, как показано ниже.

// GET: api/Resources
[HttpGet]
public async Task<ActionResult<ICollection<Data>>> GetAll()
{
    return Ok(await Service.GetAll());
}


// GET: api/Resources/1
[HttpGet("{parameter:int}")]
public async Task<ActionResult<Data2>> GetAll([FromRoute]int parameter)
{
    return Ok(await Service.GetAll2(parameter));
}

Кроме того, на мой взгляд, было бы лучше объединить эти два действия и использовать необязательный параметр. Я хотел бы знать, в каком сценарии не требуется использовать этот подход для выполнения требования.

[HttpGet("{parameter:int?}")]
public async Task<IActionResult> GetAll([FromQuery]int parameter)
{
    if (parameter == 0)
    {
        return Ok(await Service.GetAll());
    }
    else
    {
        return Ok(await Service.GetAll2(parameter));
    }
}
person Fei Han    schedule 11.12.2019
comment
Да, но переменная параметра, которую я получаю, я получаю из запроса и не является идентификатором ресурсов, поэтому использование ее как переменной пути не имеет смысла для пути, а слияние - это то, что я действительно не хочу делать. - person Noob; 11.12.2019
comment
Я пытаюсь заставить его работать, используя действия, предложенные в комментариях под вопросом, но я не знаю, как сделать для него конфигурацию маршрута при запуске, для netcore 3.0 api - person Noob; 11.12.2019