12

Currently, we are using a route like this:

[HttpPost]
[Route("upload")]
public async Task<dynamic> Upload(dynamic uploadedData)
{
    JArray files = uploadedData.pdfs;
    // ...
}

Rather than using dynamic, I'd like to have a schematic understanding of the data coming in. So I could use a setup like this, with a class that defines the schema:

public class UploadRequest : JObject
{
    public JArray pdfs { get; set; }
}

[HttpPost]
[Route("upload")]
public async Task<dynamic> Upload(UploadRequest uploadedData)
{
    // Now can access the JArray via uploadedData.pdfs directly
    // ...
}

Is this the right approach to this situation? Or is there another standard best practice for receiving JSON data via ASP .NET WebAPI?

Specifically, this approach doesn't currently work. Though my small schema class extends JObject, I get an error of

The parameters dictionary contains an invalid entry for parameter 'uploadedData' for method 'System.Threading.Tasks.Task`1[System.Object] Upload(UploadRequest)' in 'EditPdfServer.Controllers.PdfFileController'. The dictionary contains a value of type 'Newtonsoft.Json.Linq.JObject', but the parameter requires a value of type 'EditPdfServer.Controllers.PdfFileController+UploadRequest'.

So firstly, does this seem like a proper approach? Secondly, is there a better one? Thirdly, why doesn't this approach work? Thanks in advance.

Scotty H
  • 6,432
  • 6
  • 41
  • 94
  • have you tried changing the name of uploadedData to pdfs – M. Carlson Feb 11 '16 at 21:45
  • may be this link will help you http://weblog.west-wind.com/posts/2012/Aug/30/Using-JSONNET-for-dynamic-JSON-parsing#JObjectandJArrayinASP.NETWebAPI – 111 Feb 16 '16 at 09:11

3 Answers3

6

You're on track.

You don't need to be overly concerned with the internal implementation of Newtonsoft.Json. In particular, you should try to avoid using JObject/JToken/other J-types, and you definitely don't need to subclass JObject.

Your request object class can simply be:

public class UploadRequest
{
    [JSONProperty("pdfs")]
    public SomePDFClass PDFs[] { get; set; }
}

This would map to a request of:

{
    "pdfs": [
        { <some PDF object here> },
        { <some PDF object here> },
        { <some PDF object here> }
    ]
}

The string parameter of JSONPropertyAttribute defines the name of the property as it appears in the JSON document, so you don't need to have the same name in code as you do in JSON. You can change the name in code, so long as the attribute still uses the same name as the document.

yaakov
  • 5,552
  • 35
  • 48
5

I would suggest using the JSONproperty attribute for you pdfs property:

public class UploadRequest : JObject
{
   [JSONProperty("<name of the property in the JSON object>")]
   public JArray pdfs { get; set; }
}

Also take a look at this post for some more info about the attribute: JSON.NET deserialize/serialize JsonProperty JsonObject

Community
  • 1
  • 1
M. Carlson
  • 788
  • 7
  • 17
0

Since your method is using the post verb, you should add the attribute [FromBody] on your method parameter:

[HttpPost]
public async Task<dynamic> Upload([FromBody] UploadRequest UploadedData)
{
    // Now can access the JArray via uploadedData.pdfs directly
    // ...
}
Misa Lazovic
  • 2,805
  • 10
  • 32
  • 38
  • 1
    It's worth to mention that you can only have 1 parameter marked this way. If you need multiple parameters, consider creating a wrapper object containing all of them. – Diego Prates de Andrade Feb 16 '16 at 20:32