I'm relatively new to C# and I'm looking to replicate this following JSON expression:
{"itemData":[{"pile":"club","id":"100997087277"}]}
At present I have the following methods:
public class MoveItemValues
{
public string pile;
public Int64 id;
}
public class MoveItemRequestValues
{
public MoveItemValues itemData;
}
internal string moveItem(Int64 itemId, string pile)
{
string moveItemResponse;
MoveItemRequestValues bodyContent = new MoveItemRequestValues();
bodyContent.itemData = new MoveItemValues();
bodyContent.itemData.pile = pile;
bodyContent.itemData.id = itemId;
string jsonContent = JsonConvert.SerializeObject(bodyContent);
byte[] byteArray = Encoding.UTF8.GetBytes(jsonContent);
Console.WriteLine(jsonContent);
}
This produces:
"{"itemData":{"pile":"trade","id":100997087277}}"
But as you can see the square brackets are missing.
How would I go about finishing off achieving this?
itemData is an array in the json string.
FYI: You need to follow the C# naming guidelines. Property and method should be Pascal case.
public class MoveItemValues
{
public string Pile;
public Int64 Id;
}
public class MoveItemRequestValues
{
public IList<MoveItemValues> ItemData;
public MoveItemRequestValues()
{
ItemData = new List<MoveItemValues>();
}
}
static void MoveItem(Int64 itemId, string pile)
{
string moveItemResponse;
MoveItemRequestValues bodyContent = new MoveItemRequestValues();
bodyContent.ItemData = new List<MoveItemValues>()
{
new MoveItemValues {Pile = pile, Id = itemId}
};
var camelCaseFormatter = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string jsonContent = JsonConvert.SerializeObject(bodyContent, camelCaseFormatter);
byte[] byteArray = Encoding.UTF8.GetBytes(jsonContent);
Console.WriteLine(jsonContent);
}
static void Main(string[] args)
{
MoveItem(100997087277, "trade");
Console.ReadLine();
}
Use List<>
public class MoveItemRequestValues
{
public List<MoveItemValues> itemData;
}
Related
How can I set JsonSerializer to not add "\u0022" to string for EventData property? Because I get:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{\u0022Id\u0022:1,\u0022Email\u0022:\u0022test#test.test\u0022}"}
I will never deserialize EventData, it must be readable. And I want:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{Id:1,Email:test#test.test}"}
My code:
public class EmailSent
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserCreated
{
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public string EventData { get; set; }
}
var emailSent = new EmailSent
{
Id = 1,
Email = "test#test.test"
};
var userCreated = new UserCreated
{
Id = 5,
CreateDate = DateTime.UtcNow,
EventData = JsonSerializer.Serialize(emailSent) // I will never deserialize it
};
string result = JsonSerializer.Serialize(userCreated);
You can use, for example, UnsafeRelaxedJsonEscaping:
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string json = JsonSerializer.Serialize(userCreated, serializeOptions);
This will produce the following output:
{
"Id": 5,
"CreateDate": "2021-04-21T07:49:23.4378969Z",
"EventData": "{\"Id\":1,\"Email\":\"test#test.test\"}"
}
Reference: How to customize character encoding with System.Text.Json. Please read the caution there:
Caution
Compared to the default encoder, the UnsafeRelaxedJsonEscaping encoder is more permissive about allowing characters to pass through unescaped:
(...)
This happens because JsonSerializer.Serialize() is invoked more than once.
You can specify 'JSONSerializerOptions' Encoder equal to JavaScriptTenCoder. Create(new TextEncoderSettings(UnicodeRanges.All))
like this
public static string ToString(this object str)
{
try
{
string sResult = JsonSerializer.Serialize(str, new JsonSerializerOptions{WriteIndented = true, Encoder = JavaScriptEncoder.Create(new TextEncoderSettings(System.Text.Unicode.UnicodeRanges.All))});
return sResult;
}
}
I have almost the exact same problem, only my UserCreated is being returned by ASP.NET controller function, I don't directly control serialization.
The simplest solution is to change the type of EventData to JsonNode.
To set EventData from whatever complex object you want, you can use this awkward construct
EventData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
Complete minimal example:
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "String",
FormData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
// prints {"FormName":"String","FormData":{"A":"B"}}
}
}
public class NestedJason
{
public string FormName { get; set; }
public JsonNode FormData { get; set; }
}
A cleaner option is to make FormData type object. (I'm assuming you don't want to make it type EmailSent because you want to store random data about many different types of events.) If you round trip the EventData as object, it will go in as EmailSent and come back out as JsonElement. Manual steps would be required to get it back to an EmailSent.
public class Tests
{
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "Sting",
FormData = complexData
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
NestedJason result = JsonSerializer.Deserialize(
JsonSerializer.Serialize(toSerialize),
typeof(NestedJason)) as NestedJason;
Console.WriteLine(result.FormData.GetType().Name);
}
}
public class NestedJason
{
public string FormName { get; set; }
public Object FormData { get; set; }
}
(I personally will be using the previous JsonNode option, that is more editable, but the object option skips that round trip serialization kludge.)
string sampleString = "[{\"id\":\"1\",\"status\":302},{\"id\":\"2\",\"status\":302},{\"id\":\"3\",\"status\":302},{\"id\":\"4\",\"status\":302}]";
JArray json = JArray.Parse(sampleString );
TempValue t;
foreach(JObject obj in json)
{
t = new TempValue {
id =//id of json,
status=//state of json
};
}
i want to access value of json anonymous objec to assign to t object.
It is always good to work with a typed object to avoid typing mistakes. In this case create a class with the structure of the json string like so:
public class StatusObj
{
public string id { get; set; }
public int status { get; set; }
}
The deserialize the json string to list of your class like so:
List<StatusObj> obj = JsonConvert.DeserializeObject<List<StatusObj>>(sampleString);
And then you can loop through the list like so:
foreach (var item in obj)
{
var id = item.id;
var status = item.status;
}
The whole code look like this:
class Program
{
static void Main(string[] args)
{
string sampleString = "[{\"id\":\"1\",\"status\":302},{\"id\":\"2\",\"status\":302},{\"id\":\"3\",\"status\":302},{\"id\":\"4\",\"status\":302}]";
List<StatusObj> obj = JsonConvert.DeserializeObject<List<StatusObj>>(sampleString);
foreach (var item in obj)
{
var id = item.id;
var status = item.status;
}
}
}
public class StatusObj
{
public string id { get; set; }
public int status { get; set; }
}
NB. Newtonsoft.Json package needed to be installed. You can also convert any json to class here
By the indexer
foreach(JObject obj in json)
{
t = new TempValue {
id = obj["id"].ToString() ,
...
};
Object.Item Property (String)
Gets or sets the JToken with the specified property name.
I am trying to read the incoming message on RabbitMQ via Akka.streams.Ampq source but the RoutingKey is incorrect.
Another concerning issue that the envelope does not contain the exchange name.
//code coming back with incorrect key
public void Consume(IActorRef consumerActor)
{
//Source =RabbitMQ
//Sink = Our App
var queueDeclaration = QueueDeclaration.Create(QueueName)
.WithDurable(true)
.WithAutoDelete(false);
var amqpSource = AmqpSource.AtMostOnceSource(
NamedQueueSourceSettings.Create(ConnectionSettings, QueueName).WithDeclarations(queueDeclaration),
bufferSize: 10);
var sink = Sink.ActorRef<SubMessage>(consumerActor, "complete");
var result =
amqpSource.Select(b => new SubMessage(b.Bytes.ToString(Encoding.UTF8), ConvertProperties(b.Properties), b.Envelope.RoutingKey))
.TakeWhile(x => { return true; }, true)
.RunWith(sink, Materializer);
}
//publish Method
public void Publish(dynamic message, string exchangeName)
{
var typeOf = message.GetType().Name;
var jsonMessage = Newtonsoft.Json.JsonConvert.SerializeObject(message);
//Source = Our App
//Sink = RabbitMQ
//Connections
AmqpConnectionDetails.Create(_ampqSettings.Host, _ampqSettings.Port)
.WithCredentials(AmqpCredentials.Create(_ampqSettings.UserName, _ampqSettings.Password))
.WithAutomaticRecoveryEnabled(true)
.WithNetworkRecoveryInterval(TimeSpan.FromSeconds(1));
var queueDeclaration = QueueDeclaration.Create(QueueName)
.WithDurable(true)
.WithAutoDelete(false);
var exchangeDeclaration = ExchangeDeclaration.Create(exchangeName, "direct").WithDurable(true);
var bindingDeclaration = BindingDeclaration.Create(QueueName, exchangeName).WithRoutingKey(typeOf);
//create sink
var amqpSink = AmqpSink.CreateSimple(
AmqpSinkSettings.Create(ConnectionSettings)
.WithRoutingKey(QueueName)
.WithDeclarations(exchangeDeclaration, queueDeclaration, bindingDeclaration));
//run sink
Source.From(new string[] { jsonMessage }).Select(ByteString.FromString).RunWith(amqpSink, Materializer).Wait();
}
//Extra Info below
//**********Class constructor
private readonly IAMQPSettings _ampqSettings;
private readonly Akka.Actor.ActorSystem System;
private readonly AmqpConnectionDetails ConnectionSettings;
private readonly ActorMaterializer Materializer;
private readonly string QueueName;
public EventBus(Akka.Actor.ActorSystem system, IAMQPSettings ampqSettings)
{
_ampqSettings = ampqSettings;
System = system;
ConnectionSettings = AmqpConnectionDetails.Create(ampqSettings.Host, ampqSettings.Port)
.WithCredentials(AmqpCredentials.Create(ampqSettings.UserName, ampqSettings.Password))
.WithAutomaticRecoveryEnabled(true)
.WithNetworkRecoveryInterval(TimeSpan.FromSeconds(1));
Materializer = ActorMaterializer.Create(System);
QueueName = ampqSettings.QueueName;
}
//SubMessage structure
public class SubMessage
{
public SubMessage(string message, Dictionary<string, object> properties = null, string routingKey = null, string exchangeName = null)
{
ExchangeName = exchangeName;
Message = message;
Properties = properties;
RoutingKey = routingKey;
}
public string Message { get; private set; }
public Dictionary<string, object> Properties { get; private set; }
public string RoutingKey { get; private set; }
public string ExchangeName { get; private set; }
}
Actual behaviour: I get the QueueName which is "Tax_Queue"
Expected behaviour : I am expecting to get the QueueName which is my class e.g MyTestClass RoutingKey.
I found the issue:
code says .WithRoutingKey(QueueName) instead of WithRoutingKey(routingKey)
I'm working on my project but I can't go on. My project should generate two code parts and convert these to two hashes. Thats all working. But now, I'd like to print the values out in the browser.
Thant is my unfinished code:
The Model:
namespace myapplication.test.Backend.Models
{
public class CodeContainer
{
public string CodePartA { get; set; }
public string CodePartB { get; set; }
public string HashAB { get; set; }
public string HashBA { get; set; }
}
}
The Class where I generate my codes and hashes:
namespace myapplication.test.Backend.Utilities
{
public static class VerificationCodeUitillity
{
private static string GenerateHash(string input)
{
string hash = string.Empty;
using (MD5 md5Hash = MD5.Create())
{
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
hash = sBuilder.ToString();
}
return hash;
}
private static string GenerateCodePart(int lenght)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random code = new Random();
return new string(Enumerable.Repeat(chars, lenght).Select(s => s[code.Next(s.Length)]).ToArray());
}
public static CodeContainer GeneratePVCode()
{
CodeContainer result = new CodeContainer();
result.CodePartA = GenerateCodePart(4);
result.CodePartB = GenerateCodePart(4);
result.HashAB = GenerateHash(result.CodePartA + result.CodePartB);
result.HashBA = GenerateHash(result.CodePartB + result.CodePartA);
return result;
}
}
}
And here in my Demo Controller I'd like to return the values CodePartA, CodePartB, HashAB and HashBA.
// GET api/demo/code
[HttpGet]
[Route("code")]
public string Code()
{
//return values here
}
Thanks for your help in advance!!
Cheers
Like that it should work:
// GET api/demo/code
[HttpGet]
[Route("code")]
public CodeContainer PVCodeGen()
{
return VerificationCodeUitillity.GeneratePVCode();
}
You should return the IHttpActionResult Interface in api-methods.
// GET api/demo/code
[HttpGet]
[Route("code")]
public IHttpActionResult PVCodeGen()
{
return this.Ok<CodeContainer>(VerificationCodeUitillity.GeneratePVCode());
}
Is it possible to make JavaScriptSerializer also populate properties without a setter? For example, a property like test.ID in the code below:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace JavaScriptConverterTest
{
class Program
{
static void Main(string[] args)
{
List<test> list = new List<test>();
for (int i = 0; i < 2; i++)
{
list.Add(new test(Guid.NewGuid(), "Item #" + i));
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
string jsonString = serializer.Serialize(list);
List<test> newList = serializer.Deserialize<List<test>>(jsonString);
Console.Read();
}
}
class test
{
private Guid id = Guid.Empty;
public Guid ID
{
get { return id; }
// Without a setter, JavaScriptSerializer doesn't populate this property.
// set { id = value; }
}
public string name = "";
public test()
{
}
public test(Guid id, string name)
{
this.id = id;
this.name = name;
}
}
}
You can use DataContractJsonSerializer which is built in .NET Framework and has its home at System.Runtime.Serialization.Json. You just need to decorate your field with DataMemberAttribute. Let's say you have this class:
class Foo
{
private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
After decorating:
[DataContract]
class Foo
{
[DataMember] private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
And testing:
private static void Main(string[] args)
{
var foo = new Foo("boo");
var serializer = new DataContractJsonSerializer(typeof(Foo));
string str;
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, foo);
str = Encoding.Default.GetString(stream.ToArray());
}
Console.WriteLine(str);
Foo loadedFoo;
using (var stream = new MemoryStream(Encoding.Default.GetBytes(str)))
{
loadedFoo = serializer.ReadObject(stream) as Foo;
}
Console.WriteLine(loadedFoo.Boo);
Console.ReadLine();
}
The loadedFoo that is constructed from the json string gets "boo" as value for _boo field.