From 406a0f40676948a07a75c2d1dce823a66b2db319 Mon Sep 17 00:00:00 2001 From: Matthias Heil Date: Wed, 1 Apr 2026 15:47:54 +0200 Subject: [PATCH] Using static NamedPipeClient? PipeClient { get; set; } in Vector3DebuggerVisualizerProvider works. new VisualizerTargetType("Frame Array Visualizer", "Num.Roto.Visualization.Math.Geometry.Frame[] --- NamedPipes/NamedPipeClient.cs | 31 +++++++++++++------ NamedPipes/NamedPipeServer.cs | 26 +++++++++++++--- TestClient/Program.cs | 4 +-- TestServer/Program.cs | 6 ++-- .../Vector3DebuggerVisualizerProvider.cs | 25 ++++++++++++--- Vector3Visualizer/Vector3Visualizer.csproj | 8 +++-- Vector3VisualizerSource/Vector3Model.cs | 7 +++-- .../Vector3ObjectSource.cs | 17 +++------- Vector3VisualizerTest/Program.cs | 12 +++++++ .../Vector3VisualizerTest.csproj | 10 ++++++ .../Vector3VisualizerTest.slnx | 3 ++ VisualizerExtensionExample.slnx | 3 ++ 12 files changed, 111 insertions(+), 41 deletions(-) create mode 100644 Vector3VisualizerTest/Program.cs create mode 100644 Vector3VisualizerTest/Vector3VisualizerTest.csproj create mode 100644 Vector3VisualizerTest/Vector3VisualizerTest.slnx diff --git a/NamedPipes/NamedPipeClient.cs b/NamedPipes/NamedPipeClient.cs index 1982486..5aab100 100644 --- a/NamedPipes/NamedPipeClient.cs +++ b/NamedPipes/NamedPipeClient.cs @@ -9,7 +9,7 @@ namespace NamedPipes; public class NamedPipeClient (string pipeName,string? serverLocation = null, string? serverName = null,Action? logger = null): IDebugVisualizer, IDisposable { private bool IsConnected => PipeClient.State == PipeState.Connected; - private PipeClient PipeClient { get; }= new(new PipeSerializer(), pipeName); + private PipeClient PipeClient { get; } = new(new PipeSerializer(), pipeName); private string ServerLocation { get; } = serverLocation ?? Environment.GetEnvironmentVariable("USERPROFILE") + @"\Documents\Visual Studio 2026\Visualizers\Server\NrxVisualizer\"; private string ServerName { get; } = serverName ?? "Num.Roto.Nrx.VisualizerServer"; private Action Logger { get;} = logger ??((m) => Trace.WriteLine(m)); @@ -19,29 +19,40 @@ public class NamedPipeClient (string pipeName,string? serverLocation = null, st if (IsConnected) return; PipeClient.SetLogger((m) => Trace.WriteLine(m)); var serverAvailable = Process.GetProcessesByName(ServerName).Length > 0; + Logger($"Server available: {serverAvailable}"); if (!serverAvailable) { var serverPath = ServerLocation + ServerName + ".exe"; - if (!File.Exists(serverPath)) throw new FileNotFoundException(serverPath); + if (!File.Exists(serverPath)) throw new FileNotFoundException($"{nameof(StartServerAsync)}, Server does not exist, Path = {serverPath}"); var server = new Process { StartInfo = { FileName = serverPath } }; server.Start(); } - await PipeClient.ConnectAsync(); - } + try + { + await PipeClient.ConnectAsync().ConfigureAwait(true); + Logger("NamedPipeClient.StartServerAsync succeded."); + return; + } + catch(Exception e) + { + Logger(e.ToString()); + throw; + } + } public async Task SetDebugObjectAsync(DebugObject debugObject) { - await StartServerAsync(); - var result = PipeClient.InvokeAsync(server => server.SetDebugObjectAsync(debugObject)).Result; - Logger("NamedPipeClient.SetDebugObject: result = " + result); + await StartServerAsync().ConfigureAwait(true); + var result = await PipeClient.InvokeAsync(server => server.SetDebugObjectAsync(debugObject)); + Logger("NamedPipeClient.SetDebugObjectAsync: result = " + result); return result; } public async Task SetMessageAsync(string message) { - await StartServerAsync(); - var result = PipeClient.InvokeAsync(server => server.SetMessageAsync(message)).Result; - Logger("NamedPipeClient.SetMessage: result = " + result); + await StartServerAsync().ConfigureAwait(true); + var result = await PipeClient.InvokeAsync(server => server.SetMessageAsync(message)); + Logger("NamedPipeClient.SetMessageAsync: result = " + result); return result; } diff --git a/NamedPipes/NamedPipeServer.cs b/NamedPipes/NamedPipeServer.cs index 0cabc29..bb7ab14 100644 --- a/NamedPipes/NamedPipeServer.cs +++ b/NamedPipes/NamedPipeServer.cs @@ -7,6 +7,11 @@ using PipeMethodCalls; namespace NamedPipes; public partial class NamedPipesServer(string pipeName,Action? logger = null) : ObservableObject,IDebugVisualizer, IDisposable { + ~NamedPipesServer() + { + Logger(@"~NamedPipesServer called!"); + + } public bool IsConnected => PipeServer is { State: PipeState.Connected }; private PipeServer? PipeServer {get; set;} private string PipeName { get; } = pipeName; @@ -15,15 +20,28 @@ public partial class NamedPipesServer(string pipeName,Action? logger = n public async Task WaitForConnectionAsync() { if(IsConnected) return; - if (PipeServer == null || PipeServer.State == PipeState.Closed) + if (PipeServer == null || PipeServer.State != PipeState.Connected) { PipeServer?.Dispose(); PipeServer = new PipeServer(new PipeSerializer(), PipeName, () => this); PipeServer.SetLogger((m) => Trace.WriteLine(m)); - } - await PipeServer.WaitForConnectionAsync(); + } + Logger("Waiting for client connection..."); + await PipeServer.WaitForConnectionAsync().ConfigureAwait(true); + } + public async Task RunAsync() + { + while(true) + { + await WaitForConnectionAsync().ConfigureAwait(true); + Logger("Client connected."); + while (IsConnected) + { + await Task.Delay(100).ConfigureAwait(true); + } + Logger("Client disconnected."); + } } - [ObservableProperty] public partial DebugObject? DebugObject { get; private set; } diff --git a/TestClient/Program.cs b/TestClient/Program.cs index 12794ad..7f38bfa 100644 --- a/TestClient/Program.cs +++ b/TestClient/Program.cs @@ -4,8 +4,8 @@ var count = 0; var message = "Hello World!".ToCharArray(); while (true) { - var pipeClient = new NamedPipeClient("testPipe",@".\","TestServer"); - Thread.Sleep(100); + var pipeClient = new NamedPipeClient("testPipe",@".\","TestServer",logger:Console.WriteLine); + Thread.Sleep(1000); pipeClient.SetMessageAsync($"Hello from TestClient " + count++).GetAwaiter().GetResult(); pipeClient.SetDebugObjectAsync(new DebugObject{Type = typeof(string).FullName,Data = Encoding.GetEncoding("UTF-8").GetBytes(message)}).GetAwaiter().GetResult(); pipeClient.Dispose(); diff --git a/TestServer/Program.cs b/TestServer/Program.cs index 5dcb78e..bd9d7cb 100644 --- a/TestServer/Program.cs +++ b/TestServer/Program.cs @@ -1,7 +1,5 @@ using System; -using System.Threading; +var pipeServer = new NamedPipes.NamedPipesServer("testPipe",logger:Console.WriteLine); +await pipeServer.RunAsync().ConfigureAwait(true); -var pipeServer = new NamedPipes.NamedPipesServer("testPipe",Console.WriteLine); -pipeServer.WaitForConnectionAsync().GetAwaiter().GetResult(); -while (pipeServer.IsConnected) Thread.Sleep(100); diff --git a/Vector3Visualizer/Vector3DebuggerVisualizerProvider.cs b/Vector3Visualizer/Vector3DebuggerVisualizerProvider.cs index 285f465..a4e1bdf 100644 --- a/Vector3Visualizer/Vector3DebuggerVisualizerProvider.cs +++ b/Vector3Visualizer/Vector3DebuggerVisualizerProvider.cs @@ -1,11 +1,16 @@ using Microsoft.VisualStudio.Extensibility; using Microsoft.VisualStudio.Extensibility.DebuggerVisualizers; using Microsoft.VisualStudio.RpcContracts.RemoteUI; +using NamedPipes; +using System; +using System.Collections; using System.Collections.Generic; using System.Numerics; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Vector3VisualizerSource; + namespace Vector3Visualizer; [VisualStudioContribution] @@ -16,18 +21,30 @@ internal sealed class Vector3DebuggerVisualizerProvider : DebuggerVisualizerProv [ new VisualizerTargetType("Vector3 Visualizer", "System.Numerics.Vector3, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"), new VisualizerTargetType("Vector3[] Visualizer", typeof(Vector3[])), - new VisualizerTargetType("List Visualizer", typeof(List<>)), - new VisualizerTargetType("Quaternion Visualizer", typeof(Quaternion)) + new VisualizerTargetType("Quaternion Visualizer", typeof(Quaternion)), + new VisualizerTargetType("Frame Visualizer", "Num.Roto.Visualization.Math.Geometry.Frame, Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), + new VisualizerTargetType("Frame Array Visualizer", "Num.Roto.Visualization.Math.Geometry.Frame[], Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), + //not working + new VisualizerTargetType("Frame List Visualizer", "System.Collections.Generic.List, Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), ]) { VisualizerObjectSourceType = new VisualizerObjectSourceType(typeof(Vector3ObjectSource)), Style = VisualizerStyle.ToolWindow, }; + private static NamedPipeClient? PipeClient { get; set; } + private static void SendToVisualizer(Vector3Model? vector3Model) + { + if (vector3Model is null) return; + PipeClient ??= new NamedPipeClient("testPipe", serverName: @"TestServer", logger: (m) => Console.WriteLine(m)); + _ = PipeClient.SetMessageAsync($"Hello from {nameof(CreateVisualizerAsync)},vector3Model = {vector3Model.Vector3},{vector3Model.Quaternion}"); + } public override async Task CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken) { - Vector3Model? model = await visualizerTarget.ObjectSource.RequestDataAsync(jsonSerializer: null, CancellationToken.None); - return await Task.FromResult(new Vector3VisualizerUserControl(model)); + Vector3Model? model = await visualizerTarget.ObjectSource.RequestDataAsync(jsonSerializer: null, cancellationToken); + SendToVisualizer(model); + var control = new Vector3VisualizerUserControl(dataContext: model); + return await Task.FromResult(control); //return await Task.FromResult(new MyRemoteUserControl(model)); } } diff --git a/Vector3Visualizer/Vector3Visualizer.csproj b/Vector3Visualizer/Vector3Visualizer.csproj index 8c363a7..6a7a5ce 100644 --- a/Vector3Visualizer/Vector3Visualizer.csproj +++ b/Vector3Visualizer/Vector3Visualizer.csproj @@ -14,8 +14,12 @@ - - + + + + + + diff --git a/Vector3VisualizerSource/Vector3Model.cs b/Vector3VisualizerSource/Vector3Model.cs index 624a1fb..cf26549 100644 --- a/Vector3VisualizerSource/Vector3Model.cs +++ b/Vector3VisualizerSource/Vector3Model.cs @@ -1,12 +1,13 @@ -using System.Runtime.Serialization; +using System.Numerics; +using System.Runtime.Serialization; namespace Vector3VisualizerSource; [DataContract] public class Vector3Model { [DataMember] - public string Vector3 { get; set; } = "Null"; + public Vector3? Vector3 { get; set; } [DataMember] - public string Quaternion { get; set; } = "Null"; + public Quaternion? Quaternion { get; set;} } diff --git a/Vector3VisualizerSource/Vector3ObjectSource.cs b/Vector3VisualizerSource/Vector3ObjectSource.cs index d8313a7..365c05a 100644 --- a/Vector3VisualizerSource/Vector3ObjectSource.cs +++ b/Vector3VisualizerSource/Vector3ObjectSource.cs @@ -1,42 +1,35 @@ using Microsoft.VisualStudio.DebuggerVisualizers; using NamedPipes; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; - namespace Vector3VisualizerSource; public class Vector3ObjectSource : VisualizerObjectSource { - private static NamedPipeClient? PipeClient { get; set; } - private static void Send(Vector3Model vector3Model) - { - PipeClient ??= new NamedPipeClient("testPipe"); - PipeClient.SetMessageAsync($"Hello from {nameof(Vector3ObjectSource)}").GetAwaiter().GetResult(); - } public Vector3ObjectSource() { Debug.WriteLine("new Vector3ObjectSource"); } public override void GetData(object target, Stream outgoingData) { + Debug.WriteLine("GetData: objectType is: " + target.GetType().FullName); Vector3Model vector3Model = new(); switch (target) { case Vector3 vector3: - vector3Model.Vector3 = vector3.ToString(); + vector3Model.Vector3 = vector3; break; case IEnumerable vector3List: - vector3Model.Vector3 = vector3List.Last().ToString(); + vector3Model.Vector3 = vector3List.Last(); break; case Quaternion quaternion: - vector3Model.Quaternion = quaternion.ToString(); + vector3Model.Quaternion = quaternion; break; } - - Send(vector3Model); SerializeAsJson(outgoingData, vector3Model); } } \ No newline at end of file diff --git a/Vector3VisualizerTest/Program.cs b/Vector3VisualizerTest/Program.cs new file mode 100644 index 0000000..af9639c --- /dev/null +++ b/Vector3VisualizerTest/Program.cs @@ -0,0 +1,12 @@ + +using System.Numerics; + +var a = new Vector3(1,2,3); +var typeName = a.GetType().AssemblyQualifiedName; + +var b = new Vector3(5, 6, 7); +Vector3[] v3Array = [a, b]; +List v3List = v3Array.ToList(); + +var quaternion = new Quaternion(1,2,3,4); +return; \ No newline at end of file diff --git a/Vector3VisualizerTest/Vector3VisualizerTest.csproj b/Vector3VisualizerTest/Vector3VisualizerTest.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/Vector3VisualizerTest/Vector3VisualizerTest.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/Vector3VisualizerTest/Vector3VisualizerTest.slnx b/Vector3VisualizerTest/Vector3VisualizerTest.slnx new file mode 100644 index 0000000..4a0b9ac --- /dev/null +++ b/Vector3VisualizerTest/Vector3VisualizerTest.slnx @@ -0,0 +1,3 @@ + + + diff --git a/VisualizerExtensionExample.slnx b/VisualizerExtensionExample.slnx index cb77de7..cb391a5 100644 --- a/VisualizerExtensionExample.slnx +++ b/VisualizerExtensionExample.slnx @@ -1,8 +1,11 @@ + + +