我在使用 DBus 时遇到问题。
我正在尝试使用一些操作按钮启动并运行通知气泡。
到目前为止,我已经能够让气泡显示出来
retValue = await proxy.NotifyAsync(
并获取在回调中按下的按钮,
await proxy.WatchActionInvokedAsync
请参阅下面的代码。
所以现在,因为在收到响应之前通知就返回了,所以我需要等待用户的响应(ManualResetEventSlim),然后才能关闭连接。
这造成了死锁,我通过切换到 AsyncManualResetEvent 解决了这个问题。
现在它可以工作了,有点 - 我得到了气泡,如果选择了气泡动作,我会得到响应(如果在超时之前单击 - 目前未处理超时),但我也得到了 WatchActionInvokedAsync 的 onError 回调中传递的异常.
错误回调:无法访问已处置的对象。对象名称:
'Tmds.DBus.Connection'
为什么我会收到此错误?在处理连接之前
不应该返回吗?
什么可能导致此错误?
除此之外,为什么异常有一个空的堆栈跟踪?await notifyResponseReceived.WaitAsync();
namespace NotificationTest
{
// https://devblogs.microsoft.com/pfxteam/building-async-coordination-primitives-part-1-asyncmanualresetevent/
public class AsyncManualResetEvent
{
private volatile System.Threading.Tasks.TaskCompletionSource<bool> m_tcs;
public AsyncManualResetEvent()
{
this.m_tcs = new System.Threading.Tasks.TaskCompletionSource<bool>();
}
public System.Threading.Tasks.Task WaitAsync()
{
return this.m_tcs.Task;
}
//public void Set()
//{
// this.m_tcs.TrySetResult(true);
//}
public void Set()
{
System.Threading.Tasks.TaskCompletionSource<bool> tcs = this.m_tcs;
System.Threading.Tasks.Task.Factory.StartNew(s => ((System.Threading.Tasks.TaskCompletionSource<bool>)s).TrySetResult(true),
tcs, System.Threading.CancellationToken.None, System.Threading.Tasks.TaskCreationOptions.PreferFairness, System.Threading.Tasks.TaskScheduler.Default);
tcs.Task.Wait();
}
public void Reset()
{
while (true)
{
System.Threading.Tasks.TaskCompletionSource<bool> tcs = this.m_tcs;
if (!tcs.Task.IsCompleted ||
System.Threading.Interlocked.CompareExchange(ref this.m_tcs, new System.Threading.Tasks.TaskCompletionSource<bool>(), tcs) == tcs)
return;
} // Whend
} // End Sub Reset
} // End Class AsyncManualResetEvent
class Program
{
// https://wiki.debianforum.de/Desktop-Notification_von_Systemservice_mittels_dbus
// https://cheesehead-techblog.blogspot.com/2009/02/five-ways-to-make-notification-pop-up.html
// https://wiki.debianforum.de/Desktop-Notification_von_Systemservice_mittels_dbus
// https://gist.github.com/ducin/6152106
// https://cweiske.de/tagebuch/DBus%20notify-send%20over%20network.htm
// dotnet dbus list services --bus system | grep NetworkManager org.freedesktop.NetworkManager
// dotnet dbus list objects --bus system --service org.freedesktop.NetworkManager
// dotnet dbus codegen --bus system --service org.freedesktop.NetworkManager
// cd ~/gitlab/Projects/NotificationTest/Tmds.DBus.Tool
// dotnet run codegen --bus system --service org.freedesktop.NetworkManager
// dotnet run codegen --bus session --service org.freedesktop.Notifications
private static async System.Threading.Tasks.Task<uint> SendNotification()
{
uint retValue = 666;
// System.Threading.ManualResetEventSlim notifyResponseReceived = new System.Threading.ManualResetEventSlim();
AsyncManualResetEvent notifyResponseReceived = new AsyncManualResetEvent();
Tmds.DBus.ObjectPath objectPath = new Tmds.DBus.ObjectPath("/org/freedesktop/Notifications");
string service = "org.freedesktop.Notifications";
using (Tmds.DBus.Connection connection = new Tmds.DBus.Connection(Tmds.DBus.Address.Session))
{
await connection.ConnectAsync();
Notifications.DBus.INotifications proxy = connection.CreateProxy<Notifications.DBus.INotifications>(service, objectPath);
// Task<IDisposable> WatchActionInvokedAsync(Action<(uint id, string actionKey)> handler, Action<Exception> onError = null);
await proxy.WatchActionInvokedAsync(
delegate ((uint id, string actionKey) id)
{
if (id.id != retValue)
{
System.Console.WriteLine("abort");
return;
}
System.Console.WriteLine("Dialog Id: {0}", id.id);
System.Console.WriteLine($"ActionKey: {id.actionKey}");
notifyResponseReceived.Set();
}, delegate (System.Exception ex)
{
System.Console.Write("Error callback: ");
System.Console.WriteLine(ex.Message);
System.Console.WriteLine(ex.StackTrace);
}
);
// string[] actions = new string[0];
string[] actions = new string[] { "0", "Cancel", "1", "No", "266789", "default", "3", "test" };
System.Collections.Generic.Dictionary<string, object> hints =
new System.Collections.Generic.Dictionary<string, object>();
string icon = "insert-image"; // # Siehe https://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html#names
icon = "call-start";
icon = "/root/Downloads/5d9ad698-8270-4141-b64e-736d3dbb9ecc.jpeg";
icon = "dialog-information";
icon = "dialog-error";
icon = "dialog-warning";
icon = "flag-ch";
// https://developer.gnome.org/notification-spec/
//await proxy.NotifyAsync("Notification", 0, icon, "summary", "body", actions, hints, 0);
retValue = await proxy.NotifyAsync("Notifica1tion", 0, icon, "This is the summary", "This is the body", actions, hints, 5000);
// notifyResponseReceived.Wait(); // blocks itselfs
await notifyResponseReceived.WaitAsync();
} // End Using connection
return retValue;
} // End Task SendNotification
static void Main(string[] args)
{
System.Console.Write("Notification ID: ");
System.Console.WriteLine(SendNotification().Result);
System.Console.ReadKey();
System.Console.WriteLine(" --- Press any key to continue --- ");
System.Console.ReadKey();
} // End Sub Main
} // End Class AsyncManualResetEvent
} // End Namespace NotificationTest
生成的代理对象(Notifications.DBus.INotifications)在这里:https ://pastebin.com/v40pyaFN以防万一有人想要它。
此代码使用Tmds.DBus 库。