9

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.

mattruma
  • 16,589
  • 32
  • 107
  • 171
  • 2
    JObject should work. Dynamic won't. – Darrel Miller May 27 '13 at 14:14
  • Switching to JObject doesn't work either ... same error message. – mattruma May 27 '13 at 14:24
  • 1
    Are you setting the content-type header to `application/json` on the client? – Darrel Miller May 27 '13 at 14:26
  • Yes ... updated my question with what else I am sending over ... – mattruma May 27 '13 at 14:28
  • Where exactly does the error occur? The data property is coming through for me, but your CreateResponse probably won't work because I don't think JSON.NET can serialize an expando. – Darrel Miller May 27 '13 at 14:34
  • I just putting a break in the web api, as I enter the method, data is still null, so when I start to "pick" properties off data, it's null. – mattruma May 27 '13 at 14:40
  • I tried just something simple like `public HttpResponseMessage Post(JObject data) { return Request.CreateResponse(HttpStatusCode.OK, data); }` and it didn't work ... just seeing what data is passed. – mattruma May 27 '13 at 14:40
  • @DarrelMiller I updated my question with a simple example ... if you could share any insight on it, I would appreciate it. – mattruma May 27 '13 at 15:00
  • As I mentioned before, dynamic will not work. The serializers don't know what to do with it. However, JObject does work with your data. Not sure why it isn't working for you. Can you show your configuration? – Darrel Miller May 27 '13 at 15:43

4 Answers4

12

Remove the quotes from "application/json".

Content-Type: application/json
Matt Houser
  • 33,983
  • 6
  • 70
  • 88
4

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......" }'
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
1

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'},

bresleveloper
  • 5,940
  • 3
  • 33
  • 47
-3

remove [FromBody] attribute and it should work

Parv Sharma
  • 12,581
  • 4
  • 48
  • 80