0

I found a lot of info about this topic, but none of those sites and articles could solve my problem. I'm having a pretty simple method:

[HttpPost, Route("Diagnosis/{lkNo}/Tree/{nodeID:int}/Answer")]
public List<TreeNode> AnswerTreeNode(string lkNo, int nodeID, 
[FromBody] dynamic data) {
    // So some stuff
}

When I call that method, it fills the first two parameters, but data is always null. Here's my test request as received by the server:

POST /Diagnosis/LK-28084453/Tree/0/Answer HTTP/1.1
Cache-Control: no-cache
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate
Cookie: ASP.NET_SessionId=*****; __RequestVerificationToken=*****
Host: localhost:51124
User-Agent: PostmanRuntime/7.6.0
Postman-Token: *****
Content-Length: 5
Content-Type: application/x-www-form-urlencoded

=Test

Sending the parameter as json leads to the same result:

...
Content-Length: 25
Content-Type: application/json

{ "value": "some value" }

Whatever I try, data is always null. Here's my route config:

// WebAPI
GlobalConfiguration.Configure(config => {
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DiagnosisApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    // Default return JSON
    config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
        new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();

    config.MessageHandlers.Add(new MyHandler());
});

public class MyHandler : System.Net.Http.DelegatingHandler {
    protected override async System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> SendAsync(
                                             System.Net.Http.HttpRequestMessage request,
                                                System.Threading.CancellationToken token) {
        System.Net.Http.HttpMessageContent requestContent = new System.Net.Http.HttpMessageContent(request);
        string requestMessage = requestContent.ReadAsStringAsync().Result; // This one contains the raw requests as posted abve

        return await base.SendAsync(request, token);
    }
}

Do you have an idea, what's wrong here?

André Reichelt
  • 1,484
  • 18
  • 52
  • 1
    Don't use `dynamic`, there's almost always a better way. The model binder has no idea what to do with that type, and for that matter, neither do you as the consumer. – DavidG Jan 24 '19 at 14:01
  • @DavidG How would you solve it? Depending on the type of question, the parameter can either be a boolean, a string or an array of strings (for now). Anyways, even if I set it to object or string, it remains to be null. – André Reichelt Jan 24 '19 at 14:04
  • Try to use object type then – Alex Sham Jan 24 '19 at 14:06
  • How do you expect to determine if the post body is a bool or a string though? Can't you change how the data is posted instead to make it a JSON object with a known schema? – DavidG Jan 24 '19 at 14:07
  • @DavidG Sure. Client and server code are both implemented by me. But for a first step, I would be super happy, if I would receive any data at all - instead of `null`. – André Reichelt Jan 24 '19 at 14:12
  • I would agree with DavidG on this. it sounds like you have some architectural issues there. – Andrei Dragotoniu Jan 24 '19 at 14:14
  • Dangit! Heisenberg's calling ... My "nifty" debugging feature config.MessageHandlers.Add(new MyHandler()); actually butchered the data. I commented out that line and now I'm actually receiving the JSON as string. – André Reichelt Jan 24 '19 at 14:29

2 Answers2

0

My suggestion would be to not use the dynamic type in your method signature.

Change it to string and make sure you serialize what you are sending to the api as well.

Once you see the data coming in then you can use something like Newtonsoft Json to parse the string into a dynamic object and you can take it from there.

Your method would become :

public List<TreeNode> AnswerTreeNode(string lkNo, int nodeID, 
[FromBody] string data) {
    // parse data into dynamic here
}
Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32
  • I've changed the signature to `public List AnswerTreeNode(string lkNo, int nodeID, [FromBody] string data)` data is still null for both of the requests shown above. – André Reichelt Jan 24 '19 at 14:08
0

I solved the problem by removing my temporary message handler. Also, I changed the data attribute to Newtonsoft's JObject type. Now I can easily implement my own routine to interpret the received data. For example:

if (data["result"].Type == JTokenType.Boolean && data["result"].Value<bool>())

Here's my Javascript code:

node.treat = function (result) {
    if (result !== undefined)
        $.ajax({
            url: 'Diagnosis/' + vm.data.lkNo() + '/Tree/' + node.id + '/Answer',
            data: JSON.stringify({ result: result }),
            type: 'POST',
            contentType: "application/json",
            success: function (response) { /* do something */ }
        };
}

Works like a charm!

André Reichelt
  • 1,484
  • 18
  • 52