0

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();
        }
    }
Honker
  • 1
  • 1
  • were you able to deserialize in the client itself? and wt exactly the error you face? also describe how are you sending the stream, is it via httppost body? – Krishna Chaitanya May 05 '20 at 11:23
  • What is `Stream` in the first two methods? Is it a network stream kept by the instance which hosts Serialize and Deserialize? If you can share the rest of your code (at least the parts to make a reproducible example) someone may be able to help – Oguz Ozgul May 05 '20 at 11:28
  • "Yet the server never gets the obejcts": Did you debug and see if the server gets any data? Does it fail while deserializing? – Oguz Ozgul May 05 '20 at 11:29
  • Firstly I fill the StartupMessage and send it using the Serialize-Function in the client. My Stream is from the type NetworkStream. When the server recieves the message, it shows a "Connected" in the console. Yet the "Connected" message never shows up. I thought the Serialize-function from the jsonSerializer sends it automaticly to the server via the stream. – Honker May 05 '20 at 11:29
  • I'm using Visual Studio 2017 Community, how can I debug and see if the server gets the message? – Honker May 05 '20 at 11:30
  • Is there some way to track the network traffic inside Visual Studio? – Honker May 05 '20 at 11:38
  • @OguzOzgul I added some more code of my client – Honker May 05 '20 at 11:50
  • If you serialize into a network stream, then yes, it will pump all the json data into the network stream. The network stream however should be a connected stream, which means you first connect to the server, get the network stream of the client socket and serialize into it. "Connected" is something else I think. Where do you call Server.Connect() ? – Oguz Ozgul May 05 '20 at 12:46
  • @OguzOzgul Added the server part too. I accept any incoming connection and create a new thread for each connection. In that threat I get the NetworkStream from the incoming connection – Honker May 05 '20 at 12:55
  • I am talking about the client-side. Where do you call Server.Connect() ? Do you ever connect to the server? – Oguz Ozgul May 05 '20 at 14:11
  • I don't call a Server.Connect(), but I create the TCPClient in the Constructor: `Server = new TcpClient(ServerIP, Message.Port);` This automaticly connects the client to the server! – Honker May 05 '20 at 14:15
  • Ok, I tried to debug the code and it seems that the client does not send a message into the NetworkStream – Honker May 05 '20 at 18:19

1 Answers1

0

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!

Honker
  • 1
  • 1