Сериализовать C# объектов в JSON на сервере - PullRequest
0 голосов
/ 05 мая 2020

Я пытаюсь сериализовать C# объектов в строку JSON, а затем отправить ее по сети на сервер. Тем не менее, сервер никогда не получает объекты. Я попытался поиграть с настройками JsonSerializer, установив для TypeNamehandling значение Obejcts, но это тоже не сработало. Мне также не нравится преобразовывать JSON -String в байты и отправлять их таким образом, потому что тогда мне нужно найти способ передать sh используемый мной NetworkStream, и в настоящее время этот поток всегда открыт.

Я не нашел решения в Интернете. Я надеюсь, что кто-то здесь может мне помочь. Весь код загружен на мой GitHub!

Код моего клиента:

    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);
    }

Код моего сервера

    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);
    }

И объект сообщения выглядит так

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

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

Edit : Еще немного кода от моего клиента, который показывает, как и с чем я отправляю объекты:

 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();
    }

Редактировать 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();
        }
    }

1 Ответ

0 голосов
/ 06 мая 2020

Нашел решение. Проблема заключалась в том, что мой клиент никогда не отправлял данные JSON, а мой Сервер не мог их получить, если данные были отправлены.

Решение было довольно простым. Я просто использую StreamWriter для отправки преобразованного объекта. Важно, чтобы я использовал функцию WriteLine, так как она добавляет метку Environment.NewLine в конце пакета, показывая серверу, что это конец пакета!

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

Для Получая часть, я использую StreamReader с функцией ReadLine. Эта функция считывает поток, используемый в StreamReader, пока не увидит отметку Environment.NewLine.

        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);
        }
    }

Единственная проблема с этим состоит в том, что JsonConvert.DeserializeObject -функция не будет десериализовать абстрактные объекты. или интерфейсы. Для этого вы можете посмотреть этот пост!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...