Необработанное исключение: System.ObjectDisposedException: Доступ к ликвидированному объекту невозможен
У меня есть клиент и сервер. Вот код клиента:
using System;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Windows.Forms;
using System.Json;
using System.Text.Json;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Lab3Client
{
public partial class Form1 : Form
{
private TcpClient client;
private StreamReader reader;
private StreamWriter writer;
private bool isConnected;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
client = new TcpClient();
client.Connect("127.0.0.1", 5555);
HandleCommunication();
}
private void HandleCommunication()
{
reader = new StreamReader(client.GetStream(), Encoding.ASCII);
writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
isConnected = true;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void AddWorker_Click(object sender, EventArgs e)
{
}
private void AddWorker_Click_1(object sender, EventArgs e)
{
Worker worker = new Worker(Name.Text, Position.Text, long.Parse(Salary.Text));
string workerData = JsonSerializer.Serialize(worker);
ServerRequest request = new ServerRequest
{
ActionType = 0,
Payload = workerData
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
}
catch (IOException)
{
}
}
}
private void ShowAll_Click(object sender, EventArgs e)
{
ServerRequest request = new ServerRequest
{
ActionType = 1,
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
string serverResponse = reader.ReadLine();
WorkersArray workers = JsonSerializer.Deserialize<WorkersArray>(serverResponse);
string output = "";
workers.Workers.ForEach(worker =>
{
output += worker.Name + " " + worker.Position + " " + worker.Salary + "\r\n";
});
SearchAllOutput.Text = output;
}
catch (IOException)
{
}
}
}
private void SearchByName_Click(object sender, EventArgs e)
{
ServerRequest request = new ServerRequest
{
ActionType = 2,
Payload = WorkerName.Text
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
string serverResponse = reader.ReadLine();
WorkersArray workers = JsonSerializer.Deserialize<WorkersArray>(serverResponse);
string output = "";
workers.Workers.ForEach(worker =>
{
output += worker.Name + " " + worker.Position + " " + worker.Salary + "\r\n";
});
SearchAllOutput.Text = output;
}
catch (IOException)
{
}
}
}
private void DeleteBtn_Click(object sender, EventArgs e)
{
ServerRequest request = new ServerRequest
{
ActionType = 3,
Payload = WorkerName.Text
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
string serverResponse = reader.ReadLine();
WorkersArray workers = JsonSerializer.Deserialize<WorkersArray>(serverResponse);
string output = "";
workers.Workers.ForEach(worker =>
{
output += worker.Name + " " + worker.Position + " " + worker.Salary + "\r\n";
});
SearchAllOutput.Text = output;
}
catch (IOException)
{
}
}
}
private void button2_Click(object sender, EventArgs e)
{
ServerRequest request = new ServerRequest
{
ActionType = 4,
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
string serverResponse = reader.ReadLine();
WorkersArray workers = JsonSerializer.Deserialize<WorkersArray>(serverResponse);
string output = "";
workers.Workers.ForEach(worker =>
{
output += worker.Name + " " + worker.Position + " " + worker.Salary + "\r\n";
});
SearchAllOutput.Text = output;
}
catch (IOException)
{
}
}
}
private void Edit_Click(object sender, EventArgs e)
{
Worker newWorker = new Worker(NewName.Text, NewPosition.Text, long.Parse(NewSalary.Text));
EditWorkerRequest editWorkerRequest = new EditWorkerRequest
{
NewWorker = newWorker,
OldName = OldName.Text
};
ServerRequest request = new ServerRequest
{
ActionType = 5,
Payload = JsonSerializer.Serialize(editWorkerRequest)
};
string data = JsonSerializer.Serialize(request);
if (isConnected)
{
try
{
writer.WriteLine(data);
writer.Flush();
string serverResponse = reader.ReadLine();
WorkersArray workers = JsonSerializer.Deserialize<WorkersArray>(serverResponse);
string output = "";
workers.Workers.ForEach(worker =>
{
output += worker.Name + " " + worker.Position + " " + worker.Salary + "\r\n";
});
SearchAllOutput.Text = output;
}
catch (IOException)
{
}
}
}
}
class Worker
{
public string Name { get; set; }
public string Position { get; set; }
public long Salary { get; set; }
public Worker(string name, string position, long salary)
{
Name = name;
Position = position;
Salary = salary;
}
}
class WorkersArray
{
public List<Worker> Workers { get; set; }
}
class ServerRequest
{
public int ActionType { get; set; }
public string Payload { get; set; }
}
class ServerResponse
{
public string Response { get; set; }
}
class EditWorkerRequest
{
public string OldName { get; set; }
public Worker NewWorker { get; set; }
}
}
Вот код сервера:
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Text.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
namespace Lab3Server
{
public partial class Form1 : Form
{
private bool isRunning;
private TcpListener tcpListener;
public Form1()
{
InitializeComponent();
}
private void InitializeTcp()
{
tcpListener = new TcpListener(IPAddress.Any, 5555);
tcpListener.Start();
isRunning = true;
LoopClients();
}
private void LoopClients()
{
while (isRunning)
{
TcpClient newClient = tcpListener.AcceptTcpClient();
Thread thread = new Thread(new ParameterizedThreadStart(HandleClient));
thread.Start(newClient);
}
}
private void HandleClient(object obj)
{
TcpClient client = (TcpClient)obj;
StreamWriter streamWriter = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader streamReader = new StreamReader(client.GetStream(), Encoding.ASCII);
bool isClientConnected = true;
string clientData = null;
while (isClientConnected)
{
clientData = streamReader.ReadLine();
Console.WriteLine("Data: " + clientData);
ServerRequest request = JsonSerializer.Deserialize<ServerRequest>(clientData);
if (request.ActionType == 0)
{
AddWorker(request.Payload);
} else if (request.ActionType == 1)
{
GetWorkers(client);
} else if (request.ActionType == 2)
{
SearchWorker(request.Payload, client);
} else if (request.ActionType == 3)
{
DeleteWorker(request.Payload, client);
} else if (request.ActionType == 4)
{
SortBySalary(client);
} else if (request.ActionType == 5)
{
EditWorker(request.Payload, client);
}
}
}
private void EditWorker(string payload, TcpClient client)
{
EditWorkerRequest request = JsonSerializer.Deserialize<EditWorkerRequest>(payload);
Worker newWorker = request.NewWorker;
string line;
List<Worker> workers = new List<Worker>();
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader reader = new StreamReader(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt");
while ((line = reader.ReadLine()) != null)
{
workers.Add(JsonSerializer.Deserialize<Worker>(line));
}
for (int i = 0; i < workers.Count; i++)
{
if (workers[i].Name.Equals(request.OldName))
{
workers[i] = newWorker;
}
}
WorkersArray arr = new WorkersArray()
{
Workers = workers
};
reader.Close();
writer.Write(JsonSerializer.Serialize(arr));
writer.Close();
}
private void SortBySalary(TcpClient client)
{
string line;
StreamReader reader = new StreamReader(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt");
List<Worker> workers = new List<Worker>();
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
while ((line = reader.ReadLine()) != null)
{
workers.Add(JsonSerializer.Deserialize<Worker>(line));
}
reader.Close();
IEnumerable<Worker> query = workers.OrderBy(worker => worker.Salary);
workers = query.ToList();
WorkersArray arr = new WorkersArray()
{
Workers = workers
};
reader.Close();
writer.Write(JsonSerializer.Serialize(arr));
writer.Close();
}
private void DeleteWorker(string name, TcpClient client)
{
string line;
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader reader = new StreamReader(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt");
List<Worker> workers = new List<Worker>();
while ((line = reader.ReadLine()) != null)
{
workers.Add(JsonSerializer.Deserialize<Worker>(line));
}
reader.Close();
workers = workers.FindAll(worker => !worker.Name.Equals(name));
WorkersArray arr = new WorkersArray()
{
Workers = workers
};
string workersStr = JsonSerializer.Serialize(arr);
writer.Write(workersStr);
writer.Flush();
File.WriteAllText(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt", workersStr);
}
private void SearchWorker(string payload, TcpClient client)
{
string line;
List<Worker> workers = new List<Worker>();
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader reader = new StreamReader(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt");
while ((line = reader.ReadLine()) != null)
{
workers.Add(JsonSerializer.Deserialize<Worker>(line));
}
workers = workers.FindAll(worker => worker.Name.Equals(payload));
WorkersArray arr = new WorkersArray()
{
Workers = workers
};
writer.Write(JsonSerializer.Serialize(arr));
writer.Close();
reader.Close();
}
private void GetWorkers(TcpClient client)
{
string line;
List<Worker> workers = new List<Worker>();
StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.ASCII);
StreamReader reader = new StreamReader(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt");
while ((line = reader.ReadLine()) != null)
{
workers.Add(JsonSerializer.Deserialize<Worker>(line));
}
WorkersArray arr = new WorkersArray()
{
Workers = workers
};
writer.Write(JsonSerializer.Serialize(arr));
writer.Close();
reader.Close();
}
private void AddWorker(string worker)
{
FileStream fileStream = new FileStream(@"E:\Лабы\7 сем\рис\Lab3\Lab3Server\text.txt", FileMode.OpenOrCreate, FileAccess.Write);
fileStream.Seek(0, SeekOrigin.End);
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine(worker);
streamWriter.Close();
fileStream.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
InitializeTcp();
}
}
class Worker
{
public string Name { get; set; }
public string Position { get; set; }
public long Salary { get; set; }
public Worker(string name, string position, long salary)
{
Name = name;
Position = position;
Salary = salary;
}
}
class ServerRequest
{
public int ActionType { get; set; }
public string Payload { get; set; }
}
class ServerResponse
{
public string Response { get; set; }
}
class WorkersArray
{
public List<Worker> Workers { get; set; }
}
class EditWorkerRequest
{
public string OldName { get; set; }
public Worker NewWorker { get; set; }
}
}
Когда я в клиенте нажимаю кнопку получить всех рабочих (GetWorkers в сервере), то срабатывает ObjectAlreadyDisposedException в методе HandleClient. До этого пробовал заменить во всех методах сервера writer.close на writer.flush, но в таком случае сервер отправлял данные, а клиент их почему-то не получал. Понимаю, что проблема в том, что я уничтожаю каким-то образом объект, но как по другому отправить данные клиенту не знаю. Буду благодарен любой помощи!
Ответы (1 шт):
StreamWriter и StreamWriter закрывают переданный им поток, как только уничтожаются. Так как вы вручную не уничтожаете (не вызываете .Dispose() для двух классов в этом методе, их уничтожает (финализирует) Garbage Collector, что вызывает закрытие потока TcpClient дважды, при этом второе закрытие подряд как раз и выдает то самое исключение. Нельзя закрыть уже закрытый поток.
Изучите, как надо правильно работать с классами, реализующими IDisposable.
Для удобства использования IDisposable есть ключевое слово using. Ниже приведенный код показывает, как это выглядит. Теперь объекты диспозятся в коде, а не где-то там сборщиком мусора, это правильно, так положено делать, чтобы код был предсказуемым.
Но как я вижу, именно в этом методе вам не нужно закрывать поток TcpClient, поэтому в конструкторы этих двух классов я передаю параметр leaveOpen = true, это сообщает StreamReader и StreamWriter, что они должны оставить переданный им поток открытым при уничтожении.
private void HandleClient(object obj)
{
using (TcpClient client = (TcpClient)obj)
using (StreamWriter streamWriter = new StreamWriter(client.GetStream(), Encoding.ASCII, leaveOpen: true))
using (StreamReader streamReader = new StreamReader(client.GetStream(), Encoding.ASCII, leaveOpen: true))
{
bool isClientConnected = true;
string clientData = null;
while (isClientConnected)
{
clientData = streamReader.ReadLine();
Console.WriteLine("Data: " + clientData);
ServerRequest request = JsonSerializer.Deserialize<ServerRequest>(clientData);
if (request.ActionType == 0)
{
AddWorker(request.Payload);
}
else if (request.ActionType == 1)
{
GetWorkers(client);
}
else if (request.ActionType == 2)
{
SearchWorker(request.Payload, client);
}
else if (request.ActionType == 3)
{
DeleteWorker(request.Payload, client);
}
else if (request.ActionType == 4)
{
SortBySalary(client);
}
else if (request.ActionType == 5)
{
EditWorker(request.Payload, client);
}
}
}
}
Реализуйте using во всех остальных частях когда, используйте leaveOpen, когда используемый поток не нужно закрывать, в вашем случае - везде, где используется client.GetStream(). Поток закроет тот using, который у TcpClient.
Схема такая:
Было
StreamReader sr = ...
// ваш код
sr.Close();
Стало
using (StreamReader sr = ...)
{
// ваш код
}
Так же внимательно перечитайте код, например в методе SortBySalary вы вызываете 2 раза reader.Close(), повторюсь - так не надо делать.