How to Debug System.Text.Json Deserializer - c#

In the case of deserializing JSON data using System.Text.Json where the data doesn't match the target model, it throws a NotSupportedException with no detail whatsoever.
If the data is complex, it can be very difficult to pin-point where the problem occurred.
Is there a way to get some more debug information, or some hint as to which member failed to deserialize?
EDIT
Here's a sample command
var result = await JsonSerializer.DeserializeAsync<ApiResponse<T>>(responseStream, OntraportSerializerOptions.Default, CancellationToken.None).ConfigureAwait(false);
Error message:
The collection type 'System.Collections.Generic.Dictionary2[System.Int32,OntraportApi.Models.ResponseSectionFields]' on 'OntraportApi.Models.ApiResponse1[System.Collections.Generic.Dictionary`2[System.Int32,OntraportApi.Models.ResponseSectionFields]].Data' is not supported.'
responseStream.Length = 18494, want me to paste it?

Related

Identify Cause of Serialization Error Coming From Inside Library/NuGet Package

Sometimes when calling the Mastercard MATCH API via the NuGet package MasterCard-Match, I will get a JSON deserialization exception:
Unexpected character encountered while parsing value: <. Path '',
line 0, position 0.
The exception is from MasterCard.Core with an inner exception from Newtonsoft.Json, both have the same message.
It looks like I'm receiving HTML ('<' at line 0, position 0) and the library is trying to deserialize it as JSON. My guess is that the MasterCard API is sending back an HTML error page instead of a JSON error. But I can't step into the function call to "see" the response its getting before throwing the exception.
As per the documentation I create a request map with the provided data and call TerminationInquiryRequest.Create(map), this is the line the exception is thrown. This function call is a black box, I can't step into it, it just throws the exception.
try
{
RequestMap requestMap = CreateRequestMap();
// This line throws the exception
TerminationInquiryRequest apiResponse = TerminationInquiryRequest.Create(requestMap);
}
catch(Exception e)
{
// Exception handling
}
I've made over 11,000+ calls using this library and only 32 have had this error, but of course I get to hear about it every time it happens.
Is there any way to debug libraries that I'm not aware of, or a way to view the response that the library is getting from the API?
I already have some logic to wait and retry the call if it fails.

How can I pass ARM template parameters through the API instead of a parameter file?

I'm attempting to automate the creation of some resources in Azure using Azure Resource Manager .NET libraries. I am able to create the Resource Group and have placed my ARM template in an accessible location on blob storage; however, I would like to be able to pass in the parameters to the request in code instead of staging a JSON file somewhere in storage.
It seems like this should be possible. For example, on the Deployment.Properties object, it has both Parameters and ParametersLink, but I cannot find any documentation on its usage and the following is throwing an exception saying that no value was specified for the parameters in the template:
deployment.Properties = new DeploymentProperties
{
Mode = DeploymentMode.Incremental,
TemplateLink = new TemplateLink("link-to-my-template-json-in-storage"),
Parameters = new
{
diskStorageAccountName = "value",
imageVhdPath = "value",
virtualNetworkName = "value",
virtualNetworkSubnetName = "value",
vmName = value,
vmAdminUserName = "value",
vmAdminPassword = "value"
}
};
This yields the following error:
An unhandled exception of type 'Microsoft.Rest.Azure.CloudException' occurred in mscorlib.dll
Additional information: Deployment template validation failed: 'The value for the template parameter 'diskStorageAccountName' at line '5' and column '32' is not provided. Please see http://aka.ms/arm-deploy/#parameter-file for usage details.'.
Am I doing something wrong? DeploymentProperties.Parameters is just an Object so I had assumed that it would be serialized and passed on correctly -- is this assumption incorrect?
Edit: The MSDN article is not very helpful either.
Edit 2: I wonder if this is a bug in the autogenerated code. See line 700 here:
https://github.com/Azure/azure-sdk-for-net/blob/master/src/ResourceManagement/Resource/ResourceManagement/Generated/DeploymentOperations.cs
Looks like it is trying to JObject.Parse
Edit 3: Opened an issue on GitHub.
For the Deployment Properties Parameters, you should use the JObject type from the Newtonsoft.Json.Linq namespace.
E.g.
using Newtonsoft.Json.Linq;
// paramJsonString is a string type object
Parameters = JObject.Parse(paramJsonString);
Note: The Microsoft.Azure.Management.Resources nuget package will be deprecated.
Strongly recommend to use Microsoft.Azure.ResourceManager
1.0.0-preview Microsoft.Azure.ResourceManager for your development related to Azure Resource Manager.
Hope this helps!
According to the source code testing, it has something of an odd layout...
#"{ 'siteName': {'value': 'mctest0101'},'hostingPlanName': {'value': 'mctest0101'},'siteMode': {'value': 'Limited'},'computeMode': {'value': 'Shared'},'siteLocation': {'value': 'North Europe'},'sku': {'value': 'Free'},'workerSize': {'value': '0'}}",
There is also an issue raised with similar problems
I've not currently got time to test this! so if it doesn't work let me know and I'll delete this answer.

dotnetrdf xml exception using QueryWithResultSet

