How to pass complex class as argument to httpget
Asked Answered
C

3

8

I would like to be able to handle a complex type as an argument to my HttpGet method.

The method pickNFirstElements works when the api method does not take any parameters, but not when i try to pass the object.

I have an idea that i need to inform my ajax query that the data is a single object, but i don't know how that is done, as i thought that was the point of BindProperties tag in the TodoItem class.

[HttpGet]
        [Route("search")]
        public async Task<ActionResult<TodoItem>> GetMatchingTodoItem([FromQuery]TodoItem todo)
        {
            // var name = todo.Name;
            // var completed = todo.IsComplete;
            return await _context.TodoItems.FirstAsync();
        }
function pickNFirstElements() {
    const item = {
        Name: "dope",
        IsComplete: false,
        Id: 2
    }
    $.ajax({
        type: "GET",
        url: uri+"/search",
        data: { name: item.Name, isComplete: item.IsComplete, Id: Item.Id },
        cache: false,
        success: function (return1) {
            alert(return1.name);
        }
    })
};
namespace TodoApi.Models
{
    [Microsoft.AspNetCore.Mvc.BindProperties(SupportsGet =true)]
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}
Commensurable answered 28/6, 2019 at 11:35 Comment(7)
passing complex objects to get is not advisableSeemaseeming
[FromBody], not [FromQuery]Dodds
What would the proper design be then? using simple parameters and then passing them to a constructor in get?Commensurable
HTTP gets are meant to be stateless and immutable and its not good design to send a complex object, we send it via query strings or route parametersSeemaseeming
Well, don't mind above comments too much. This is supposed to work, using FromQuery and BindPropertiesAttribute.Akiko
Yet it doesn't @JessedeWitCommensurable
@Commensurable See my answer for what is actually wrong with your code.Akiko
A
3

Your code is actually working (almost) fine. You only have a typo in this line:

data: { name: item.Name, isComplete: item.IsComplete, Id: Item.Id },

should be lowercase 'item' instead of 'Item':

data: { name: item.Name, isComplete: item.IsComplete, Id: item.Id },

Check your console in the browser, you'll see that it cannot find the object 'Item'.

Akiko answered 28/6, 2019 at 12:40 Comment(0)
S
2

HTTP Get are meant to be stateless and immutable. You cannot pass something in the request body using HTTP Get.

So you can either send query / route parameters.

I suggest to refactor your code to this:

Javascript:

function pickNFirstElements() {
    const item = {
        Name: "dope",
        IsComplete: false,
        Id: 2
    };
    const queryParams = new URLSearchParams(item).toString();

    $.ajax({
        type: "GET",
        url: `${uri}/search?${queryParams}`,
        cache: false,
        success: function (return1) {
            alert(return1.name);
        }
    })
};

C#:

[HttpGet("search")]
public async Task<ActionResult<TodoItem>> GetMatchingTodoItem(string name, bool isComplete, int Id)
{
    return await _context.TodoItems.FirstAsync();
}
Seemaseeming answered 28/6, 2019 at 11:55 Comment(4)
I see that this solution can work, but what if I'm working with larger classes that might have other classes as fields. Such a class would require many parameters which i would believe is bad practice? I made my initial code work with a Post instead, as it accepts complex types, but the purpose of a post should never be to retrieve elements, right?Commensurable
You cannot pass something in the request body using HTTP Get. Well, technically you can - https://mcmap.net/q/40417/-http-get-with-request-body . But it just isn't useful to do so. :)Commissure
@Commensurable this solution can quickly become unwieldy but you need to take a step back and re-think what you are trying to implement, HTTP POSTs are okay if want to send a complex object and expect the response to be idempotent.Seemaseeming
Passing arguments in the 'data' field in an ajax call of type "GET" actually adds them to the querystring, instead of the body. So that's not the problem here.Akiko
E
0

.Net Core gives you BindAttribute..

[HttpGet("route")]
public async Task<ActionResult<TodoItem>> SomeMethod([Bind(nameof(TodoItem))] TodoItem todoItem)
{
    // Your code..
}
Ezzell answered 21/2, 2023 at 5:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.