C#命名管道首次连接正常,二次触发报System.ObjectDisposedException错误
问题根源
你把NamedPipeServerStream、StreamReader、StreamWriter都声明成了类的公共字段,第一次点击按钮执行完后,finally块里已经把这些对象全部释放了。第二次点击按钮时,你还是试图复用这些已经被Dispose的实例,自然就抛出ObjectDisposedException了。
修复方案
核心思路是每次点击按钮都创建全新的管道实例,不要复用已释放的对象,同时用更安全的异步写法和资源管理方式:
关键改动点
- 把管道相关变量从类级字段移到
server_named_pipe方法内部,每次调用都创建新实例 - 用
await pipeServer.WaitForConnectionAsync(stoppingToken)替代旧的Begin/End异步模式,避免回调里的资源引用问题 - 用
using语句自动管理对象生命周期,不用手动调用Dispose - 创建管道时直接传入权限设置,避免后续操作失效
修改后的完整代码
public string test = ""; // 按钮点击执行的方法 public void pipe_server() { var source = new CancellationTokenSource(); _ = server_named_pipe(source.Token); // 用_避免async void警告,可按需处理Task } protected async Task server_named_pipe(CancellationToken stoppingToken) { // 1. 配置管道安全权限 var pipeSecurity = new PipeSecurity(); var worldSid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null); var accessRule = new PipeAccessRule(worldSid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); pipeSecurity.AddAccessRule(accessRule); // 2. 每次调用创建新管道实例,using自动释放资源 using var pipeServer = new NamedPipeServerStream( "testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 20, 20, pipeSecurity); using var streamReader = new StreamReader(pipeServer); using var streamWriter = new StreamWriter(pipeServer); streamWriter.AutoFlush = true; // 自动刷新输出流 try { // 3. 异步等待连接,同时处理超时 var connectTask = pipeServer.WaitForConnectionAsync(stoppingToken); if (await Task.WhenAny(connectTask, Task.Delay(5000, stoppingToken)) == connectTask) { await connectTask; // 确认连接成功 // 4. 直接在流程内处理数据传输 await streamWriter.WriteLineAsync("Waiting"); await pipeServer.WaitForPipeDrainAsync(); test = await streamReader.ReadLineAsync(); using var logWriter = File.AppendText(CommonClass.error_path); await logWriter.WriteLineAsync($"Named_Pipe_message: {test} {DateTime.Now}"); } else { // 超时提示,可按需扩展 Console.WriteLine("连接超时"); } } catch (OperationCanceledException) { // 处理令牌取消的情况 } catch (Exception ex) { if (pipeServer.IsConnected) { await pipeServer.WaitForPipeDrainAsync(); pipeServer.Disconnect(); } // 可添加异常日志记录 } // using块自动释放所有资源,无需手动Dispose }
额外说明
- 原有的
PipeConnected回调被整合到异步流程中,避免了回调引用外部已释放资源的问题 - 用
Task.WhenAny实现超时等待,更符合async/await的异步编程范式 streamWriter.AutoFlush = true省去了每次写入后手动Flush的操作- 区分了取消令牌触发的异常,避免误判业务异常
内容的提问来源于stack exchange,提问作者Mdarende
相关产品推荐
相关产品推荐

