0

So, previously my team used POST requests for everything. I finally won the war in convincing them the use the verbs as intended.
GETs for queries,
POSTs for creates etc.

We have a pretty complex object which we need to send as a GET:

{
    "UserId": "1",
    "CategoryId": "39",
    "StartMillis": 1609459200000,
    "EndMillis": 1635724799000,
    "GroupByAttributeTypeId": "105",
    "SelectedAttributes": [{
            "TypeId": "100",
            "AttributeIds": [1]
        }, {
            "TypeId": "105",
            "AttributeIds": [6697]
        }
    ]
}

This is easy as a POST, but not so much as a GET. The Action method that we created looks something like:

[HttpGet]
[Route(AspNet.Mvc.ActionTemplate)]

public IActionResult GetCompletedAudits([FromQuery]CompletedAuditDto payload)
{
   return OkResponse(_auditService.GetCompletedAudit(payload));
}

where CompletedAuditDto is:

public class CompletedAuditDto
{
    public int UserId { get; set; }
    public string CategoryId { get; set; }
    public long StartMillis { get; set; }
    public long EndMillis { get; set; }
    public string GroupByAttributeTypeId { get; set; }

    public IEnumerable<TypeAttributeDto> SelectedAttributes;
}

and TypeAttributeDto is:

public class TypeAttributeDto
{
    public int TypeId;
    public IEnumerable<int> AttrIds;
}

And I've tried many different serializations using the qs library. But the SelectedAttributes collection always comes up as null. I turned my logging down to the debug level and the model binder doesn't even seem to attempt to deserialize that object (no mention of the SelectedAttributes collection)

[14:35:44 DBG] Attempting to bind parameter 'payload' of type 'WebApp.Payloads.Request.CompletedAuditDto' ... [14:35:44 DBG] Attempting to bind parameter 'payload' of type 'WebApp.Payloads.Request.CompletedAuditDto' using the name '' in request data ... [14:35:44 DBG] Attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.UserId' of type 'System.Int32' using the name 'UserId' in request data ... [14:35:44 DBG] Done attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.UserId' of type 'System.Int32'. [14:35:44 DBG] Attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.CategoryId' of type 'System.String' using the name 'CategoryId' in request data ... [14:35:44 DBG] Done attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.CategoryId' of type 'System.String'. [14:35:44 DBG] Attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.StartMillis' of type 'System.Int64' using the name 'StartMillis' in request data ... [14:35:44 DBG] Done attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.StartMillis' of type 'System.Int64'. [14:35:44 DBG] Attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.EndMillis' of type 'System.Int64' using the name 'EndMillis' in request data ... [14:35:44 DBG] Done attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.EndMillis' of type 'System.Int64'. [14:35:44 DBG] Attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.GroupByAttributeTypeId' of type 'System.String' using the name 'GroupByAttributeTypeId' in request data ... [14:35:44 DBG] Done attempting to bind property 'WebApp.Payloads.Request.CompletedAuditDto.GroupByAttributeTypeId' of type 'System.String'. [14:35:44 DBG] Done attempting to bind parameter 'payload' of type 'WebApp.Payloads.Request.CompletedAuditDto'. [14:35:44 DBG] Done attempting to bind parameter 'payload' of type 'WebApp.Payloads.Request.CompletedAuditDto'.

Any ideas how I can get this serialized into a format which the model-binder would be happy with. This is one of the many things I have attempted:

UserId=1&CategoryId=39&StartMillis=1609459200000&EndMillis=1635724799000&GroupByAttributeTypeId=105&SelectedAttributes%5B%5D.TypeId=100&SelectedAttributes%5B%5D.AttributeIds%5B%5D=1&SelectedAttributes%5B%5D.TypeId=105&SelectedAttributes%5B%5D.AttributeIds%5B%5D=6697

1 Answer 1

1

Firstly, you need add getter setter in your model like below:

public class CompletedAuditDto
{
    public int UserId { get; set; }
    public string CategoryId { get; set; }
    public long StartMillis { get; set; }
    public long EndMillis { get; set; }
    public string GroupByAttributeTypeId { get; set; }

    public IEnumerable<TypeAttributeDto> SelectedAttributes { get; set; }
}
public class TypeAttributeDto
{
    public int TypeId { get; set; }
    public IEnumerable<int> AttrIds { get; set; }
}

Then send request like below:

UserId=1&CategoryId=39&StartMillis=1609459200000&EndMillis=1635724799000&GroupByAttributeTypeId=105&SelectedAttributes[0].TypeId=100&SelectedAttributes[0].AttrIds=1&SelectedAttributes[1].TypeId=105&SelectedAttributes[1].AttrIds=6697

Sign up to request clarification or add additional context in comments.

2 Comments

I can't believe I did not see that. I remember thinking yesterday that something looked amiss, but I could not put my finger on it. I'd never code like that, so I did not consider that public variables were randomly being used instead of properties. But its on me for not seeing it. Thanks very much. The next challenge is finding a serializer which will serialize a Javascript object like that. Thanks again.
As an addendum, you can serialize it using qs like this: qs.stringify(val, { allowDots: true }) which results in a string like this UserId=1&CategoryId=39&StartMillis=1609459200000&EndMillis=1635724799000&GroupByAttributeTypeId=105&SelectedAttributes%5B0%5D.TypeId=100&SelectedAttributes%5B0%5D.AttrIds%5B0%5D=1&SelectedAttributes%5B1%5D.TypeId=105&SelectedAttributes%5B1%5D.AttrIds%5B0%5D=6697 . The model binder was happy with that.

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.