Маршрутизация атрибутов ASP Core 3.0

Как указать маршруты к следующей конечной точке API с помощью маршрутизации атрибутов?

Возвращенный объект продукта имеет несколько атрибутов, а также поля Store и Manufacturer, которые содержат либо значение NULL, либо объекты Store и Manufacturer соответственно.


    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase {


        [HttpGet ("")]
        public async Task<ActionResult<IEnumerable<Product>>> Get(
            bool stores = false, int storeId = 0,
            bool manufacturers = false, int manufacturerId = 0
        ) {

            // Default - returns all Products 
            // stores = true will set Product.Store = to the store object
            // storeId = 1 will filter Products to those in Store 1
            // manufacturer = true will st Product.Manufacturer to a manufacturer object
            // manufacturerId = 1 will filter Product to those produced by manufacturer 1

            var products = await _ctx.GetProducts(
                stores, storeId, 
                manufacturers, manufacturerId
            );
            return products.ToList();
        }

Я хотел бы иметь несколько удобочитаемых маршрутов для доступа и соответствующей настройки параметров.

  • [HttpGet ("")]

    • /api/Products to return objects with Store and Manufacturer = null. This is desirable.
    • ("") не нужен, когда он один, но необходим, если я добавляю другие маршруты.
  • [Route("{stores=false}/{storeId=0})]

    • /api/Products/true returns Product objects with Store filled and Manufacturer = null. This is good.
    • /api/Products/true/1 фильтрует в Магазине 1, что тоже хорошо.
    • Но это дурацкий URL (правда? - товары, магазины или производители?)
  • [Route("Stores/{storeId?})]

    • /api/Products/Stores/1 leaves stores = false, though filters on Store 1 but does not include the stores object. "Stores" is not in the route data. It is in the Request.Path but I don't want to go there.
    • /api/Products/Stores?storeId=1 не работает. Request.QueryString.Value =? StoreId = 1, но это не привязывается к моему аргументу storeId.

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

Я предполагаю, что я бы хотел либо изменить один URL-адрес с помощью строки запроса, например,

  • /api/Products?stores=true&manufacturerId=1для получения товаров с информацией о магазине, произведенных производителем 1, или
  • /api/Products?storeId=1,stores=true,manufacturers=true, чтобы получить полную информацию о товарах в магазине 1

В качестве альтернативы было бы нормально иметь

  • /api/Products/Stores/1, чтобы получить Товары с информацией о магазине для товаров в магазине 1
  • /api/Products/Stores/Manufacturers/1, чтобы получить проекты с информацией о магазине и производителе для произведенных производителем 1

Фактически, я открыт для любой читаемой схемы URL.

Спасибо!


person bob    schedule 14.12.2019    source источник
comment
«ни один не дал мне результатов, которые я ищу» - Что вы ищете?   -  person poke    schedule 15.12.2019
comment
обновил вопрос   -  person bob    schedule 15.12.2019


Ответы (1)


Я бы немного переделал ваш API-контроллер. Было бы хорошо, если бы вы дали своим действиям какие-нибудь значимые имена вместо Get().

Я также хотел бы создать службу, которая будет иметь логику для предоставления запрошенного продукта и замены _ctx

    // Default - returns all Products 
    [HttpGet ("")]
    public async Task<ActionResult<IEnumerable<Product>>> GetAllProducts()
    {
        var products = await _ctx.GetAllProducts();
        return products.ToList();
    }

    // stores = true will set Product.Store = to the store object
    // storeId = 1 will filter Products to those in Store 1
    [HttpGet ("Stores/{storeId?}")]
    public async Task<ActionResult<IEnumerable<Product>>> GetProductsByStore(int? storeId)
    {
        if (storeId.HasValue)
        {
            // get products by store id
            products = await _ctx.GetProductsByStoreId(storeId);
        }
        else
        {
             products = await _ctx.GetProductsByCurrentStore(); // just a suggestion I 
         have no idea what you mean by saying "..set Product.Store = to the store object"
        }

        return products.ToList();
    }

    // manufacturer = true will st Product.Manufacturer to a manufacturer object
    // manufacturerId = 1 will filter Product to those produced by manufacturer 1
    [HttpGet ("Manufacturers/{manufacturerId?}")]
    public async Task<ActionResult<IEnumerable<Product>>> GetProductsByManufacturer(int? manufacturerId)
    {
        if (manufacturerId.HasValue)
        {
            products = await _ctx.GetProductsByManufacturerId(manufacturerId);
        }
        else
        {
            products = await _ctx.GetProductsByManufacturer();
        }

        return products.ToList();
    }
person Kos    schedule 15.12.2019
comment
Спасибо. Я думал о том, чтобы сломать метод контроллера, но он ограничивает. Я мог бы, например, отфильтровать по storeId, но по-прежнему возвращать данные производителя как часть объекта. Означает ли маршрутизация атрибутов, что методы контроллера должны быть простыми? - person bob; 17.12.2019
comment
@bob Я вижу, что вы возвращаете Product, и если Manufacturer является частью этого объекта, я не вижу проблем с его возвратом при фильтрации по Store. Я не уверен, что понимаю, о чем вы спрашиваете, маршрутизация имеет отношение к тому, как вы строите свою логику контроллера. - person Kos; 29.12.2019