简体   繁体   中英

Reading dynamic object FromBody in WebAPI just doesn't work

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?

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
}

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM