WCF answer processing C# - c#

There is a WCF service and I need to use it`s method.
method takes 3 parameters - string, DateTime, DateTime.
So my code is like this:
ServiceReference.LogsServiceClient myclient;
myclient = new ServiceReference.LogsServiceClient();
var response = myclient.GetHotPeriodLogs("somestring", dtFrom, dtTo);
========
Returned data type of method is some array (ServiceReference.TechLog[])
It seems the answer is the array of json responses.
So, I have the exception "Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1"
I should like to ask, what is the method to work with the answer?
Further, I need to insert each string of data into MSSQL DB, so I need to get sets of data. So, what I have to do?

ok. at first let us assume this is your ServiceReference.TechLog object:
public class TechLog
{
public DateTime CreationDate { get; set; }
public string Email { get; set; }
public bool IsApproved { get; set; }
}
now we need a json deserilzer method like this:
public static T JsonDeserializer<T>(string jsonString)
{
var settings = new JsonSerializerSettings { DateFormatHandling=DateFormatHandling.MicrosoftDateFormat };
var instance = JsonConvert.DeserializeObject<T>(jsonString, settings);
return instance;
}
that's all we need. now we can deserilze any thing like this:
var x = JsonDeserializer<TechLog[]>(response);

Related

Deserialize JSON object into a class with a "dynamic" property

I am receiving JSON messages that are matched to the following class:
public class Response
{
public int Code { get; }
public string Message { get; }
public string Result { get; }
}
But the value of Result property depends on what we get in Code and does not have a fixed structure.
E.g. if Code = 1, Result will return a list of objects of type X and if Code = 2, Result will return a list of objects of type Y.
When I try to deserialize a message I am receiving, having Result type set to string does not seem to work.
var responseObj = JsonConvert.DeserializeObject<Response>(response);
if (responseObj.Code == 1)
{
return responseObj.Result;
}
The return statement above throws the following exception:
Unexpected character encountered while parsing value: [. Path 'Result'
How can I define my class so that it receives the entire text of Result and I can decide about its deserialization later? Because all my requests respond to with the above structure and I'd like to manage all these requests from the same place.
How can I define my class so that it receives the entire text of Result and I can decide about its deserialization later?
If that is what you want to do then make your Result property a JToken instead of a string as shown below. You will also need to add setters to all of the properties shown in your Response class to allow the deserialization to work properly: you can't deserialize into read-only properties.
public class Response
{
public int Code { get; set; }
public string Message { get; set; }
public JToken Result { get; set; }
}
Once you know what type the Result should be converted into, you can use the ToObject() method to do that. For example:
Response responseObj = JsonConvert.DeserializeObject<Response>(response);
if (responseObj.Code == 1)
{
var listOfX = responseObj.Result.ToObject<List<X>>();
...
}
Fiddle: https://dotnetfiddle.net/pz5m63

Deserialize a complex JSON object having DynamicJsonArray to dynamic

I have a client that sends SomeComplexObject to a webservice.
I want the webservice to be unaware of the structure of the data,
so want the data to be deserialized to a dynamic that is passed then to a method that knows how to deal with it.
I use System.Web.Helpers.Json.Encode(), Decode() methods
and I have a problem when SomeComplexObject contains a collection.
It is deserialized to a DynamicJsonArray but it is somehow not accessible
for the consumer of the data.
These are Model types.
public class Aaa
{
public Bbb B { get; set; }
public List<Ccc> Cccs { get; set; }
}
public class Bbb
{
public long Key { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class Ccc
{
public string Name { get; set; }
public int Age { get; set; }
}
Let us say that I have a myAaa object of type Aaa with a property of type Bbb
and a list of 42 Ccc objects.
Now:
var MyAaaSerialized = System.Web.Helpers.Json.Encode(MyAaa);
Then I send it and then:
var MyAaaDeserialized = System.Web.Helpers.Json.Decode(MyAaaSerialized);
And finally:
This is the code of the consumer. Email and emailService are Postal classes.
dynamic email = new Email(template);
email.Data = MyAaaDeserialized;
email.User = user;
this.emailService.Send(email);
I can see in the sent email that properties of B object are accessible.
However, properties of members of Cccs list are not.
Of course with email.Data = MyAaa; everything works OK.
Is there any dead simple way to serialize/deserialize a complex object that contains a collection?
Thanks in advance,
If I haven't misunderstood your question, it can be resolved by using the Decode overload that uses generics as below. Just specifying the type (Aaa in this case) worked for me in the code below and it printed all ccc properties correctly:
var myAaa = new Aaa()
{
B = new Bbb() { Name = "someone", DateOfBirth = DateTime.Today.AddYears(-20) },
Cccs = Enumerable.Repeat<Ccc>(new Ccc() { Age = 20, Name = "someone else" }, 42).ToList()
};
var MyAaaSerialized = System.Web.Helpers.Json.Encode(myAaa);
var MyAaaDeserialized = System.Web.Helpers.Json.Decode<Aaa>(MyAaaSerialized);
dynamic data = MyAaaDeserialized;
foreach (Ccc newCccs in data.Cccs)
{
Console.WriteLine($"{newCccs.Name}\t{newCccs.Age}");
}
Ok, I was wrong. System.Web.Helpers.Json.Encode() and Decode() work correctly. I`ll tell you what happened:
I used to use Postal mailsender locally, i.e. I used to take my super-complex POCO object and pass it as a dynamic to Postal Email class. And it worked.
Now I want some webservice to send emails so I need to pass serialized data to it. I have sent a test email and I`ve seen that values of some of the fields are not present in the email message, but 'DynamicJsonObject' is there instead. So I assumed (wrong), that the structure of deserialized object is somehow corrupted.
But the truth is different:
The missing data is of complex type, say
public class Money
{
public double Amount {get; set;}
public string Currency {get; set;}
public override ToString()
{...}
}
So when I asked in Razor email template for:
#item.Prices.SalePriceGross locally,
it somehow must have used the ToString() method.
And of course in a serialized / deserialized object there is no knowledge about the ToString() method.
I am going to need to expose a property with the string I want to display or (better) access Amount and Currency explicitly and process them in Razor email template.
Thank you for help.

How to deserialize an immutable data structure?

How would I deserialize YAML to a immutable data structure?
e.g. I have this YAML:
Value: SomeString
Number: 99
And this data structure:
public class MyData
{
public MyData(string value, int number)
{
Value = value;
Number = number;
}
public string Value { get; }
public int Number { get; }
}
For this I'd to use the constructor. So somehow I'd need to first retrieve a Dictionary<string, object> parsed from the YAML respecting my class (so 99 would be int, not string), then scan my type for an appropriate constructor,
Although the question doesn't mention it, I'm assuming you are using YamlDotNet (or SharpYaml which is a fork of YamlDotNet)
YamlDotNet doesnt support deserializing into classes that do not have a default constructor - but one option to achieve what you want is to deserialize into an intermediate Builder type that is mutable which can produce the final type.
e.g.
public class MyDataBuilder
{
public string Value { get; set; }
public int Number { get; set; }
public MyData Build() => new MyData(Value, Number);
}
And then use something like:
deserializer.Deserialize<MyDataBuilder>(yaml).Build();
You would end up having to create a parallel set of builders for your whole model however, e.g. if MyData had a third parameter of type MyOtherData (I've changed the example to use records instead of classes to make it concise):
public record MyOtherData(string OtherValue);
public record MyData(string Value, int Number, MyOtherData otherData);
In which case we would need another Builder:
public class MyOtherDataBuilder
{
public string OtherValue { get; set; }
}
And MyDataBuilder would look like:
public class MyDataBuilder
{
public string Value { get; set; }
public int Number { get; set; }
public MyOtherDataBuilder MyOtherData { get; set; }
public MyData Build() => new MyData(Value, Number, MyOtherData.Build());
}
It's an old but surprisingly relevant question. Now, with records in C#, immutable collections in .net, lack of ability to deserialize immutable data is a blocker - there is no way we need to change all our data types just to be able to deserialize. One practical workaround that I found - is to convert yaml to json first, then deal with json your preferred way - System.Text.Json, Newtonsoft, etc.
Here is how to do is easiest way:
static string ConvertToJson(string yaml) {
object DeserializeYaml() =>
new DeserializerBuilder()
.Build()
.Deserialize(new StringReader(yaml))
?? throw new InvalidOperationException("Cannot deserialize yaml string:" + Environment.NewLine + yaml);
string SerializeYamlObjectToJson(object yamlObject) =>
new SerializerBuilder()
.JsonCompatible()
.Build()
.Serialize(yamlObject);
return SerializeYamlObjectToJson(DeserializeYaml());
}
The only disadvantage, potentially big, is performance. I feel, however, that it's rarely an important requirement for yaml.
use the FormatterServices.GetUninitializedObject API (this will NOT invoke any constructors at all) and then use reflection to set fields.
Code example:
var instance = FormatterServices.GetUninitializedObject(typeof(MyData));
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var type = typeof(MyData);
var stringField = type.GetField("_value", flags);
stringField.SetValue(instance, "SomeString");
var numberField = type.GetField("_number", flags);
numberField.SetValue(instance, 99);
MyData data = (MyData)instance;

Selective json deserialization c# and json.net

I am using an API which returns JSON response.
The issue im facing is the way they return their error messages:
They return
["501","Invalid apikey"]
instead of the normal json response which is serialized to :
public class AvailableItemResponse : IResponse
{
public AvailableItemResponse ()
{
AvailableItems = new List<AvailableItem>();
}
public int ResponseId { get; set; }
public string SearchId { get; set; }
public int TotalFound { get; set; }
public List<AvailableItem> AvailableItems { get; set; }
}
How can I check the json format and select which type to deserialze the object to ?
Thanks for your help. :-)
If you are using HttpClient there should be a Code on the object received. Would thing something like the following will help.
if(response.code != 200){
//handle the error
}
The problem in this case is that you don't have a key-value json. You could check for the position of the elements and if it's a fixed parameter you can look at (for example) the first parameter and compare it to the code of the ok message (probably always the same). In this case the ResponseId is 501 so you shouldn't parse the json.
So if first parameter is STATUS_CODE_OK parse the json otherwise not.

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facebook;
using Newtonsoft.Json;
namespace facebook
{
class Program
{
static void Main(string[] args)
{
var client = new FacebookClient(acc_ess);
dynamic result = client.Get("fql", new { q = "select target_id,target_type from connection where source_id = me()"});
string jsonstring = JsonConvert.SerializeObject(result);
//jsonstring {"data":[{"target_id":9503123,"target_type":"user"}]}
List<RootObject> datalist = JsonConvert.DeserializeObject<List<RootObject>>(jsonstring);
}
public class Datum
{
public Int64 target_id { get; set; }
public string target_type { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
}
}
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[facebook.Program+RootObject]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be
I looked at other posts.
My json looks like this:
{"data":[{"target_id":9503123,"target_type":"user"}]}
To make it clear, in addition to #SLaks' answer, that meant you need to change this line :
List<RootObject> datalist = JsonConvert.DeserializeObject<List<RootObject>>(jsonstring);
to something like this :
RootObject datalist = JsonConvert.DeserializeObject<RootObject>(jsonstring);
As the error message is trying very hard to tell you, you can't deserialize a single object into a collection (List<>).
You want to deserialize into a single RootObject.
Can you try to change your json without data key like below?
[{"target_id":9503123,"target_type":"user"}]
That happened to me too, because I was trying to get an IEnumerable but the response had a single value. Please try to make sure it's a list of data in your response. The lines I used (for api url get) to solve the problem are like these:
HttpResponseMessage response = await client.GetAsync("api/yourUrl");
if (response.IsSuccessStatusCode)
{
IEnumerable<RootObject> rootObjects =
awaitresponse.Content.ReadAsAsync<IEnumerable<RootObject>>();
foreach (var rootObject in rootObjects)
{
Console.WriteLine(
"{0}\t${1}\t{2}",
rootObject.Data1, rootObject.Data2, rootObject.Data3);
}
Console.ReadLine();
}
Hope It helps.
The real problem is that you are using dynamic return type in the FacebookClient Get method. And although you use a method for serializing, the JSON converter cannot deserialize this Object after that.
Use insted of:
dynamic result = client.Get("fql", new { q = "select target_id,target_type from connection where source_id = me()"});
string jsonstring = JsonConvert.SerializeObject(result);
something like that:
string result = client.Get("fql", new { q = "select target_id,target_type from connection where source_id = me()"}).ToString();
Then you can use DeserializeObject method:
var datalist = JsonConvert.DeserializeObject<List<RootObject>>(result);
Hope this helps.
public partial class tree
{
public int id { get; set; }
public string name { get; set; }
public string sciencename { get; set; }
public int familyid { get; set; }
}
private async void PopulateDataGridView()
{
//For Single object response
tree treeobj = new tree();
treeobj = JsonConvert.DeserializeObject<tree>(Response);
//For list of object response
List<tree> treelistobj = new List<tree>();
treelistobj = JsonConvert.DeserializeObject<List<tree>>(Response);
//done
}

Categories