How to post complex object with a child collection in WebAPI - c#

I am trying to post an object in my controller but it is coming in null. The object is a complex type and suspect it is the reason why Im getting an exception.
public class CertificateRequest
{
public string Name {get;set;}
public string RequestNumber {get;set;}
public List<TradeUnit> TradeUnits {get;set;}
}
public class TradeUnit
{
public string TradeUnitNumber {get;set;}
}
Controller:
[HttpPost]
public IHttpActionResult Post(CertificateRequest req)
{
........
}
When I check Swagger, it appears the object its expecting is silently different.
<CertificateRequest>
<Name>Some Name</Name>
<RequestNumber>Req001</RequestNumber>
<TradeUnits>
<TradeUnitNumber>TUN0005</TradeUnitNumber>
</TradeUnits>
</CertificateRequest>
The problem happens when I have multiple TradeUnits I would like to post and would have my structure to be in the following format, how do I achieve this.
<CertificateRequest>
<Name>Some Name</Name>
<RequestNumber>Req001</RequestNumber>
<TradeUnits>
<TradeUnit>
<TradeUnitNumber>TUN0001</TradeUnitNumber>
</TradeUnit>
<TradeUnit>
<TradeUnitNumber>TUN0002</TradeUnitNumber>
</TradeUnit>
<TradeUnit>
<TradeUnitNumber>TUN0003</TradeUnitNumber>
</TradeUnit>
</TradeUnits>
</CertificateRequest>
How can I achieve this?

Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication135
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME, settings);
CertificateRequest request = new CertificateRequest();
XmlSerializer serializer = new XmlSerializer(typeof(CertificateRequest));
serializer.Serialize(writer, request);
}
}
public class CertificateRequest
{
public string Name { get; set; }
public string RequestNumber { get; set; }
[XmlArray("TradeUnits")]
[XmlArrayItem("TradeUnit")]
public List<TradeUnit> tradeUnits { get; set; }
public CertificateRequest()
{
Name = "Some Name";
RequestNumber = "Req001";
tradeUnits = new List<TradeUnit>() {
new TradeUnit() { TradeUnitNumber = "TUN0001"},
new TradeUnit() { TradeUnitNumber = "TUN0002"},
new TradeUnit() { TradeUnitNumber = "TUN0003"}
};
}
}
public class TradeUnit
{
public string TradeUnitNumber { get; set; }
}
}
Using following will eliminate a tag
[XmlElement("TradeUnit")]
public List<TradeUnit> tradeUnits { get; set; }

Related

How do I call JSON in a simplified manner

