Newtonsoft Json throws ArgumentNullException - c#

I am using the Newtonsoft Json library to handle Json strings.
I am currently in a project in which I have to receive a string from a RabbitMQ server. The string looks like this when I convert from the RabbitMQ response to the JObject found in the library:
{ "LoanResponse": { "interestRate": "12.768", "ssn": "811671177" }}
When I call the following code:
public AbstractDTO ToDTO(JObject jsonObj)
{
BankResponseDTO dto = new BankResponseDTO();
dto.InterestRate = jsonObj.GetValue("interestRate").Value<double>(); // <-- here is where it throws
dto.SSN = jsonObj.GetValue("ssn").Value<String>();
return dto;
}
I get the ArgumentNullException. With the following message:
{"Value cannot be null.\r\nParameter name: source"}
It clearly contains an interest rate but it still tells me that it's null.
Anyone who might know what could be the issue here which i am facing difficult to find?

Related

Prevent error if txt/json file is not in the right format (corrupted) before reading it

I have an app that reads and rights to a txt file in a json format. Everything is working fine except that from time to time the txt/json file for some reason becomes corrupted and the app crashes when trying to read it.
Here is the code...
User Class
public class User
{
public string UserName { get; set; }
}
usersFile.txt (json)
[{"UserName":"someUserName"}]
Reading Class
public static string myUsersFolder = #"c:\myUsersFilder";
string usersFile = Path.Combine(myUsersFolder, "usersFile.txt");
public void readUsersFromFile()
{
try
{
if (!File.Exists(usersFile))
throw new FileNotFoundException();// throws an exception if the file is not found
string jsonContent = File.ReadAllText(Path.Combine(myUsersFolder, usersFile));
List<User> users = JsonConvert.DeserializeObject<List<User>>(jsonContent);
foreach (var u in users)
{
User user = new User();
user.UserName = u.UserName;
UsersObservableCollection.Add(user);
}
}
catch (FileNotFoundException f)
{
Console.WriteLine("Couldn't read users from file: " + f.Message);
}
}
Error
'The invocation of the constructor on type 'MyProgramName.ViewModel.ViewModelLocator' that matches the specified binding constraints threw an exception.'
The issue is that if at some point the file usersFile.txt becomes corrupted, where the format is not right, for instance missing a } curly bracket, the app crashes.
[{"UserName":"someUserName"] // missing a curly bracket, app crashes
How can I prevent the app from crashing if the file is in the wrong format?
You should use the .NET JSON serializer (System.Text.Json). The .NET JSON library has a modern async API (How to serialize and deserialize (marshal and unmarshal) JSON in .NET.
The original exception you are experiencing is the result of the failed deserialization. You could (but shouldn't) wrap the deserialization part alone into a try-catch block. Also don't explicitly throw an exception (FileNotFoundException) just to catch it (even in the same context). Rather show the error message directly (or log it).
Exceptions are very expensive. You would always try to avoid them. Checking if the file exists successfully avoids the FileNotFoundException. Job done.
For this sake, the correct approach would be to validate the JSON before you try to deserialize it: avoid the exception instead of handling it.
The following example shows a fixed version of your code. It also incorporates JSON validation to avoid any malformed input related exceptions.
The example also uses the StreamReader to read from the file asynchronously. this helps to avoid freezing your application during file handling. Generally use async APIs where possible.
public async Task readUsersFromFileAsync()
{
if (!File.Exists(usersFile))
{
Console.WriteLine("Couldn't read users from file: " + f.Message);
}
using var fileReader = new StreamReader(Path.Combine(myUsersFolder, usersFile));
string jsonContent = await fileReader.ReadToEndAsync();
if (!await TryValidateJsonInputAsync(jsonContent, out IList<string> errorMessages))
{
foreach (string errorMessage in errorMessages)
{
Console.WriteLine(errorMessage);
}
return;
}
List<User> users = JsonConvert.DeserializeObject<List<User>>(jsonContent);
foreach (var u in users)
{
User user = new User();
user.UserName = u.UserName;
UsersObservableCollection.Add(user);
}
}
private Task<bool> TryValidateJsonInputAsync(string jsonContentToValidate, out IList<string> messages)
{
var jsonSchemaText = new StreamReader("json_schema.txt");
JSchema jsonSchema = JSchema.Parse(jsonSchemaText);
JObject jsonToValidate = JObject.Parse(jsonContentToValidate);
return jsonToValidate.IsValid(jsonSchema, out messages);
}
The example JSON schema used in the example (json_schema.txt file).
{
'description': 'A person',
'type': 'object',
'properties': {
'name': {'type': 'string'},
'hobbies': {
'type': 'array',
'items': {'type': 'string'}
}
}
}
See the Newtonsoft documentation Validating JSON to get more detailed information on how to validate JSON input.
But again, I recommend the JsonSerializer from the System.Text.Json namespace as it offers an async API.

System.Text.Json.JsonException: The JSON value could not be converted

I'm using Ubuntu and dotnet 3.1, running vscode's c# extension.
I need to create a List from a JSON file, my controller will do some calculations with this model List that I will pass to it
So, here is my code and the error I'm getting.
First, I thought my error was because at model my attributes were char and C#, for what I saw, cannot interpret double-quotes for char, it should be single quotes. Before losing time removing it, I just changed my type declarations to strings and it's the same error.
Can someone help me?
ElevadorModel
using System.Collections.Generic;
namespace Bla
{
public class ElevadorModel
{
public int andar { get; set; }
public string elevador { get; set; }
public string turno { get; set; }
}
}
Program.cs:
class Program
{
static void Main(string[] args)
{
var path = "../input.json";
string jsonString;
ElevadorModel elevadoresModel = new ElevadorModel();
jsonString = File.ReadAllText(path); //GetType().Name = String
Console.WriteLine(jsonString); //WORKS
elevadoresModel = JsonSerializer.Deserialize<ElevadorModel>(jsonString);
}
JSON:
Your input json has an array as the base token, whereas you're expecting an object. You need to change your deserialization to an array of objects.
var elevadoresModels = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
elevadoresModel = elavoresModels.First();
Your input JSON is an array of models, however you're trying to deserialize it to a single model.
var models = JsonSerializer.Deserialize<List<ElevadorModel>>(jsonString);
This is also a problem in Blazor-Client side. For those calling a single object
e.g ClassName = await Http.GetFromJsonAsync<ClassName>($"api/ClassName/{id}");
This will fail to Deserialize. Using the same System.Text.Json it can be done by:
List<ClassName> ListName = await Http.GetFromJsonAsync<List<ClassName>>($"api/ClassName/{id}");
You can use an array or a list. For some reason System.Text.Json, does not give errors and it is successfully able Deserialize.
To access your object, knowing that it is a single object use:
ListName[0].Property
In your case the latter solution is fine but with the path as the input.
In my case, I was pulling the JSON data to deserialize out of an HTTP response body. It looked like this:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);
And the error would show up. Upon further investigation, I found the respBody string had the JSON base object (an array) wrapped in double quotes...something like this:
"[{\"prop\":\"value\"},...]"
So I added
respBody = respBody.Trim('\"');
And the error changed! Now it was pointing to an invalid character '\'.
I changed that line to include
respBody = respBody.Trim('\"').Replace("\\", "");
and it began to deserialize perfectly.
For reference:
var resp = await _client.GetAsync($"{endpoint}");
var respBody = await resp.Content.ReadAsStringAsync();
respBody = respBody.Trim('\"').Replace("\\", "");
var listOfInstances = JsonSerializer.Deserialize<List<modelType>>(respBody);

Not able to access public property from ts file in Html file

I need to get some data from service and display it in HTML. I have put API call in service, and I got that data in ts file(checked in console), But When I am trying to get the same data into html, its showing null reference exception. Couldnt figure out what I missed.
export class SsoComponent implements OnInit {
public samlResponseData: SamlResponse;
constructor(
private ssoService: SsoService,
private store: Store<AppState>) { }
ngOnInit() {
this.verifySessionExpiration();
}
public verifySessionExpiration() {
this.store.pipe(select(getAuthData))
.subscribe(authData => {
if (authData) {
this.ssoService.fetchSamlResponse()
.subscribe(samlResponse => {
console.log(samlResponse);
this.samlResponseData = samlResponse;
});
} else {
this.ssoService.goLogin();
}
});
}
I am seeing the correct response in console. This is my code in HTML.
{{samlResponseData.ResponseData}}
I am getting a console error saying, "Unable to set property 'ResponseData' of undefined or null reference"
I have a model SamlResponse with a string property that I want to show it in HTML.
Please help.
The logic you have in verifySessionExpiration() asynchronous. You are getting that error because your template is trying to access samlResponseData before it has a value.
One way to fix it would be to only render the data when you know the value isn't null or undefined.
<ng-container *ngIf="samlResponseData">
{{samlResponseData.ResponseData}}
</ng-container>
Another option would be to initialize samlResponseData to some empty object:
samlResponseData = {};

MongoDB db.runCommand() from C#

Hi I'm using C# with MongoDB Official driver v2.2.4 and I want to run db.runCommand() on the admin database.
So far i have this and i am able to connect to the admin database but db.runCommand is giving me this error "An unhandled exception of type 'System.FormatException' occurred in MongoDB.Bson.dll Additional information: JSON reader was expecting a value but found 'db'."
MongoClient client = new MongoClient();
database = client.GetDatabase("admin");
var collection = database.GetCollection<BsonDocument>("test");
var commandResult = database.RunCommand<string>(#"db.createCollection(test1)");
After I resolve this test I want to run this command from C# but I am stuck.
db.runCommand( { addshard : “localhost:10001”, name : “shard10001” } );
Any one can resolve this problem and provide me with a good explanation and example. After some search I have tried this code does seems to make more sense but still getting an error.
"Additional information: Command addshard failed: no such command: 'addshard', bad cmd: '{ addshard: "192.168.1.4:27017", name: "shard1" }'."
Any ideas please of what I'm doing wrong! Thanks.
var addShardCommand = new BsonDocument {
{ "addshard", "192.168.1.4:27017"},
{ "name", "shard1" }
};
var addShardResult = database.RunCommand<BsonDocument>(addShardCommand);
You need to check what is the correct command in mongodb. like sometime name need Document object instead of just string.
I am using something like this. check if this help
var name = new BsonDocument { { "name", "regions" } };
var command = new BsonDocument { { "listCollections", 1 }, { "filter", name } };
var result = Database.RunCommand<BsonDocument>(command);
var k = result.ToJson();
Here name is again object which I found from this documentation https://docs.mongodb.com/manual/reference/command/listCollections/
Some more help you can take from here
https://zetcode.com/csharp/mongodb/

Unexpected character encountered while parsing value

Currently, I have some issues. I'm using C# with Json.NET. The issue is that I always get:
{"Unexpected character encountered while parsing value: e. Path '', line 0, position 0."}
So the way I'm using Json.NET is the following. I have a Class which should be saved. The class looks like this:
public class stats
{
public string time { get; set; }
public string value { get; set; }
}
public class ViewerStatsFormat
{
public List<stats> viewerstats { get; set; }
public String version { get; set; }
public ViewerStatsFormat(bool chk)
{
this.viewerstats = new List<stats>();
}
}
One object of this class will be filled and saved with:
File.WriteAllText(tmpfile, JsonConvert.SerializeObject(current), Encoding.UTF8);
The saving part works fine and the file exists and is filled. After that the file will be read back into the class with:
try
{
ViewerStatsFormat current = JsonConvert.DeserializeObject<ViewerStatsFormat>(tmpfile);
//otherstuff
}
catch(Exception ex)
{
//error loging stuff
}
Now on the current= line comes the exception:
{"Unexpected character encountered while parsing value: e. Path '', line 0, position 0."}
I don't know why this comes. The JSON file is the following -> Click me I am the JSON link
Does anyone have any ideas?
Possibly you are not passing JSON to DeserializeObject.
It looks like from File.WriteAllText(tmpfile,... that type of tmpfile is string that contain path to a file. JsonConvert.DeserializeObject takes JSON value, not file path - so it fails trying to convert something like #"c:\temp\fooo" - which is clearly not JSON.
I solved the problem with these online tools:
To check if the Json structure is OKAY: http://jsonlint.com/
To generate my Object class from my Json structure: https://www.jsonutils.com/
The simple code:
RootObject rootObj= JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(pathFile));
In my case, the file containing JSON string had BOM. Once I removed BOM the problem was solved.
I experienced the same error in my Xamarin.Android solution.
I verified that my JSON was correct, and noticed that the error only appeared when I ran the app as a Release build.
It turned out that the Linker was removing a library from Newtonsoft.JSON, causing the JSON to be parsed incorrectly.
I fixed the error by adding Newtonsoft.Json to the Ignore assemblies setting in the Android Build Configuration (screen shot below)
JSON Parsing Code
static readonly JsonSerializer _serializer = new JsonSerializer();
static readonly HttpClient _client = new HttpClient();
static async Task<T> GetDataObjectFromAPI<T>(string apiUrl)
{
using (var stream = await _client.GetStreamAsync(apiUrl).ConfigureAwait(false))
using (var reader = new StreamReader(stream))
using (var json = new JsonTextReader(reader))
{
if (json == null)
return default(T);
return _serializer.Deserialize<T>(json);
}
}
Visual Studio Mac Screenshot
Visual Studio Screenshot
I have also encountered this error for a Web API (.Net Core 3.0) action that was binding to a string instead to an object or a JObject. The JSON was correct, but the binder tried to get a string from the JSON structure and failed.
So, instead of:
[HttpPost("[action]")]
public object Search([FromBody] string data)
I had to use the more specific:
[HttpPost("[action]")]
public object Search([FromBody] JObject data)
This issue is related to Byte Order Mark in the JSON file. JSON file is not encoded as UTF8 encoding data when saved. Using File.ReadAllText(pathFile) fix this issue.
When we are operating on Byte data and converting that to string and then passing to JsonConvert.DeserializeObject, we can use UTF32 encoding to get the string.
byte[] docBytes = File.ReadAllBytes(filePath);
string jsonString = Encoding.UTF32.GetString(docBytes);
I had the same problem with webapi in ASP.NET core, in my case it was because my application needs authentication, then it assigns the annotation [AllowAnonymous] and it worked.
[AllowAnonymous]
public async Task <IList <IServic >> GetServices () {
        
}
I ran into this issue and it ended up being because of BOM characters in my input string.
Here's what I ended up doing:
String.Trim(new char[] { '\uFEFF', '\u200B' });
This resolved the issue for me.
In my case, I was getting an error on JsonConvert.PopulateObject().
My request was returning JSON that was wrapped in an extra pair of '[ ]' brackets, making my result an array of one object rather than just an object. Here's what I did to get inside these brackets (only for that type of model):
T jsonResponse = new T();
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.DateTimeOffset,
NullValueHandling = NullValueHandling.Ignore,
};
var jRslt = response.Content.ReadAsStringAsync().Result;
if (jsonResponse.GetType() == typeof(myProject.Models.MyModel))
{
var dobj = JsonConvert.DeserializeObject<MyModel[]>(jRslt);
var y = dobj.First();
var szObj = JsonConvert.SerializeObject(y);
JsonConvert.PopulateObject(szObj, jsonResponse, settings);
}
else
{
JsonConvert.PopulateObject(jRslt, jsonResponse);
}
If you are using downloading data using url...may need to use
var result = client.DownloadData(url);
In my scenario I had a slightly different message, where the line and position were not zero.
E. Path 'job[0].name', line 1, position 12.
This was the top Google answer for the message I quoted.
This came about because I had called a program from the Windows command line, passing JSON as a parameter.
When I reviewed the args in my program, all the double quotes got stripped.
You have to reconstitute them.
I posted a solution here. Though it could probably be enhanced with a Regex.
I had a similar error and thought I'd answer in case anyone was having something similar. I was looping over a directory of json files and deserializing them but was getting this same error.
The problem was that it was trying to grab hidden files as well. Make sure the file you're passing in is a .json file. I'm guessing it'll handle text as well. Hope this helps.
I had simular problem. In my case the problem was in DateTime format. It was just numbers and it is also know as EpochFormat or UnixTimestamp.
A part from my JSON:
"direction": "outbound",
"date_archive": 1554691800224,
"date_doc": 1524700800000,
"date_sent": 1524704189000,
"date_received": 1524704189000,
"date_store_till": 1712544600224,
So I've used an attribute like this:
[JsonProperty("date_received")]
[JsonConverter(typeof(MicrosecondEpochConverter))]
public DateTime? DateReceived { get; set; }
You can find MicrosecondEpochConverter code here: https://stackoverflow.com/a/19972214/4324624
I faced similar error message in Xamarin forms when sending request to webApi to get a Token,
Make sure all keys (key : value) (ex.'username', 'password', 'grant_type') in the Json file are exactly what the webApi expecting, otherwise it fires this exception.
Unhandled Exception: Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0
Please check the model you shared between client and server is same. sometimes you get this error when you not updated the Api version and it returns a updated model, but you still have an old one. Sometimes you get what you serialize/deserialize is not a valid JSON.
In my case, it was the lack of a default parameterless constructor !!!
In my case, I was calling the async service method without using await, so before Task is completed I was trying to return the result!
Suppose this is your json
{
"date":"11/05/2016",
"venue": "{\"ID\":12,\"CITY\":Delhi}"
}
if you again want deserialize venue, modify json as below
{
"date":"11/05/2016",
"venue": "{\"ID\":\"12\",\"CITY\":\"Delhi\"}"
}
then try to deserialize to respective class by taking the value of venue
This error occurs when we parse json content to model object. Json content type is string.
For example:
https://dotnetfiddle.net/uFClKj
Some times, an api that we call may return an error. If we do not check the response status, but proceed to parse the response to model, this issue will occur.
When I encountered a similar problem, I fixed it by substituting &mode=xml for &mode=json in the request.

Categories

Resources