I have this class:
[Serializable]
public class ServerResponse
{
public string[] Response { get; set; }
public object Packet { get; set; }
public ServerResponse(string[] response, object packet){
this.Response = response;
this.Packet = packet;
}
public string[] getResponse() { return this.Response; }
public object getPacket() { return this.Packet; }
}
And use the following to convert to JSON:
static void writeToClient(TcpClient client, object message)
{
string json = JsonConvert.SerializeObject(message);
NetworkStream clientStream = client.GetStream();
byte[] buffer = NetworkHelper.GetMessageAsBytes(json);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
However, the Packet is never serialized. Can anyone see what I'm doing wrong? Sample output:
{"Response":["message","Authenticated"],"Packet":{}}
And this is the actual class I'm attempting to serialize:
[Serializable]
public class ActiveGameSession
{
private LoginServerSettings serverSettings;
private List<UserCharacter> sessionCharacters = new List<UserCharacter>();
private UserAccount sessionAccount;
public ActiveGameSession()
{
this.sessionCharacters = new List<UserCharacter>();
this.sessionAccount = null;
this.serverSettings = null;
}
public ActiveGameSession(List<UserCharacter> chars, UserAccount session)
{
this.sessionCharacters = chars;
this.sessionAccount = session;
}
#region setters
public void setCharacters(List<UserCharacter> chars)
{
this.sessionCharacters = chars;
}
public void setSession(UserAccount session)
{
this.sessionAccount = session;
}
public void setServerSettings(LoginServerSettings settings)
{
this.serverSettings = settings;
}
#endregion
#region getters
public List<UserCharacter> getCharacters()
{
return this.sessionCharacters;
}
public UserAccount getAccount()
{
return this.sessionAccount;
}
public LoginServerSettings getSettings()
{
return this.serverSettings;
}
#endregion
}
JSON.NET may not support serialization of an object of type Object. Try using a more concrete type. If you want to have multiple packet types you can try using generics or derive from a common base class.
Edit:
Also there are no public properties of ActiveGameSession to be deserialized, please note that the getXXX, setXXX methods is not recognized as properties.
You need to cast the object representing the Packet to a type that JSON.NET can serialize. Try casting to a string and try again.
Related
I have the following class serialized into a file using BinaryFormatter:
[Serializable]
public class TestClass
{
public String ItemTwo { get; set; }
public String ItemOne { get; set; }
}
Using this code:
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, new TestClass{ItemOne = "ItemOne", ItemTwo = "ItemTwo"});
fs.Close();
When deserializing using this code:
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();
TestClass addresses = (TestClass)formatter.Deserialize(fs);
fs.Close();
I get everything normally.
However, now I need the class to have some backing fields like so:
[Serializable]
public class TestClass
{
private string _itemTwo;
private string _itemOne;
public String ItemTwo
{
get { return _itemTwo; }
set { _itemTwo = value; }
}
public String ItemOne
{
get { return _itemOne; }
set { _itemOne = value; }
}
}
My problem is that now, for some reason, deserialization from previous version doesn't work anymore. I get the class but the Properties are left null.
I cannot affect the serialization process, or the former class state.
How can I get the file to deserialize to the current class?
If you try to serialize the first version of TestClass the backfields will be serialized automatically by the binary formatter. Auto properties are only syntactic sugar, the compiler transform them in normal properties with backing fields. If you decompile your original console application (or class library) with ILSpy for example you'll see that your private fields are declared as:
.field private string '<ItemOne>k__BackingField'
which is way different from your second declaration with backing fields which yields to:
.field private string _itemOne
An approach would be declaring the ISerializable interface on your TestClass and get the value of the original properties using the information contained in the class SerializationInfo
[Serializable]
public class TestClass : ISerializable
{
private string _itemTwo;
private string _itemOne;
public String ItemTwo
{
get { return _itemTwo; }
set { _itemTwo = value; }
}
public String ItemOne
{
get { return _itemOne; }
set { _itemOne = value; }
}
protected TestClass(SerializationInfo info, StreamingContext context)
{
_itemTwo = info.GetString("<ItemTwo>k__BackingField");
_itemOne = info.GetString("<ItemOne>k__BackingField");
}
[SecurityPermissionAttribute(SecurityAction.Demand,
SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
//Add data to your serialization process here
}
}
so you tell the BinaryFormatter how you want your backing fields to be initialized during deserialization.
I have an object I would like to serialize into json in Unity to send to a service via REST call. In .NET I know you can easily ignore null properties.
[JsonProperty("some_model", NullValueHandling = NullValueHandling.Ignore)]
public class SomeModel
{
....
}
Is this possible using FullSerializer in Unity?
Currently I have
fsData data = null;
fsResult r = sm_Serializer.TrySerialize(objectToSerialize, out data);
string sendjson = data.ToString();
Is there a similar attribute I can add to the DataModel using FullSerializer?
[fsObject(ignoreNullProperties)]
public class SomeModel
{
....
}
Looks like one answer is custom converters.
private static fsSerializer sm_Serializer = new fsSerializer();
[fsObject(Converter = typeof(CustomConverter))]
public class SomeClass
{
string MyProp { get; set; }
}
public class CustomConverter : fsConverter
{
private static fsSerializer sm_Serializer = new fsSerializer();
public override bool CanProcess(Type type)
{
return type == typeof(SomeClass);
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
throw new NotImplementedException();
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
SomeClass someClass = (SomeClass)instance;
serialized = null;
Dictionary<string, fsData> serialization = new Dictionary<string, fsData>();
fsData tempData = null;
if (someClass.MyProp != null)
{
sm_Serializer.TrySerialize(someClass.MyProp, out tempData);
serialization.Add("myProp", tempData);
}
serialized = new fsData(serialization);
return fsResult.Success;
}
}
This works but any other suggestions are greatly appreciated!
I need to find a way to serialize a method call and it's associated parameter. This is because we'll be passing payloads onto a queue (like MSMQ) and then later on a process will pick up the message and need to deserialize the payload and call the method required.
Both sides of the queue use the same C# library, but one is inside a Web context and the other is inside a batch process / console app.
I have demonstrated below what I'd like to do, however, I realise it may not be possible. I know I could always encapsulate the meta data of what target method call and the have some huge switch statement that maps a parameter/payload to a method, however, it would be very cool and succinct if I could call any method I want (it doesn't matter whether it's static).
namespace SerializableMethodCalls
{
public class DTO
{
public string MyData { get; set; }
public int AnInteger { get; set; }
}
public class DTO2
{
public string MyData2 { get; set; }
public int AnInteger2 { get; set; }
}
class Program
{
private static Queue<string> _queue = new Queue<string>();
static void Main(string[] args)
{
DTO payload = new DTO
{
AnInteger = 45678,
MyData = "Test"
};
DTO2 payload2 = new DTO2
{
AnInteger2 = 534653,
MyData2 = "test2"
};
DoSomething(payload);
DoSomething(payload2);
_queue.Enqueue(Serialize(DoSomething, payload));
while (_queue.Count > 0)
{
var message = _queue.Dequeue();
DeserializeAndCallMethod(message);
}
}
private static void DeserializeAndCallMethod(string message)
{
// somehow deserialize the method invocation and then call the method with the serialized payload!
}
public static void DoSomething(DTO2 payload2)
{
Console.WriteLine("Done2! {0}, {1}", payload2.AnInteger2, payload2.MyData2);
}
public static void DoSomething(DTO dto)
{
Console.WriteLine("Done! {0}, {1}", dto.AnInteger, dto.MyData);
}
public static string Serialize(Method method, object parameter)
{
// somehow serialize a method call!?
}
}
}
I'd be interested in hearing your thoughts
Many thanks
Kris
Convert with the demonstrated From/To... methods between your DTOs and reflective objects:
class TypeDTO {
public string AssemblyName;
public string ClassName;
public static TypeDTO FromType(Type type) {
return new TypeDTO() {
AssemblyName = type.Assembly.FullName,
ClassName = type.FullName
};
}
public Type ToType() {
return ToType(AppDomain.CurrentDomain);
}
public Type ToType(AppDomain domain) {
Assembly assembly = domain.GetAssemblies().Where(t => t.FullName == AssemblyName).Single();
return assembly.GetType(ClassName);
}
}
class MethodSignatureDTO {
public TypeDTO DeclaringType;
public string MethodName;
public TypeDTO[] ParameterTypes;
public static MethodSignatureDTO FromMethod(MethodInfo method) {
return new MethodSignatureDTO() {
DeclaringType = TypeDTO.FromType(method.DeclaringType),
MethodName = method.Name,
ParameterTypes = method.GetParameters().Select(t => TypeDTO.FromType(t.ParameterType)).ToArray()
};
}
public MethodInfo ToMethod() {
return ToMethod(AppDomain.CurrentDomain);
}
public MethodInfo ToMethod(AppDomain domain) {
Type[] parameterTypes = ParameterTypes.Select(t => t.ToType(domain)).ToArray();
return DeclaringType.ToType(domain).GetMethod(MethodName, parameterTypes);
}
}
class MethodCallDTO {
public MethodSignatureDTO Method;
public object Instance;
public object[] Arguments;
public object Invoke() {
return Invoke(AppDomain.CurrentDomain);
}
public object Invoke(AppDomain domain) {
return Method.ToMethod(domain).Invoke(Instance, Arguments);
}
}
I'm trying to serialize a simple custom class that has private members, using protobuf-net library, for a windows store style app:
[ProtoContract]
class ProtoTest
{
[ProtoMember(1)]
string Test;
public ProtoTest(string test)
{
this.Test = test;
}
}
When I serialize an instance the private member is never serialized but is instead ignored. Making the member public resolves the problem but is not really a satisfactory solution for my application. Is there anything that I'm doing incorrectly here or does anybody know if this is a known bug (I did search but couldn't find anything)?
The sample in the protobuf-net wiki.
[ProtoContract]
public class StandaloneExtensible : IExtensible
{
[ProtoMember(1)]
public int KnownField { get; set; }
private byte[] buffer;
Stream IExtensible.BeginAppend() {
return Extensible.BeginAppend();
}
Stream IExtensible.BeginQuery() {
return Extensible.BeginQuery(buffer);
}
void IExtensible.EndAppend(Stream stream, bool commit) {
buffer = Extensible.EndAppend(buffer, stream, commit);
}
void IExtensible.EndQuery(Stream stream) {
Extensible.EndQuery(stream);
}
int IExtensible.GetLength() {
return Extensible.GetLength(buffer);
}
}
I have a List<object> with different types of objects in it like integers, strings, and custom types. All custom types are protobuf-adjusted.
What I wanna do now is to serialize / deserialize this list with protobuf.net. Up until now I suspect that I have to declare each and every type explicitly, which is unfortunately not possible with these mixed-list constructs. Because the binary formater has no problems to do these things I hope that I missed something and that you can help me out.
So my question is how to deal with objects in protobuf.net.
(disclosure: I'm the author of protobuf-net)
BinaryFormatter is a metadata-based serializer; i.e. it sends .NET type information about every object serialized. protobuf-net is a contract-based serializer (the binary equivalent of XmlSerializer / DataContractSerializer, which will also reject this).
There is no current mechanism for transporting arbitrary objects, since the other end will have no way of knowing what you are sending; however, if you have a known set of different object types you want to send, there may be options. There is also work in the pipeline to allow runtime-extensible schemas (rather than just attributes, which are fixed at build) - but this is far from complete.
This isn't ideal, but it works... it should be easier when I've completed the work to support runtime schemas:
using System;
using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
[ProtoInclude(10, typeof(DataItem<int>))]
[ProtoInclude(11, typeof(DataItem<string>))]
[ProtoInclude(12, typeof(DataItem<DateTime>))]
[ProtoInclude(13, typeof(DataItem<Foo>))]
abstract class DataItem {
public static DataItem<T> Create<T>(T value) {
return new DataItem<T>(value);
}
public object Value {
get { return ValueImpl; }
set { ValueImpl = value; }
}
protected abstract object ValueImpl {get;set;}
protected DataItem() { }
}
[ProtoContract]
sealed class DataItem<T> : DataItem {
public DataItem() { }
public DataItem(T value) { Value = value; }
[ProtoMember(1)]
public new T Value { get; set; }
protected override object ValueImpl {
get { return Value; }
set { Value = (T)value; }
}
}
[ProtoContract]
public class Foo {
[ProtoMember(1)]
public string Bar { get; set; }
public override string ToString() {
return "Foo with Bar=" + Bar;
}
}
static class Program {
static void Main() {
var items = new List<DataItem>();
items.Add(DataItem.Create(12345));
items.Add(DataItem.Create(DateTime.Today));
items.Add(DataItem.Create("abcde"));
items.Add(DataItem.Create(new Foo { Bar = "Marc" }));
items.Add(DataItem.Create(67890));
// serialize and deserialize
var clone = Serializer.DeepClone(items);
foreach (DataItem item in clone) {
Console.WriteLine(item.Value);
}
}
}
List<YourClass> list;
ProtoBuf.Serializer.Deserialize<List<YourClass>>(filestream);
There is a way of doing this, albeit not a very clean way, by using a wrapper object that utilises another serialisation mechanism that supports arbitrary objects. I am presenting an example below using JSON but, like I said, resorting to a different serialisation tool seems like defeating the purpose of using protobuf:
[DataContract]
public class ObjectWrapper
{
[DataMember(Order = 1)]
private readonly string _serialisedContent;
[DataMember(Order = 2)]
private readonly string _serialisedType;
public object Content { get; private set; }
[UsedImplicitly]
private ObjectWrapper() { }
public ObjectWrapper(object content)
{
_serialisedContent = JsonConvert.SerializeObject(content);
_serialisedType = content.GetType().FullName;
Content = content;
}
[ProtoAfterDeserialization]
private void Initialise()
{
var type = Type.GetType(_serialisedType);
Content = type != null
? JsonConvert.DeserializeObject(_serialisedContent, type)
: JsonConvert.DeserializeObject(_serialisedContent);
}
}
EDIT: This can also be done using C#'s built-in binary serialisation
[DataContract]
public class ObjectWrapper
{
[DataMember(Order = 1)]
private readonly string _serialisedContent;
public object Content { get; private set; }
[UsedImplicitly]
private ObjectWrapper() { }
public ObjectWrapper(object content)
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, content);
stream.Flush();
stream.Position = 0;
_serialisedContent = Convert.ToBase64String(stream.ToArray());
}
}
[ProtoAfterDeserialization]
private void Initialise()
{
var data = Convert.FromBase64String(source);
using (var stream = new MemoryStream(data))
{
var formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
}