mattruma
mattruma

Reputation: 16677

ASP.NET WEB API not binding to dynamic object on POST

If have the following Api Controller ... using StrutureMap for the DI ...

using System;
using System.Dynamic;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using IdentityService.Domain;
using IdentityService.Domain.Contracts;
using IdentityService.Domain.Models;

namespace IdentityService.Controllers
{
    public class AccountController : ApiController
    {
        private readonly IRepository<Client> _clientRepository;
        private readonly IRepository<RelyingParty> _relyingPartyRepository;
        private readonly IRepository<Token> _tokenRepository;

        public AccountController(
            IRepository<Client> clientRepository,
            IRepository<RelyingParty> relyingPartyRepository,
            IRepository<Token> tokenRepository)
        {
            _clientRepository = clientRepository;
            _relyingPartyRepository = relyingPartyRepository;
            _tokenRepository = tokenRepository;
        }

        public HttpResponseMessage Post(
            [FromBody] dynamic data)
        {
            dynamic result = new ExpandoObject();

            try
            {
                var clientAuthenticator = new ClientAuthenticator(
                    _clientRepository,
                    _relyingPartyRepository,
                    _tokenRepository);

                Token token;
                clientAuthenticator.Authenticate(
                    data.Key,
                    data.ChecksumValue,
                    data.Checksum,
                    data.Name,
                    data.Password,
                    out token);

                result.Token = token;
            }
            catch (Exception ex)
            {
                result.ErrorCode = ex.GetType().ToString();
                result.ErrorMessage = ex.GetBaseException().Message;
            }

            return this.Request.CreateResponse(HttpStatusCode.OK, (ExpandoObject)result);
        }
    }
}

Using Fiddler, I am make the following post:

POST http://localhost:54029/api/account HTTP/1.1
User-Agent: Fiddler
Host: localhost:54029
Content-Type: "application/json"
Content-Length: 218

{
    "Key": "7d42276d3c3954716c672543385b575836472f5d543d7776205627413a",
    "ChecksumValue": "127.0.0.1",
    "Checksum": "ao4Ei77BaX1/iMZMTAJxWzt4fxc=",
    "Name": "USER_NAME",
    "Password": "PASSWORD"
}

Any idea why my data would be null? I have tried switching to JObject, with no success. All the examples I have found makes me think this should work.

Here is the complete response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcY29kZS1tYXR0cnVtYVx0YWxrLWF1dGhlbnRpY2F0aW9uLXNlcnZlclxJZGVudGl0eVNlcnZpY2VcYXBpXGFjY291bnQ=?=
X-Powered-By: ASP.NET
Date: Mon, 27 May 2013 13:59:45 GMT
Content-Length: 137

{"ErrorCode":"Microsoft.CSharp.RuntimeBinder.RuntimeBinderException","ErrorMessage":"Cannot perform runtime binding on a null reference"}

Any help would be much appreciated!

Update

I tried just a simple example, like:

public async Task<dynamic> Post(dynamic data)
{
     var body = await Request.Content.ReadAsStringAsync();

     return data;
}

The parameter data is still null, but I can see the values in body.

Upvotes: 9

Views: 27176

Answers (5)

Fabricio Leite
Fabricio Leite

Reputation: 338

I had same problem. In my case i had success doing this:

Used dynamic as parameter type and used JsonConvert.DeserializeObject.

[Route("webhook")]
public class WebhookController : Controller
{
    [HttpPost]
    [Route("v1/cobranca")]
    public async Task<ActionResult<IStatusCodeHttpResult>> Post([FromBody] dynamic retornoCobranca)
    {
 
        dynamic retornoObj = JsonConvert.DeserializeObject<dynamic>(retornoCobranca.ToString());

        var id = ((JValue)retornoObj.payment.id).Value;
        
        ...
    }
}

In my case, the request body is something like this:

{
    "payment": {
        "id": "123456"
    }
}

Upvotes: 0

bresleveloper
bresleveloper

Reputation: 6066

if you make the param from [FromBody] to dynamic, and if its a JSON object (made with JSON.stringify) then you can just use .ToString() to get the string value and you should be OK

   public void Post(string token, [FromBody]dynamic value)
    {
        int userID = db.GetUserIdByToken(token);
        db.InsertJson(userID, value.ToString());
    }

other definitions is headers: {'Content-Type': 'application/json'},

Upvotes: 1

Simon_Weaver
Simon_Weaver

Reputation: 146110

In an MVC 6 controller (which extends from Controller and not ApiController) the following does work (with report being JSON) :

    [HttpPost("[action]")]
    public void RunReport([FromBody]dynamic report)
    {
        ....
    }

Updated: For MVC 5 this is what I use

    [HttpPost]
    public async Task<HttpResponseMessage> FBLogin(Newtonsoft.Json.Linq.JObject jObject)
    {
        dynamic data = (dynamic)jObject;

        string accessToken = data.accessToken;
        ...
     }

Where the JSON payload is :

 '{accessToken: "EAAJF9eVIKOsBABdKVNOLJyfyCnnkrl8mlW2crgZC1NYsDqgq9ZBIZC......" }'

Upvotes: 4

Matt Houser
Matt Houser

Reputation: 36073

Remove the quotes from "application/json".

Content-Type: application/json

Upvotes: 13

Parv Sharma
Parv Sharma

Reputation: 12705

remove [FromBody] attribute and it should work

Upvotes: -4

Related Questions