I have an asp.net project in which, I would like to query DBPedia.
Using the following code I am getting an error:
public string testEndpoint()
{
//TEST02
SparqlRemoteEndpoint endpoint = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"), "http://dbpedia.org");
string res = "";
//Make a SELECT query against the Endpoint
SparqlResultSet results = endpoint.QueryWithResultSet("SELECT ?year WHERE {dbpedia:Rihanna dbpedia-owl:birthYear ?year}");
foreach (SparqlResult result in results)
{
res = result.ToString();
Console.WriteLine(result.ToString());}
Error message: "An exception of type 'System.Xml.XmlException' occurred in dotNetRDF.dll but was not handled in user code".
Even if I handle the exception the method cannot be executed. Regarding the details it says that there is an invalid XML-version 1.1.
As the XML comes from DBPedia I don't know how to change the xml version or how else I can handle this problem.
Virtuoso, which is the triple store used behind the dbpedia SPARQL endpoint, has updated its XML result generation. They replaced the XML version 1.0 with 1.1 in this commit. This causes the exception in the dotNetRDF parser.
Later on Virtuoso reverted the changes in the XML header. Hopefully DBPedia will update their binaries soon, so the old XML header appears again in the SPARQL results.
Source: http://github.com/openlink/virtuoso-opensource/issues/405

Unsupported Media Type error when using json-patch in Ramone

Update: I downloaded Ramone project, added it to my project and then ran the application again with debugger. The error is shown below:
public MediaTypeWriterRegistration GetWriter(Type t, MediaType mediaType)
{
...
CodecEntry entry = SelectWriters(t, mediaType).FirstOrDefault(); => this line throws error
...
}
Error occurs in CodecManager.cs. I am trying to figure out why it does not recognize json-patch media type. Could it be because writer is not being registered correctly? I am looking into it. If you figure out the problem, please let me know. Since you are the author of the library, it will be easier for you to figure out the issue. I will have to go through all the code files and methods to find the issue. Thanks!
I was excited to know that Ramone library supports json-patch operations but when I tried it, I got following error:
415- Unsupported Media Type
This is the same error that I get when I use RestSharp. I thought may be RestSharp does not support json-patch and errors out so I decided to try Ramone lib but I still get same error. Endpoint has no issues because when I try same command using Postman, it works but when I try it programmatically in C#, it throws unsupported media type error. Here is my code:
var authenticator = new TokenProvider("gfdsfdsfdsafdsafsadfsdrj5o97jgvegh", "sadfdsafdsafdsfgfdhgfhehrerhgJ");
JsonPatchDocument patch = new JsonPatchDocument<MetaData>();
patch.Add("/Resident2", "Boyle");
//patch.Replace("/Resident", "Boyle");
RSession = RamoneConfiguration.NewSession(new Uri("https://api.box.com"));
RSession.DefaultRequestMediaType = MediaType.ApplicationJson;
RSession.DefaultResponseMediaType = MediaType.ApplicationJson;
Ramone.Request ramonerequest = RSession.Bind("/2.0/files/323433290812/metadata");
ramonerequest.Header("Authorization", "Bearer " + authenticator.GetAccessToken(code).AccessToken);
//var ramoneresponse = ramonerequest.Patch(patch); //results in error: 405 - Method Not Allowed
var ramoneresponse = ramonerequest.Put(patch); //results in error: 415 - Unsupported Media Type
var responsebody = ramoneresponse.Body
Endpoint information is available here: http://developers.box.com/metadata-api
I used json-patch section in the following article as a reference:
http://elfisk.dk/Ramone/Documentation/Ramone.pdf
By the way I tried Patch() method (as shown in above ref. article) but that resulted in "Method not allowed" so I used Put() method which seems to work but then errors out because of json-patch operation.
Any help, guidance, tips in resolving this problem will be highly appreciated. Thanks much in advance.
-Sham
The Box documentation says you should use PUT (which is quite a bit funny). The server even tells you that it doesn't support the HTTP PATCH method (405 Method Not Allowed) - so PUT it must be.
Now, you tell Ramone to use JSON all the time (RSession.DefaultRequestMediaType = MediaType.ApplicationJson), so you end up PUT'ing a JSON document to Box - where you should be PUT'ing a JSON-Patch document.
Drop the "RSession.DefaultRequestMediaType = MediaType.ApplicationJson" statement and send the patch document as JSON-Patch with the use of: ramonerequest.ContentType("application/json-patch+json").Put(...).

Twitterizer2 1.2.4 Streaming API exception - Unexpected end when deserializing object

Any help would be appreciated. I'm getting an exception thrown during deserialization inside JSON.Net:
Unexpected end when deserializing object. Line 216, position 2.
My calling code:
var asyncResult = s.StartPublicStream(streamErrorCallback, statusCreatedCallback, statusDeletedCallback, eventCallback, rawJsonCallback);
Setting a breakpoint in my rawJsonCallback handler shows (what appears to be) valid JSON coming back from the API.
Added the source for Twitterizer2 and JSON.Net, looks like Twitterizer.Streaming.TwitterStream.ParseMessage(string) is failing here near line 520
var user = obj.SelectToken("user", false);
if (user != null)
{
if (statusCreatedCallback != null && user.HasValues)
{
statusCreatedCallback(JsonConvert.DeserializeObject<TwitterStatus>(ConvertJTokenToString(obj)));
}
return;
}
On the call to DeserializeObject().
Newtonsoft.Json.Serliazation.JsonSerializerInternalReader.PopulateObject() fails because the reader.TokenType == None.
I suspect there is a discrepancy between the contract type/values and the object coming back from the API, but I'm not sure how to test further. Wasn't able to get the Json.Net source to compile so I can't step through it.
The problem is that Twitterizer 2.4 is using NewtonSoft.Json v4.08, which breaks it. Install Newtonsoft.Json v4.03, and you'll be fine.
Maybe this could solve your issue. I had a simillar one when I wanted to use the twitterize with JSON.NET 4.5
I follow the steps that someone mentioned on github and then I've compiled the whole source code with the new json lib and voilá ;)

Categories

Resources