I am connecting to an external API which seems to be returning JSON
using (var client = new APIClient())
{
var data = client.General.GetAccountInfo().Data.Balances;
}
When I move over .Data.Balances, it shows:
IEnumerable<API.Net.Objects.Spot.SpotData.APIBalance>
API.Net.Objects.Spot.SpotData.APIAccountInfo.Balances { get; set; }
List of assets and their current balances
Here is an extract of the JSON data:
"balances":[
{
"asset":"ABC",
"free":"0.00000000",
"locked":"0.00000000"
},
{
"asset":"DEF",
"free":"0.00000000",
"locked":"0.00000000"
},
{
"asset":"GHI",
"free":"0.00000000",
"locked":"0.00000000"
}
]
How do I make use of this data so if I type console.writeline(data[0]["asset"]), it gives me ABC?
This seems to be the simplist solution:
using System.Linq;
using (var client = new APIClient())
{
var data = client.General.GetAccountInfo().Data.Balances.ToList();
Console.WriteLine(data[0].asset);
Console.WriteLine(data[0].free);
Console.WriteLine(data[0].locked);
}
Hy,
From the sample file you can create a class ´balance »
Public class balance
{
Public string asset {get; set;}
Public Free .......
Public Locked .....
}
And then you can use Json.net
To deserialize the JSon file
public void serializejson()
{
List balances = JsonConvert.DeserializeObject<List>(data);
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Game
{
public class Balance
{
[JsonPropertyName("asset")]
public string Asset { get; set; }
[JsonPropertyName("free")]
public string Free { get; set; }
[JsonPropertyName("locked")]
public string Locked { get; set; }
}
public class Root
{
[JsonPropertyName("balances")]
public List<Balance> Balances { get; set; }
}
class Program
{
static void Main(string[] args)
{
var data = File.ReadAllText("test.json");
var deserialized = JsonSerializer.Deserialize<Root>(data);
var balances = deserialized.Balances;
// Don't iterati in such a way! Use foreach instead.
for (int i = 0; i < balances.Count; i++)
{
Console.WriteLine($"{balances[i].Asset} {balances[i].Free} {balances[i].Locked}");
}
foreach (var balance in balances)
{
Console.WriteLine($"{balance.Asset} {balance.Free} {balance.Locked}");
}
}
}
}
You can use this code for you:
public class Balance {
public string asset { get; set; }
public string free { get; set; }
public string locked { get; set; }
}
public class Root {
public List<Balance> balances { get; set; }
}
And for deserialize:
using (var client = new APIClient())
{
var data = client.General.GetAccountInfo().Data.Balances;
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(data);
Console.WriteLine(myDeserializedClass.balances[0].asset);
}

C# receiving json string but unable to deserialize it

i have an application that has to deserialize an array of data wrapped in a "results" Root Object, using Netwonsoft.Json package from NuGet
The Json string is exactly this:
{"results":[{"Coin":"SBD","LP":0.000269,"PBV":-54.36,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true},{"Coin":"XMR","LP":0.027135,"PBV":11.44,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true}]}
This Json string is created from a Console App i made, i wanted it to look like this https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-NEO&tickInterval=hour
My class looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp2
{
public class Result
{
public string Coins { get; set; }
public decimal LastPrice { get; set; }
public decimal PercentBuyVolume { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
}
In the Main form i have a function to download from a URL that Json (i have XAMPP running Apache) and deserialize it in an array. And it looks like this:
private void DownloadBittrexData()
{
int PanelID = 0;
var Coin = new List<string>();
var LastPrice = new List<decimal>();
var PercentBuyVolume = new List<decimal>();
var MACD1M = new List<bool>();
var MACD30M = new List<bool>();
var MACD1H = new List<bool>();
var MACD1D = new List<bool>();
var client = new WebClient();
var URL = client.DownloadString("http://localhost/test.json");
Console.WriteLine("Json String from URL: " + URL);
var dataDeserialized = JsonConvert.DeserializeObject<RootObject>(URL);
foreach (var data in dataDeserialized.results)
{
Coin.Add(data.Coins);
LastPrice.Add(data.LastPrice);
PercentBuyVolume.Add(data.PercentBuyVolume);
}
int sizeOfArrayClose = Coin.Count - 1;
for (int i = 0; i <= sizeOfArrayClose; i++)
{
Console.WriteLine("Coin: " + Coin[i]);
Console.WriteLine("Lastprice: " + LastPrice[i]);
Console.WriteLine("PBV: " + PercentBuyVolume[i]);
}
}
Newtonsoft.Json is of course declared at the beginning of the form together with System.Net
using System.Net;
using Newtonsoft.Json;
The output looks like this:
Json String from URL: {"results":[{"Coin":"SBD","LP":0.000269,"PBV":-54.36,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true},{"Coin":"XMR","LP":0.027135,"PBV":11.44,"MACD1M":true,"MACD30M":true,"MACD1H":true,"MACD1D":true}]}
Coin:
Lastprice: 0
PBV: 0
Coin:
Lastprice: 0
PBV: 0
It's like it fails to deserialize it after downloading it.
What should i do? Thank you very much.
Your property names don't map to the field names in the JSON. You could rename your C# properties to match the JSON, but it would make for unreadable downstream code.
Instead, you should map your properties (with nice, readable names) to the names that appear in the JSON, using JsonPropertyAttribute:
public class Result
{
public string Coin { get; set; } //didn't bother here: changed property name to Coin
[JsonProperty("LP")]
public decimal LastPrice { get; set; }
[JsonProperty("PBV")]
public decimal PercentBuyVolume { get; set; }
}
your model should be like this for deserialize json
public class Result
{
public string Coin { get; set; }
public double LP { get; set; }
public double PBV { get; set; }
public bool MACD1M { get; set; }
public bool MACD30M { get; set; }
public bool MACD1H { get; set; }
public bool MACD1D { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
LastPrice and PercentBuyVolume are not available in your model that's the reason it's getting an error.
I tried your exact code on my system and I was able to retrieve the result as expected. Hope this helps, It's easy to understand.
Here is the main class
static void Main(string[] args)
{
RootObject configfile = LoadJson();
foreach (var tResult in configfile.results)
{
Console.WriteLine("Coin: " + tResult.Coin);
Console.WriteLine("Lastprice: " + tResult.LP);
Console.WriteLine("PBV: " + tResult.PBV);
}
Console.ReadLine();
}
LoadJson Function would be
private static RootObject LoadJson()
{
string json = "{\"results\":[{\"Coin\":\"SBD\",\"LP\":0.000269,\"PBV\":-54.36,\"MACD1M\":true,\"MACD30M\":true,\"MACD1H\":true,\"MACD1D\":true},{\"Coin\":\"XMR\",\"LP\":0.027135,\"PBV\":11.44,\"MACD1M\":true,\"MACD30M\":true,\"MACD1H\":true,\"MACD1D\":true}]}";
RootObject configs = Deserialize<RootObject>(json);
return configs;
}
and Deserialize function would be
private static T Deserialize<T>(string json)
{
T unsecureResult;
string _DateTypeFormat = "yyyy-MM-dd HH:mm:ss";
DataContractJsonSerializerSettings serializerSettings = new DataContractJsonSerializerSettings();
DataContractJsonSerializer serializer;
MemoryStream ms;
unsecureResult = default(T);
serializerSettings.DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat(_DateTypeFormat);
serializer = new DataContractJsonSerializer(typeof(T));
ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
unsecureResult = (T)serializer.ReadObject(ms);
return unsecureResult;
}
and Now your Datamodel would be
public class Result
{
public string Coin { get; set; }
public double LP { get; set; }
public double PBV { get; set; }
public bool MACD1M { get; set; }
public bool MACD30M { get; set; }
public bool MACD1H { get; set; }
public bool MACD1D { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}

c# serialise model to objectContent

I have the following class I want to serialise:
public class UpdateDoorCommand : IXmlSerializable
{
// string such as D1
public string DoorId { get; }
public string Name { get; }
public string Notes { get; }
public UpdateDoorCommand(string doorId, string name, string notes)
{
DoorId = doorId;
Name = name;
Notes = notes;
}
public UpdateDoorCommand()
{
}
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("Door");
writer.WriteAttributeString("Address", "D1");
writer.WriteElementString("Name", Name);
writer.WriteElementString("Notes", Notes);
writer.WriteEndElement();
}
}
I want the output to look like this:
<Door Address="D1">
<Name>Name1</Name>
<Notes>Notes1</Notes>
</Door>
I use the following code to serialise the object:
[TestMethod]
public async Task XmlSerialisationTest()
{
var model = new UpdateDoorCommand("D1", "Name1", "Notes1");
var mediaTypeFormatters = new MediaTypeFormatterCollection();
mediaTypeFormatters.XmlFormatter.UseXmlSerializer = true;
mediaTypeFormatters.XmlFormatter.WriterSettings.OmitXmlDeclaration = true;
var content = new ObjectContent<UpdateDoorCommand>(model, mediaTypeFormatters.XmlFormatter);
// this does not look like the type
var str = await content.ReadAsStringAsync();
}
}
However the the output of the serialisation does not give the desired results.
The xml is wrapped in an element with the classname of the object.
How can I get desired xml output using the ObjectContent class?
Note that the code needs a reference to System.Net.Http.Formatting in order to run.
I'm not sure if the two ways are compatible but try this:
[XmlRoot(ElementName = "Door", DataType = "string")]
public class UpdateDoorCommand : IXmlSerializable
{
// *snip*
public void WriteXml(XmlWriter writer)
{
//writer.WriteStartElement("Door");
writer.WriteAttributeString("Address", "D1");
writer.WriteElementString("Name", Name);
writer.WriteElementString("Notes", Notes);
//writer.WriteEndElement();
}
}
Simple with Xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
UpdateDoorCommand updateDoorCommand = new UpdateDoorCommand("D1","Name1","Note1");
updateDoorCommand.WriteXml();
}
}
public class UpdateDoorCommand
{
// string such as D1
public string DoorId { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public UpdateDoorCommand(string doorId, string name, string notes)
{
DoorId = doorId;
Name = name;
Notes = notes;
}
public UpdateDoorCommand()
{
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml()
{
XElement doorCommand = new XElement("Door", new object[] {
new XAttribute("Address", DoorId),
new XElement("Name", Name),
new XElement("Notes1", Notes)
});
}
}
}

Deserialize XML into Object

Im trying to deserialize an xml response from from Amazons simple db service.
The xml is like this.
<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<ListDomainsResult>
<DomainName>Logging</DomainName>
<DomainName>teets</DomainName>
</ListDomainsResult>
<ResponseMetadata>
<RequestId>9d48122e-1ddf-8771-b771-b36599838ea0</RequestId>
<BoxUsage>0.0000071759</BoxUsage>
</ResponseMetadata>
</ListDomainsResponse>
And the object i'm trying to serialize into is this.
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
public class ListDomainsResult
{
public List<String> DomainNames { get; set; }
public string NextToken { get; set; }
}
public class Response
{
public static string NameSpace = "http://sdb.amazonaws.com/doc/2009-04-15/";
public ResponseMetadata ResponseMetadata{ get; set; }
}
public class ResponseMetadata
{
public string RequestId { get ; set; }
public string BoxUsage { get; set; }
}
My problem is that the response metadata is getting deserialized correctly but the List of strings called DomainName is not being deserialized, it is empty each time.
Can someone see what i'm doing wrong.
Updated with more code
public async Task<Response> ListDomains (ListDomainsRequest request)
{
using (Client = new HttpClient ()) {
ListDomainsRequestMarshaller marshaller = new ListDomainsRequestMarshaller ();
marshaller.Configure (request);
HttpResponseMessage responseMessage = Client.GetAsync (marshaller.Marshal ()).Result;
ListDomainsResponseUnMarshaller unmarshaler = new ListDomainsResponseUnMarshaller (responseMessage);
return unmarshaler.Response;
}
}
public ListDomainsResponseUnMarshaller (HttpResponseMessage message)
{
XDocument doc = XDocument.Load (message.Content.ReadAsStreamAsync ().Result);
if (message.StatusCode.Equals (HttpStatusCode.OK)) {
Serializer = new XmlSerializer (typeof(ListDomainsResponse), Response.NameSpace);
Response = (ListDomainsResponse)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
} else {
Serializer = new XmlSerializer (typeof(Response));
Response = (Response)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
}
Serializer = null;
}
Adding Attributes helped
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute ("ListDomainsResponse", Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResult
{
[System.Xml.Serialization.XmlElementAttribute ("DomainName")]
public string[] DomainName { get; set; }
public string NextToken { get; set; }
}

Deserialize part of a binary file

Is it possible to deserialize part of a binary file?
Basically I have an object similar to below, which I serialize into a binary file.
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> { get; set; } // lots of data in here (order of kB-MB)
}
What I would like is to be able to deserialize only Name and Value by way of populating a ListView for file selection purposes and then deserialize the rest of the file when needed (i.e. the user chooses that file from the ListView).
As always, any help greatly appreciated and if any 3rd party libraries are suggested they would need to be able to be used freely in a commercial environment.
protobuf-net can do that, because it is not tied to the specific type; for example:
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
[ProtoContract]
public class MyOtherObject { }
[ProtoContract]
public class MyObject
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
[ProtoMember(3)]
public IList<MyOtherObject> Items { get; set; }
}
[ProtoContract]
public class MyObjectLite
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
}
static class Program
{
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
Serializer.Serialize(file, obj);
}
MyObjectLite lite;
using (var file = File.OpenRead("foo.bin"))
{
lite= Serializer.Deserialize<MyObjectLite>(file);
}
}
}
But if you don't want two different types, and/or you don't want to have to add attributes - that can be done too:
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;
public class MyOtherObject { }
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> Items { get; set; }
}
static class Program
{
static readonly RuntimeTypeModel fatModel, liteModel;
static Program()
{
// configure models
fatModel = TypeModel.Create();
fatModel.Add(typeof(MyOtherObject), false);
fatModel.Add(typeof(MyObject), false).Add("Name", "Value", "Items");
liteModel = TypeModel.Create();
liteModel.Add(typeof(MyOtherObject), false);
liteModel.Add(typeof(MyObject), false).Add("Name", "Value");
}
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
fatModel.Serialize(file, obj);
}
MyObject lite;
using (var file = File.OpenRead("foo.bin"))
{
lite = (MyObject)liteModel.Deserialize(
file, null, typeof(MyObject));
}
}
}
How about putting the Name and Valueinto a superclass and serializing them separately?
Alternatively, you could maintain a Dictionary and serialize that into one file.

Categories

Resources