0

I have noticed something strange with my .Net Core 3.1 and .Net Core 5 Apis. When there are 2 different GET methods to retrieve all records and a single record by id, route based parameters work but querystring parameters do not.

Here is some sample code

using Core5TestApi.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Core5TestApi.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class DataController : ControllerBase
    {
        private readonly ILogger<DataController> _logger;
        List<Data> allData = new List<Data>{
                new Data { Id = 1, Name = "Name 1" },
                new Data { Id = 2, Name = "Name 2" }
            };

        public DataController(ILogger<DataController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<Data> GetAll ()
        {
            return allData;
        }

        [HttpGet("{id}")]
        [Route("{id}")]
        public Data Get(int id)
        {
            return allData.First(i => i.Id == id);
        }
    }
}

The following are the urls and the results

Call: http://localhost:51672/api/data Result:[{"id":1,"name":"Name 1"},{"id":2,"name":"Name 2"}]

Call: http://localhost:51672/api/data/1 Result: {"id":1,"name":"Name 1"}

Call: http://localhost:51672/api/data?id=1 Result: [{"id":1,"name":"Name 1"},{"id":2,"name":"Name 2"}]

The last result ignores the querystring parameter and performs the GetAll.

I feel like I am missing something very basic though I believe I have seen this work before

I have also attempted the [FromQuery] attribute before the parameter in the Get method. This actually breaks the route based parameter path

1 Answer 1

3

When you call http://localhost:51672/api/data?id=1 routing ignores ?id=1 since there is no any route for this.

You have to use http://localhost:51672/api/data/1 if you want the record with id=1.

And remove from the last action [Route("{id}")], it should be:

          [HttpGet("{id}")]
            public Data Get(int id)
        {
            return allData.First(i => i.Id == id);
        }

but if you still want to use http://localhost:51672/api/data?id=1 your action should be:

             [HttpGet]
            public Data Get([FromQuery] int id)
        {
            return allData.First(i => i.Id == id);
        }

Or you can use one action for both:

       //http://localhost:51672/api/data/getAll
        [HttpGet("GetAll")]
        public IEnumerable<Data> GetAll()
        {
              return allData.ToArray();
        }

        [HttpGet("{id0?}")]
        [HttpGet]
        public Data Get(int id0, [FromQuery] int id)
        {
            var itemId =  id0 == 0 ? id : id0;
            if(itemId==0) ...return error
            return allData.FirstOrDefault(i => i.Id == itemId);
        }
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer Sergey. Please confirm if my summary of your answer is correct: when using route based attributes if both querystring and route based parameters are desired, they cannot use the same variable. Another question is why you do not have a simple [HttpGet] attribute and use the [Route] to specify this. What is the difference between [HttpGet] and [Route] in terms of specifying the path (can't find anything that explains that). It seems like they are interchangeable
I never use any [HttpGet] or [HttpPost] in my APIs. You don't need them . They don't make any difference in the code. Some browsers or httpclients can use Post instead of Get. In this case your Apis will not be working if you use attributes. I prefer [Route] and explicit action names. In a reall application you can have a hundred action in one controller and it is impossible to usejust get or post attributes. Classical Rest is only good in a texbook.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.