I've a method that deserialize string into a type.
var data = JsonConvert.DeserializeObject<TestData>("invalid json");
If string is not valid, JsonReaderException occurring.
I want to return default value of TestData (null) when string is not valid instead of throw exception.
How can I do this without try/catch and JObject?
You can use JsonSerializerSettings to handle it the result of it will be NULL.
The reference of JsonConvert.DeserializeObject and JsonSerializerSettings.Error
var settings = new JsonSerializerSettings
{
Error = (se, ev) =>
{
ev.ErrorContext.Handled = true;
}
};
var data = JsonConvert.DeserializeObject<Currency>("invalid json", settings);
Related
I am serializing a generic list of OfflineTransaction objects into a json file. When I deserialize the list back it does not deserialize the base class but instead the parent class for a property of the OfflineTransaction. For example, an OfflineTransaction has a NewEvent object and a NewEvent's parent is a NewDBRecord class. The issue I am having is the json file show's it being serialized as a NewEvent but it is being deserialized as a NewDBRecord.
Any help is appreciated in getting this NewEvent back instead of a NewDBRecord, etc.
Example json file
"$type": "DTData.Offline.OfflineTransaction, DTData",
"ExtraData": null,
"SqlStatement": "",
"StoredProcedure": "",
"OracleParameters": null,
"DBRecord": {
"$type": "DTData.Data.NewDBRecord.NewEvent, DTData",
....
//how I serialize a list of offline transactions
List<OfflineTransaction> offlineTransactionsList = new List<OfflineTransaction>(offlineTransactions);
var settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.TypeNameHandling = TypeNameHandling.All;
var jsonString = JsonConvert.SerializeObject(offlineTransactionsList,settings);
File.WriteAllText(fileName, jsonString);
// how I deserialize the list
var result = JsonConvert.DeserializeObject<List<OfflineTransaction>>(File.ReadAllText(fileName));
Figured the problem out. I was not passing in any settings when doing the deserializing.
Below is the solution
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.All;
var result = JsonConvert.DeserializeObject<List<OfflineTransaction>>(File.ReadAllText(fileName),settings);
I have a WebAPI server that has a Hub that replies to Subscribe requests by publishing an Dictionary<long, List<SpecialParam>> object.
The list of SpecialParam contains items of type SpecialParamA & SpecialParamB which both inherit SpecialParam.
When I try to capture the publish on the client:
hubProxy.On<Dictionary<long, List<SpecialParam>>>(hubMethod, res =>
{
DoStuff();
});
The DoStuff() method isn't called. If I change the publish return value to string, and change the proxy to receive a string value, the DoStuff() method is called. Therefore, the problem is with the deserialization of the SpecialParam Item.
I tried configuring on the server-side:
var serializer = JsonSerializer.Create();
serializer.TypeNameHandling = TypeNameHandling.All;
var hubConfig = new HubConfiguration();
hubConfig.Resolver.Register(typeof(JsonSerializer), () => serializer);
GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => serializer);
But it didn't help.
I also tried adding to the client:
HubConnection hubConnection = new HubConnection(hubPath);
hubConnection.JsonSerializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
hubProxy = hubConnection.CreateHubProxy(hubName);
hubProxy.JsonSerializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
And it also didn't help.
In other solutions I found that people defined a new IParameterResolver, but it is only called when the server receives the input to the hub method, and not when the output is published from the hub.
Please help!
UPDATE
Here is what I caught with fidler:
{"$type":"Microsoft.AspNet.SignalR.Hubs.HubResponse, Microsoft.AspNet.SignalR.Core","I":"0"}
This is what the server replies to the client.
UPDATE 2
I'm still trying to figure out how to receive it already deserialized as Dictionary<long, List<SpecialParam>>.
I solved it by setting in the service:
public static void ConfigureApp(IAppBuilder appBuilder)
{
...
var service = (JsonSerializer)GlobalHost.DependencyResolver.GetService(typeof(Newtonsoft.Json.JsonSerializer));
service.TypeNameHandling = TypeNameHandling.All;
...
}
and removing the expected type in the client:
hubProxy.On(hubMethod, res =>
{
DoStuff();
});
I get the response in json form and I deserialize it with:
var serializer = new JsonSerializer();
serializer.TypeNameHandling = TypeNameHandling.All;
JObject jObject = resp as JObject;
var specialParams = jObject.ToObject<Dictionary<long, List<SpecialParam>>>(serializer);
I still don't know how to make my client receive it already deserialized.
I'm trying to use JsonSerializerSettings for custom error handling, but when I specify the object type the error stops in runtime debugging. The "json" is no valid JSON, due to remote error that is out of my hands to change/fix.
Working:
var responseData = JsonConvert.DeserializeObject(json,new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
Error = (sender, args) =>
{
// My error handling
}
});
Breaks With:
Additional information: Error converting value "Received merchantid does not match a registered merchant" to type 'TransmitModels+errorData'. Path ...
TransmitModels.errorData responseData = JsonConvert.DeserializeObject<TransmitModels.errorData>(json,new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
Error = (sender, args) =>
{
// My error handling
}
});
You need to call
args.ErrorContext.Handled = true;
in your callback to tell Json.NET that you handled the exception. If you don't (maybe because you just want to log the error), the exception is thrown after your callback.
We have scenario where external API returns either User XML or Error XML based on whether request succeed or failed.
At the moment I'm passing User POCO to the restsharp and works fine. But if it fails, this object is NULL. And we won't know why it failed unless we parse the Error XML manually.
Is there a way to workaround this?
e.g.
var restClient = new RestClient(baseURL);
var request = new RestRequest(uri);
request.Method = Method.POST;
var response = restClient.Execute<User>(request);
On execution of above method the API can return Error xml object. How do I get Error object on fail and User on success?
This is possible, although the code is a little ugly. RestSharp allows you to specify your own XML deserializer, so we'll need to do that in order to make this work.
First, though, you need a data type that can store either an Error or a User (I made it generic so it works for more than just Users):
public class Result<T>
{
public T Data { get; set; }
public Error Error { get; set; }
}
So the idea is, now when you execute the request, you ask RestSharp for a Result<User> instead of just a User, i.e.:
var result = client.Execute<Result<User>>(request);
Now here's the magic required to deserialize as either an Error or a User. It's a custom deserializer that inherits from RestSharp's XmlDeserializer. Warning: this code is not tested at all, but it can hopefully point you in the right direction.
public class XmlResultDeserializer : XmlDeserializer
{
public override T Deserialize<T>(IRestResponse response)
{
if (!typeof(T).IsGenericType || typeof(T).GetGenericTypeDefinition() != typeof(Result<>))
return base.Deserialize<T>(response);
// Determine whether the response contains an error or normal data.
var doc = XDocument.Parse(response.Content);
var result = Activator.CreateInstance<T>();
if (doc.Root != null && doc.Root.Name == "Error")
{
// It's an error
var error = base.Deserialize<Error>(response);
var errorProperty = result.GetType().GetProperty("Error");
errorProperty.SetValue(result, error);
}
else
{
// It's just normal data
var innerType = typeof(T).GetGenericArguments()[0];
var deserializeMethod = typeof(XmlDeserializer)
.GetMethod("Deserialize", new[] { typeof(IRestResponse) })
.MakeGenericMethod(innerType);
var data = deserializeMethod.Invoke(this, new object[] { response });
var dataProperty = result.GetType().GetProperty("Data");
dataProperty.SetValue(result, data);
}
return result;
}
}
Then you would wire it all up like this:
var restClient = new RestClient(baseURL);
client.AddHandler("application/xml", new XmlResultDeserializer());
var request = new RestRequest(uri);
request.Method = Method.POST;
var result = restClient.Execute<Result<User>>(request);
if (response.Data.Data != null)
{
var user = response.Data.Data;
// Do something with the user...
}
else if (response.Data.Error != null)
{
var error = response.Data.Error;
// Handle error...
}
in asp web api i have this controller that respond to ajax request and send back json data:
public IEnumerable<PersonaleDTO> GetPersonale()
{
var n = (from p in db.Personale
select new PersonaleDTO { Id = p.Id, Nome = p.Nome, Cognome = p.Cognome Cellulare = p.Cellulare, Email = p.Email, Attivo = (bool)p.Attivo }).ToList();
return n;
}
This method return seven object and it's correct.
Now when i receive back the data in the json format i see that i receive also and $id member along with the id, Nome, Cognome...
What is the $id variable? How can remove this from the json response?
Try this code in WebApiConfig
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
Edit : If for some reason you're using a custom ContractResolver then as per this post
The custom ContractResolver setting overrides the PreserveReferencesHandling setting.
In your implementation of DefaultContractResolver/IContractResolver, add this;
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}
This behaves similarly to the PreserveReferencesHandling.None setting without a custom ContractResolver.