我有一个简单的。NET 6 WinForms应用程序,它创建一个带有一个菜单项的系统托盘图标:退出。应用将派生一个异步任务来管理从Windows服务接收和记录消息的命名管道。如果用户单击Exit菜单项,事件处理程序将取消令牌,但是命名管道WaitForConnectionsAsync
调用无法识别取消。
我已经尝试了启动顺序的许多变化。在本例中,我认为命名管道线程可能需要configureAwait(false)
,但它仍然不起作用。散布在调试消息上的情况表明UI部分确实正确退出,并且令牌 * 被取消,但是命名管道类永远不会退出WaitForConnectionAsync
调用。
Program.cs
internal static class Program
{
private static SystemTrayApp trayApp = null;
private static CancellationTokenSource ctsMessageServer = new();
[STAThread]
static void Main()
=> MainAsync().GetAwaiter().GetResult();
static async Task MainAsync()
{
List<Task> tasks = new();
tasks.Add(Task.Run(() =>
{
ApplicationConfiguration.Initialize();
trayApp = new SystemTrayApp();
Application.Run(trayApp);
}));
tasks.Add(Task.Run(async Task () =>
{
await MessageServer.RunServer(ctsMessageServer.Token).configureAwait(false);
}));
await Task.WhenAll(tasks);
Environment.Exit(0);
}
public static void Exit()
{
ctsMessageServer.Cancel();
trayApp.Dispose();
Application.Exit();
}
}
MessageServer。cs(部分)
internal static class MessageServer
{
private static readonly string pipeServerName = "fubar";
private static readonly string separatorControlCode = "\u0014";
public static async Task RunServer(CancellationToken cancellationToken)
{
try
{
while(!cancellationToken.IsCancellationRequested)
{
using var server = new NamedPipeServerStream(pipeServerName, PipeDirection.In);
await server.WaitForConnectionAsync(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
// omitted the rest, never reaches the line above
// below: reading the data, disconnect, catch blocks, etc.
SystemTrayApp
中没有什么有趣的东西--它只是创建图标和菜单,Exit事件处理程序处理一些内部对象,然后调用上面所示的Program.Exit
。
对于MessageServer
类,我知道所有代码都是正确的,并且可以工作,我在许多其他项目(example)中使用过它,多年来我在许多场景中使用过async/await和取消令牌,包括复杂的多线程WPF应用程序。我假设图片中的WinForms有所不同。..
1条答案
按热度按时间cxfofazt1#
根据WaitForConnectionAsync上的备注:
使用取消令牌的取消请求仅在NamedPipeServerStream对象是使用PipeOptions的管道选项值创建的情况下才有效。Asynchronous或如果取消发生在调用WaitForConnectionAsync方法之前。
试试这个: