简体   繁体   中英

Serialize C# objects to a JSON to a server

I try to serialize C# objects to a JSON string and then send it over a network to a server. Yet the server never gets the obejcts. I tried to play with the settings of the JsonSerializer by setting the TypeNamehandling to Obejcts, but that didn't work too. I also don't like to convert the JSON-String to bytes and send it that way, because then I need to find some way to flush the NetworkStream I'm using and currently this Stream is always open.

I don't find any solution online. I hope someone here can help me. The whole code is uploaded to my GitHub!

My Client Code:

    public void Serialize(object value)
    {
        StreamWriter streamWriter = new StreamWriter(Stream);
        JsonWriter jsonWriter = new JsonTextWriter(streamWriter);
        jsonSerializer.Serialize(jsonWriter, value,typeof(Message));
    }

    public Message Deserialize()
    {
        StreamReader streamReader = new StreamReader(Stream);
        JsonReader jsonReader = new JsonTextReader(streamReader);
        return jsonSerializer.Deserialize<Message>(jsonReader);
    }

My Server Code

    public void Serialize(Stream stream, object value)
    {
        StreamWriter streamWriter = new StreamWriter(stream);
        JsonWriter jsonWriter = new JsonTextWriter(streamWriter);
        jsonSerializer.Serialize(jsonWriter, value,typeof(Message));
    }

    public Message Deserialize(Stream stream)
    {
        StreamReader streamReader = new StreamReader(stream);
        JsonReader jsonReader = new JsonTextReader(streamReader);
        return jsonSerializer.Deserialize<Message>(jsonReader);
    }

And a message object looks like this

[Serializable]
public class StartupMessage : Message
{
    public string Username { get; set; }

    public StartupMessage(string username)
    {
        Username = username ?? throw new ArgumentNullException(nameof(username));
    }
}

Edit : Some more code from my Client, which shows how and with what I send the objects:

 public string Username { get; }
    public string ServerIP { get; }
    //private readonly BinaryFormatter Formatter;
    private readonly JsonSerializer jsonSerializer;
    private readonly TcpClient Server;
    private readonly NetworkStream Stream;
    public event EventHandler<NewMessageEventArgs> NewMessage;

    public Client(string username, string serverIP)
    {
        Username = username ?? throw new ArgumentNullException(nameof(username));
        ServerIP = serverIP ?? throw new ArgumentNullException(nameof(serverIP));
        //Formatter = new BinaryFormatter();
        Server = new TcpClient(ServerIP, Message.Port);
        Stream = Server.GetStream();

        var settings = new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.Objects
        };
        jsonSerializer = JsonSerializer.Create(settings);
    }

    public void Start()
    {
        Serialize(new StartupMessage(Username));
        var recieverThread = new Thread(() =>
        {
            while (true)
            {
                Message msg = Deserialize();
                if(msg is ConnectedMessage)
                {
                    Console.WriteLine("Connected!");
                }
                if(msg is MessageMessage message)
                {
                    OnNewMessage(new NewMessageEventArgs(message.Message, message.Username));
                }
            }
        });
        recieverThread.Start();
    }

Edit 2 :

private readonly List<ClientInfo> clientInfos;
    //private readonly BinaryFormatter formatter;
    private readonly TcpListener tcpListener;
    private readonly JsonSerializer jsonSerializer;
    public EventHandler<NewMessageEventArgs> NewMessage;

    public Server()
    {
        clientInfos = new List<ClientInfo>();
        //formatter = new BinaryFormatter();
        tcpListener = new TcpListener(IPAddress.Any, Message.Port);
        var settings = new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.Objects
        };
        jsonSerializer = JsonSerializer.Create(settings);
    }

    public void Start()
    {
        while (true)
        {
            tcpListener.Start();
            TcpClient client = tcpListener.AcceptTcpClient();
            var recieverThread = new Thread(() =>
            {
                NetworkStream stream = client.GetStream();
                while (true)
                {

                    Message msg = Deserialize(stream);
                    if (msg is StartupMessage startup)
                    {
                        OnNewMessage(new NewMessageEventArgs("CONNECTED", startup.Username),true);
                        string username = startup.Username;
                        clientInfos.Add(new ClientInfo(username, stream));
                        Serialize(stream, new ConnectedMessage());
                    }
                    if (msg is MessageMessage message)
                    {
                        OnNewMessage(new NewMessageEventArgs(message.Message, message.Username),false);
                        foreach (ClientInfo info in clientInfos)
                        {
                            Serialize(info.Stream, message);
                        }
                    }
                }
            });
            recieverThread.Start();
        }
    }

Found the solution. The problem was, that my client never really sents the JSON data and my Server can't really recieve it, if the data was being sent.

The solution was rather simple. I just use an StreamWriter to sent the converted object. It's important that I use the WriteLine -function, since that adds the Environment.NewLine -mark at the end of the package showing the server that this is the end of the package!

public void Serialize(Stream stream, Message value)
    {
        using (StreamWriter streamWriter = new StreamWriter(stream))
        {
            string json = JsonConvert.SerializeObject(value);
            streamWriter.WriteLine(json);
        }
    }

For the recieving part I use the StreamReader with the function ReadLine . This function reads the stream used in the StreamReader until it sees the Environment.NewLine -mark.

        public Message Deserialize(Stream stream)
    {
        using (StreamReader streamReader = new StreamReader(stream, true))
        {
            JsonReader jsonReader = new JsonTextReader(streamReader);
            string json = streamReader.ReadLine();
            return JsonConvert.DeserializeObject<Message>(json);
        }
    }

The only problem with this is, that the JsonConvert.DeserializeObject -function won't deserialize abstract objects or interfaces. For this you can watch this post!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM