I am creating a nested custom type with primitive datatypes.
I am having a Web APi that returns the data in JSON.
using json2csharp.com, I am generating classes for the same.
I have decorated the primitive datatypes in all classes with DataMember and the types with DataContract.
I am using the following code for deserialization:
var resp = httpClient.GetAsync("http://ACTUAL_API_URI").Result;
var res = await resp.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
byte[] byteArr= Encoding.ASCII.GetBytes(res);
var ms = new MemoryStream(byteArr);
var deserializedObj= (RootObject)serializer.ReadObject(ms);
I am not getting any exception. but the deserializedObj has null values for all the properties.
Any suggestions ?
You have a couple mistakes.
You returns collection of elements and try to deserialize one element instead collection
public IEnumerable<SampleData> Get()
{
return new SampleData[]
{
new SampleData()
{
Value = 100,
NestedTypeObject1 = new NestedType1()
{
ID = 101,
BD = "Description#1",
UD = "Description#2"
},
NestedTypeObject2 = new NestedType2()
{
Date = DateTime.Now.ToString(),
S1 = "S1 String",
S2 = "S2 String"
}
}
};
}
so you just change your code to
var serializer = new DataContractJsonSerializer(typeof(List<RootObject>));
var deserializedObj= (List<RootObject>)serializer.ReadObject(ms);
You have different model names between service side and client side, just you your SampleData model and all will be good. You must to rename MyNestedType1 to NestedTypeObject1 or add name to DataContractAttribute, e.g:
[DataContract(Name = "NestedTypeObject1")]
public class MyNestedType1
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string BD { get; set; }
[DataMember]
public string UD { get; set; }
}
It belongs for property names too.
Related
Returns Json format data to me from an api.
However, the type of the "FuelType" property inside the object may be different. For example, 1 time comes as follows:
{
...
fuelType: "gasoline"
...
}}
But then it can happen:
{
...
fuelType: ["gasoline", "any"]
...
}}
If I set the "FuelType" property type on my model to a string, in the second case, Json will give me an error when it arrives, because it can't convert from array to string. No, if I set the type to an array, then, conversely, if a string arrives, it will issue an error because it cannot convert from a string to an array.
In this case, what should I put the "FuelType" property type in my model so that it does not make an error when deserializing?
It all depends on you,what type of value you want to receive?string or List?
I tried with the codes:
public class SomeModel
{
public SomeModel()
{
fuelType = new List<string>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<string> fuelType { get; set; }
//you could move the codes to someservice
public List<string> someresult(string a)
{
var targetlist = new List<string>();
targetlist.Add(a);
return targetlist;
}
public List<string> someresult(List<string> a)
{
var targetlist = new List<string>();
targetlist.AddRange(a);
return targetlist;
}
}
[HttpPost]
public JsonResult SomeAction()
{
var somemodel = new SomeModel() { Id = 1, Name = "name" };
var somevalue = /*"a"*/new List<string>() { "a", "b", "c" };
var targetvalue = somemodel.someresult(somevalue);
somemodel.fuelType.AddRange(targetvalue);
return new JsonResult(somemodel);
}
Result:
try this
var fuelType = JsonConvert.DeserializeObject<MyClass>(json);
public class MyClass
{
[JsonProperty("fuelType")]
private JToken _fuelType;
[JsonIgnore]
public string[] fuelType
{
get {
if (_fuelType==null) return null;
return _fuelType is JArray ? _fuelType.ToObject<string[]>() : new string[] { (string)_fuelType }; }
set { _fuelType = JsonConvert.SerializeObject(value); }
}
}
We are using 3rd party api kraken.io to optimize our images.
The results of optimized image is posted in a Webhook.
In their api document it states: After the optimization is over Kraken will POST a message to the callback_url specified in your request in a JSON format application/json.
I am using ngrok to allow remote webhooks to send data to my development machine, using this article.
Results posted to the Callback URL:
HTTP/1.1 200 OK
{
"id": "18fede37617a787649c3f60b9f1f280d",
"success": true,
"file_name": "header.jpg",
"original_size": 324520,
"kraked_size": 165358,
"saved_bytes": 159162,
"kraked_url": "http://dl.kraken.io/18/fe/de/37617a787649c3f60b9f1f280d/header.jpg"
}
Class to Map
public class KrakenOptimizedResults
{
public string id { get; set; }
public bool success { get; set; }
public string file_name { get; set; }
public int original_size { get; set; }
public int kraked_size { get; set; }
public int saved_bytes { get; set; }
public string kraked_url { get; set; }
}
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string jsonString = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
KrakenOptimizedResults obj = new JavaScriptSerializer().Deserialize<KrakenOptimizedResults>
(jsonString);
return Json(obj);
}
But When I debug the received jsonString in Html Visualizer it looks like key and value pairs instead of Json format.
Received Results not Json Formatted:
file_name=header.jpeg&original_size=118066&kraked_size=102459&saved_bytes=15607
I guess the received data content-type: is application/x-www-form-urlencoded.
Why i am receiving key and value pairs instead of Json format ? how can I deserialize Json data in asp.net mvc ?
Co-founder of https://kraken.io here.
There is a glaring omission in our documentation which I will fix today. To get JSON back, you need to set a "json": true flag in the request. Omitting that flag or setting "json": false will return URLEncoded. Example cURL request:
curl http://api.kraken.io/v1/upload -X POST --form data='{"auth":{"api_key":"YOUR_KEY", "api_secret":"YOUR_SECRET"}, "wait": true, "lossy": true, "callback_url": "http://requestb.in/wbhi63wb", "json": true}' --form upload=#test.jpg
Sorry for the inconvenience :-(
I was able to convert Query String Key and Value pairs to Json Format using this and this post ,there is some delay to convert form Dictionary to Json, so If there is better answers, then do post and advice, below is my solution.
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string data = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
var dict = HttpUtility.ParseQueryString(data);
var json = new JavaScriptSerializer().Serialize(dict.AllKeys.ToDictionary(k => k, k =>
dict[k]));
KrakenOptimizedResults obj = new JavaScriptSerializer().Deserialize<KrakenOptimizedResults>
(json);
return Json(obj);
}
Recieving JSON formated optimized results from kraken API.
As mentioned by #karim79, To get JSON back, you need to set a "json": true flag in the request.
As Kraken .Net/C# SDK didn't have option to set "json": true, so i have to extend their base class.
Extended Base Class:
public class OptimizeRequestBaseExtended : OptimizeRequestBase,
IOptimizeUploadRequest, IRequest
{
public OptimizeRequestBaseExtended(Uri callbackUrl)
{
CallbackUrl = callbackUrl;
}
[JsonProperty("callback_url")]
public Uri CallbackUrl { get; set; }
[JsonProperty("json")]
public bool JsonFormat { get; set; }
}
Request Kraken API:
var callbackUrl = new Uri("http://localhost:0000/Home/OptimizedWebHook");
OptimizeRequestBaseExtended settings = new OptimizeRequestBaseExtended(callbackUrl);
settings.Lossy = true;
settings.JsonFormat = true;
var response = client.Optimize(image: image, filename: filename, optimizeRequest: settings);
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string jsonString = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
KrakenOptimizedResults obj = JsonConvert.DeserializeObject<KrakenOptimizedResults>
(jsonString);
return Json(obj);
}
Step 1:
Create an aspx page. This page must be able to accept HTTP POST request.
Step 2:
Add this code to get HTTP POST data.File: default.aspx.cs
File: default.aspx.cs
var reader = new StreamReader(Request.InputStream);
var json = reader.ReadToEnd();
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(json.ToString() + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 3:
Create webhook. This code can be linked to a button on click event.File:default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
List<string> events = new List<string>();
events.Add("Update");
string postback = list.CreateWebhook(events, "URL", "json");
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(postback + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 4:
Activate webhook. Copy that webhook id from the text file and past it to the code below.
File:default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
list.ActivateWebhook("webhook id");
Step 5:
Test weebhook.File: default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
string postback = list.TestWebhook("webhook id").ToString();
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(postback + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 6:
Deserialize body of JSON object. We need to create class structure based on JSON data. I put sample json here and it created required classes
public class CustomField
{
public string Key { get; set; }
public string Value { get; set; }
}
public class Event
{
public List<CustomField> CustomFields { get; set; }
public string Date { get; set; }
public string EmailAddress { get; set; }
public string Name { get; set; }
public string SignupIPAddress { get; set; }
public string Type { get; set; }
}
public class RootObject
{
public List<Event> Events { get; set; }
public string ListID { get; set; }
}
Once you have created your class, append the code from step 2 after
var json = reader.ReadToEnd();
to deserialize and parse json.
RootObject myClass = JsonConvert.DeserializeObject(json);
if (myClass != null)
{
List<Event> t = myClass.Events;
string old_email = "", new_email = "";
old_email = t[0].OldEmailAddress;
new_email = t[0].EmailAddress;
//now you can do your logic with old_email and new_email
}
What is the right way to serve OData-queryable GET requests in ASP.NET Web Api? That may sound like a "what is better" question, but it should be a "what does work" question.
Some assumptions:
To enable OData-querying, you have to put the Queryable attribute to the action method that returns IQueryable<Model>. Therefore, you have to expose the domain model?
The domain model uses Entity Framework 5 and has navigation properties. The XML and Json Serializers do not like the EF proxies, so you have to disable them for OData queries?
The serializers pick up the navigation properties and serve them to the user.
So if I have a Category type that has navigation properties for parent and children, the serializers complain that I have cyclic references, and I cannot get rid of this error.
I have read that I should use DTOs, but HOW? How can I provide a IQueryable<DTOModel> to the user that will create the appropriate SQL for the database? Remember, I want to use $filter and the like.
I just want to give the user a filterable list of Model objects without the serialized navigation properties.... but HOW?
You don't have to expose IQueryable<> - you can create a method that accepts an instance of ODataQueryOptions and process this yourself. Here's a code sample that does most of what you require. It should be more than enough for you to work out the solution that works best for you. This method will also allow you to keep your EF proxy classes.
using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;
[ActionName("Dto")]
public IList<DtoModel> GetDto(ODataQueryOptions<DtoModel> queryOptions)
{
var data2 = DatabaseData();
//Create a set of ODataQueryOptions for the internal class
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Model>("Model");
var queryContext = new ODataQueryContext(
modelBuilder.GetEdmModel(), typeof(Model));
var newQueryOptions = new ODataQueryOptions<Model>(queryContext, Request);
var t = new ODataValidationSettings() { MaxTop = 25 };
var s = new ODataQuerySettings() { PageSize = 25 };
newQueryOptions.Validate(t);
IEnumerable<Model> results =
(IEnumerable<Model>)newQueryOptions.ApplyTo(data2, s);
int skip = newQueryOptions.Skip == null ? 0 : newQueryOptions.Skip.Value;
int take = newQueryOptions.Top == null ? 25 : newQueryOptions.Top.Value;
IList<Model> internalResults = results.Skip(skip).Take(take).ToList();
// map from Model to Dto here using AutoMapper
AutoMapper.Mapper.CreateMap<Model, DtoModel>();
IList<DtoModel> webResults =
AutoMapper.Mapper.Map<IList<Model>, IList<DtoModel>>(internalResults);
return webResults;
}
The data used in the example is a simple Queryable set of data:
private IQueryable<Model> DatabaseData()
{
return (
new Model[] {
new Model() { id = 1, name = "one", type = "a" },
new Model() { id = 2, name = "two", type = "b" },
new Model() { id = 3, name = "three", type = "c" },
new Model() { id = 4, name = "four", type = "d" },
new Model() { id = 5, name = "five", type = "e" },
new Model() { id = 6, name = "six", type = "f" },
new Model() { id = 7, name = "seven", type = "g" },
new Model() { id = 8, name = "eight", type = "h" },
new Model() { id = 9, name = "nine", type = "i" }
})
.AsQueryable();
}
These are the test classes:
public class Poco
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class DtoModel
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class Model
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
public virtual ICollection<Poco> Pocos { get; set; }
}
I need some help...
I have my entity that i have create manually.
public class Project()
{
public Project Data {get;set;}
public string ProjectID { get; set; }
public string AreaID { get; set; }
public string Country { get; set; }
}
Where property "Project" is the the table created by SQLmetal.
I have also created my class, with SQLmetal, wish there have there own entity.
Now i trying to parse between them in the constructor like:
public Project()
{
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
But when I use
projects.Select(p => new Project { Data = p });
the Data property in the constructor is null.
Any idea why? and how will I solve this the better way?
Yes, because the initializer
var x = new Project { Data = p };
is equivalent to
var x = new Project();
x.Data = p;
The Data property is set AFTER the constructor.
You can solve it by creating a constructor that takes Data as a parameter
public Project(Data data)
{
this.Data = Data;
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
and call the constructor
projects.Select(p => new Project(p));
So I'm trying to deserialize an object that has properties: $ref and $id. I have tried going between Dictionary as well as an object where I have specified namingconventions via JsonPropertyAttribute. Serialization works, but deserialization doesn't. The error I keep getting is:
Additional text found in JSON string
after finishing deserializing object.
Sample code where all three samples, fail.
[Serializable]
public class Ref
{
[JsonProperty(PropertyName = "$ref")]
public virtual string RefName { get; set; }
[JsonProperty(PropertyName = "$id")]
public virtual int Id { get; set; }
}
[Serializable]
public class Child
{
public virtual string Name { get; set; }
[JsonProperty(IsReference = true)]
public virtual Ref Father { get; set; }
}
class Program
{
static void Main(string[] args)
{
//Additional text found in JSON string after finishing deserializing object.
//Test 1
var reference = new Dictionary<string, object>();
reference.Add("$ref", "Persons");
reference.Add("$id", 1);
var child = new Dictionary<string, object>();
child.Add("_id", 2);
child.Add("Name", "Isabell");
child.Add("Father", reference);
var json = JsonConvert.SerializeObject(child);
var obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); //Exception
//Test 2
var refOrg = new Ref {RefName = "Parents", Id = 1};
var refSer = JsonConvert.SerializeObject(refOrg);
var refDeser = JsonConvert.DeserializeObject<Ref>(refSer); //Exception
//Test 3
var childOrg = new Child {Father = refOrg, Name = "Isabell"};
var childSer = JsonConvert.SerializeObject(childOrg);
var childDeser = JsonConvert.DeserializeObject<Child>(refSer); //Exception
}
}
I have the same issue when trying to deserialize a swagger/json schema document. The solution is:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
You'll find that $ref & $id are special properties used by Json.NET to manage multiple instances of objects in a single object graph.
By putting these keys into your dictionary the deserialize process is trying to parse these as references to objects that don't exist.
Try altering the keys.
This answer worked for me: Json.Net adding $id to EF objects despite setting PreserveReferencesHandling to "None"
In your implementation of DefaultContractResolver/IContractResolver, add this;
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}