I have a Post method that receives a fairly simple JSON:
{
"First": "John",
"Last": "Smith"
}
But I need it as a string.
I've tried casting the JSON to a string but it comes up null.
public void Post([FromBody]string jsonData)
{
...
}
I would like to use jsonData as a string. I am trying to avoid creating a class with field names matching the JSON because that would mean changing the API every time a field is added. I just need to receive the JSON as a string at the outset. Is there a way to cast it as such at the endpoint without using variable names?
Just use JToken as parameter.
[HttpPost]
public void PostMethod([FromBody] JToken json)
{
var jsonAsString = json.ToString();
}
Have you try this?
JObject json = JObject.Parse(str);
You might want to refer to Json.NET documentation
Related
I am working with Post endpoint in C# and I want to make all fields optional, but also want to update it to null/empty list. I know this is very weird requirement. I can set int and string data types to -1 or some default strings, but I am finding difficulties for List or any list of data.
I can put any extra flag for conditional update, but this is increasing number of properties in request body.
Could anyone suggest me solution for this case, if anyone has done similar problem. I know solution will be going to tricky one.
Sorry for the delay.
Let me try to explain it with more code.
First of all, we do a generic method that will fill a generic object with data extracted from a JSON string.
public static void FillObjectFromJson<T>(T objectToFill, string objectInJson)
where T : class
{
// Check parameters
if (objectToFill == null) throw new ArgumentNullException(nameof(objectToFill));
if (string.IsNullOrEmpty(objectInJson)) throw new ArgumentNullException(nameof(objectInJson));
// Deserialize in a typed object (helpful for the type converter)
var typed = JsonConvert.DeserializeObject<T>(objectInJson);
// Deserialize in an expando object (for check properties)
var expando = JsonConvert.DeserializeObject<ExpandoObject>(objectInJson);
// Converts the expando to dictionary for check all given properties
var dictionary = (IDictionary<string, object>)expando;
// Read all properties of the given object (the only one you can assign)
foreach (var property in typeof(T).GetProperties().Where(x => x.CanWrite))
{
// If dictionary contains the property, it was in the JSON string,
// so we have to replace it
if (dictionary.ContainsKey(property.Name))
{
var propValue = property.GetValue(typed);
property.SetValue(objectToFill, propValue);
}
}
}
For the performance it's not the best, since we deserialize the same JSON twice:
The first time into a typed object
The second time to an ExpandoObject type
I did it because we can have some problems with property types. In this example, in the ExpandoObject the Age property will be in of type int64 instead of int32. So, if we want to deserialize the JSON only once, then we need to cast properties.
Feel free to change this code as you prefer.
Now that we have a generic method, try to use it in an example.
First of all, we need a class to use:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
// This method is used only for this example, just for write data to the console
public override string ToString()
{
return $"Name: {Name} - Age: {Age}";
}
}
Then we need a method that will extract the data to update from storage. In this example we will simply back an object:
public static Person ReadPersonFromStorage()
{
return new Person
{
Name = "Name from storage",
Age = 44
};
}
Finally, we can write our test method:
// Example of JSON with explicit name (so we have to set it as null)
var personWithNameJson = "{ \"Name\" : null, \"Age\" : 24 }";
// Read the original value from the storage
var person = ReadPersonFromStorage();
Console.WriteLine(person); // We have the name
// Fills from JSON (it will replace the Name since it's in the JSON)
FillObjectFromJson(person, personWithNameJson);
Console.WriteLine(person); // The name is set to null
// Example of JSON without explicit name (so you have to leave it with the original value)
var personWithoutNameJson = "{ \"Age\" : 24 }";
// Read the original value from the storage
var otherPerson = ReadPersonFromStorage();
Console.WriteLine(otherPerson); // We have the name
// Fills from JSON (it won't replace the Name since it's NOT in the JSON)
FillObjectFromJson(otherPerson, personWithoutNameJson);
Console.WriteLine(otherPerson); // We still have the name since it's not in the JSON
I hope it's more clear what I mean and, even better, that i would help you.
PS: For this sample I used Newtonsoft for the JSON deserialization.
If you're in control of both client and server, you can manage it using the format of the request.
Suppose you have an object like this:
public class Customer {
public string Name { get; set; }
public int? Age { get; set; }
}
Then you can manage two kind of request. I will explain it using JSON format.
{
"Name": null,
"Age": 12
}
In this case, the request contains the value "Name", so you will set it to null in the database (or any other storage)
{
"Age": 12
}
In this case, the request does not contain the value "Name", so ti means it hasn't to be changed.
For the JSON format, both request are the same (Name = null). But in your code they will work in different way.
Of course:
It's not a standard, so you have to do it by yourself (JSON serializer/deserializer won't manage this scenario)
Since it's not standard, better if you manage both client and server side. Ask people to use your server if you don't follow standard rules can be a trick
I am trying to deserialize a GraphQLResponse in c#.
My response contains the following:
{
"myClassObjects": [
{
"var1": "var1Value",
"var2": "var2Value"
}, //more MyClass objects
]}
According to several sources, I should now be able to unpack and deserialize this using:
var output = response.getDataFieldAs<IEnumerable<MyClass>>("myClassObjects");
Sadly, the getDataFieldAs method does not exist (anymore).
The response.Data is a Newtonsoft.Json.Linq.JObject which contains an object "myClassObjects" which is an array of MyClass objects. When I try to unpack :
List<MyClass> output = JsonConvert.DeserializeObject<List<MyClass>>(response.Data.ToString());
I keep getting :
Cannot deserialize the current JSON object ... because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly
It's my first time working with Json and I really hope there is a handy sollution for this ? Any help would be much appreciated.
you're missing the rootObject when deserializing the "array" of, what i am assuming, is your MyClass objects.
public class RootObject {
[JsonProperty("myClassObjects")]
public List<MyClass> MyClassObjects {get;set; }
}
// then deserialize your json like this,
var obj = JsonConvert.DeserializeObject<RootObject>(response.Content);
Without the details on how you are getting the response, i am not sure how to explain the difference in response.Content vs response.Data. If you are using RestSharp, then Data would have the correctly deserialized data for you. Content is the raw string that you would deserialize yourself.
The error you keep getting is because you are deserializing the Json as [ ] but its { property: value }. Your json has an object that has an array instead of json being an array of objects.
I am trying to parse a JSON received in a Post request.
The JSON is as follows. It has to be agnostic as to how many records there are or what the fields are called. But the contact variable is always null when I send it via Postman. Is there something wrong with the class I throw it in to?
{
"Fields":
{
"first":"fn",
"last":"ln",
...
}
}
public class FieldsValues
{
List<KeyValuePair<string, string>> Fields = new List<KeyValuePair<string, string>>() { };
}
public void Post([FromBody]FieldsValues Fields)
{
...
}
I want to send the JSON into a Dictionary object but the value coming in is always null.
Your Json is not an array. You need square brackets to build an array.
Besides this the KeyValuePair has members named "Key" and "Value".
To match the List<KeyValuePair<string, string>> you'll need to input something like this:
{
"Fields":
[{
"Key":"first",
"Value":"fn"
}]
}
If you can't change the JSON structure yourself and the structure is really unknown to you, I would go for a method that accepts raw strings and parse that string with Newtonsoft to a dynamic object.
E.g. this code could accept your JSON:
public void Post()
{
string text = "";
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
text = reader.ReadToEnd();
dynamic dynObj = JObject.Parse(text);
var firstValue = dynObj.Fields.first.Value;
...
}
How can i parse a json string in c# controller
public ActionResult GetAjaxSession(string search)
{
...
}
Variable which containt the json string :
search
The Json string :
[{"id_employe":"35"},{"id_employe":"80"},{"id_employe":"136"},{"id_employe":"140"}]
I want to get all id_employe from the string
But parsing would be the right way, to get the right data out of your string.
Example with using Newtonsoft.Json:
var objects = JsonConvert.DeserializeObject<List<MyObj>>(jsonText);
With the class:
public class MyObj
{
public string id_employe { get; set; }
}
Malior's approach is perfectly fine, it's a typed approach. I'd like to mention an alternative way, using Linq and dynamic:
var jsonText="[{\"id_employe\":\"35\"},{\"id_employe\":\"80\"},"
+"{\"id_employe\":\"136\"},{\"id_employe\":\"140\"}]";
var objects = JsonConvert.DeserializeObject<List<dynamic>>(jsonText);
var values = objects.Select(s=>s.id_employe).ToList();
Fiddle
This will create a list, so values contains the following elements:
35,80,136,140
Because it is dynamic, you don't need to declare an extra class. Note that both approaches will throw a JsonReaderException if there is anything wrong with the JSON string (e.g. missing [ etc.). And if the property name isn't found it can throw a RuntimeBinderException - so you should use a try ... catch block.
So I am new to working with MVC4 and the serialization of objects on the back end seems pretty "magical" to me so if I am doing this the wrong way please let me know.
My goal however is to build a simple rest API and return JSON out. I figured that I would use System.Json and just return JsonObject. I have simplified this down for the sake of this question but the objects are much more complicated in my real issue.
Here is my controller....
....
public class ActionsController : ApiController
{
// GET api/actions
public JsonObject Get()
{
JsonObject testObjet = new JsonObject();
testObjet.Add("Name", "Test name");
testObjet.Add("Description", "Test Description");
return testObjet;
}
....
I would expect to see:
{"Name":"Test name","Description":"Test Description"}
Instead I see:
{"Name":[],"Description":[]}
I actually seem to get better results when I return a string of the JsonObject or heck even just return the object itself with the exception it has enums and I want to return the names not the number values, which is what led me to JsonObject for customization.
Does anyone know why it is dropping off the values?
EDIT:
So because of Dan's comments below I tried just for giggles to see what the XML serializer spit out with the JSON object and I get the below exception...
"Type 'System.Json.JsonPrimitive' with data contract name 'JsonPrimitive:http://schemas.datacontract.org/2004/07/System.Json' is not expected."
So it appears that you can not serialize the System.Json.JsonObject object, because it uses a type that it does not expect.
That is shocking. Does anyone have a workaround? If not I am off to find out how to show enum names when serializing instead of values.
So the answer is apparently... You Can't!
It appears that the type JsonPrimitive is not supported to serialize objects. The answers provided below by Obi and Dan helped me to poke around a bit more and find out that the XML serializer actually throws an exception while the JSON serializer simply eats it and puts out an empty array which is what you see above.
There are any number of correct answers here.
Make your own custom serializer
Output JSON as a string
Return custom objects and then work around things like the Enum
values
I am sure there are others.
But whatever you do don't try to use System.Json as a return in the ApiController because you will get the results above.
You should not force your WebApi call to use a particular format like JSON. One of the features of WebApi is that you can specify the format as part of the request. Return an object from your Get call, and let the WebApi engine do the serialization and deserialization:
public class DataObject
{
public string Name { get; set; }
public string Description { get; set; }
}
public class ActionsController : ApiController
{
// GET api/actions
public DataObject Get()
{
var testObject = new DataObject
{
Name = "Test name",
Description = "Test Description"
};
return testObject;
}
}
You can specify the format by setting the Accept header to application/xml, application/json, etc.
The default JSON serializer has no problem serializing simple string properties like Name and Description.
I would suggest you did this instead
// GET api/actions
public object Get()
{
//New up a strongly typed object if you want to return a specific type
//and change Action return type accordingly
var testObjet = new (){
Name= "Test name",
Description= "Test Description"
};
return testObjet;
}
Dan has posted a similar answer below so let me try to address your other problem. To serialize the enum, I would suggest you hide it in a public string property which would return the string value of the enum,
public class DataObject{
public MyEnum SomeEnumValue;
public string EnumValue{
get {
//..return SomeEnumValue string value
}
}
}
You can then read the value from EnumValue which should be properly serialized as you want.