Custom data visualizers for the Visual Studio debugger (.NET)
Applies to: Visual Studio Visual Studio for Mac Visual Studio Code
A visualizer is part of the Visual Studio debugger user interface that displays a variable or object in a manner appropriate to its data type. For example, a bitmap visualizer interprets a bitmap structure and displays the graphic it represents. Some visualizers let you modify as well as view the data. In the debugger, a visualizer is represented by a magnifying glass icon . You can select the icon in a DataTip, debugger Watch window, or QuickWatch dialog box, and then select the appropriate visualizer for the corresponding object.
In addition to the standard built-in visualizers, more visualizers may be available for download from Microsoft, third parties, and the community. You can also write your own visualizers and install them in the Visual Studio debugger.
This article provides a high-level overview of visualizer creation. For detailed instructions, see the following articles instead:
- Walkthrough: Write a visualizer in C#
- Walkthrough: Write a visualizer in Visual Basic
- Install a visualizer
- In the Natvis documentation, see the UIVisualizer element. Also, see the SQLite native Debugger Visualizer sample.
Custom visualizers are not supported for UWP and Windows 8.x apps.
The architecture of a debugger visualizer has two parts:
The debugger side runs within the Visual Studio debugger, and creates and displays the visualizer user interface.
Because Visual Studio executes on the .NET Framework Runtime, this component has to be written for .NET Framework. For this reason, it is not possible to write it for .NET Core.
The debuggee side runs within the process Visual Studio is debugging (the debuggee). The data object to visualize (for example, a String object) exists in the debuggee process. The debuggee side sends the object to the debugger side, which displays it in the user interface you create.
The runtime for which you build this component should match the one in which the debuggee process will run, that is, either .NET Framework or .NET Core.
The debugger side receives the data object from an object provider that implements the IVisualizerObjectProvider interface. The debuggee side sends the object through the object source, which is derived from VisualizerObjectSource.
The object provider can also send data back to the object source, which lets you write a visualizer that can edit data. You override the object provider to talk to the expression evaluator and the object source.
You can write a visualizer for a generic type only if the type is an open type. This restriction is the same as the restriction when using the
DebuggerTypeProxy attribute. For details, see Use the DebuggerTypeProxy attribute.
Custom visualizers may have security considerations. See Visualizer security considerations.
Create the debugger side user interface
To create the visualizer user interface on the debugger side, you create a class that inherits from DialogDebuggerVisualizer, and override the Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer.Show method to display the interface. You can use IDialogVisualizerService to display Windows forms, dialogs, and controls in your visualizer.
Use IVisualizerObjectProvider methods to get the visualized object on the debugger side.
Create a class that inherits from DialogDebuggerVisualizer.
Override the Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer.Show method to display your interface. Use IDialogVisualizerService methods to display Windows forms, dialogs, and controls in your interface.
Special debugger side considerations for .NET 5.0+
Custom Visualizers transfer data between the debuggee and debugger sides through binary serialization using the BinaryFormatter class by default. However, that kind of serialization is being curtailed in .NET 5 and above due to security concerns regarding its unfixible vulnerabilities. Moreover, it has been marked completely obsolete in ASP.NET Core 5 and its usage will throw as described in the ASP.NET Core Documentation. This section describes the steps you should take to make sure your visualizer is still supported in this scenario.
For compatibility reasons, the Show method that was overridden in the preceding section still takes in an IVisualizerObjectProvider. However, starting in Visual Studio 2019 version 16.10, it is actually of type IVisualizerObjectProvider2. For this reason, cast the
objectProviderobject to the updated interface.
When sending objects, like commands or data, to the debuggee-side use the
IVisualizerObjectProvider2.Serializemethod to pass it to a stream, it will determine the best serialization format to use based on the runtime of the debuggee process. Then, pass the stream to the
If the debuggee-side visualizer component needs to return anything to the debugger-side, it will be located in the Stream object returned by the TransferData method. Use the
IVisualizerObjectProvider2.GetDeserializableObjectFrommethod to get an IDeserializableObject instance from it and process it as required.
Please refer to the Special debuggee side considerations for .NET 5.0+ section to learn what other changes are required on the debuggee-side when using Binary Serialization is not supported.
If you would like more information on the issue, see the BinaryFormatter security guide.
Create the visualizer object source for the debuggee side
In the debugger side code, edit the DebuggerVisualizerAttribute, giving it the type to visualize (the debuggee-side object source) (VisualizerObjectSource). The
Target property sets the object source. If you omit the object source, the visualizer will use a default object source.
The debuggee side code contains the object source that gets visualized. The data object can override methods of VisualizerObjectSource. A debuggee side DLL is necessary if you want to create a standalone visualizer.
In the debuggee-side code:
To let the visualizer edit data objects, the object source must inherit from VisualizerObjectSource and override the
If you need to support multi-targeting in your visualizer, you can use the following Target Framework Monikers (TFMs) in the debuggee-side project file.
These are the only supported TFMs.
Special debuggee side considerations for .NET 5.0+
Additional steps might be needed for a visualizer to work starting in .NET 5.0 due to security concerns regarding the underlying binary serialization method used by default. Please read this section before continuing.
If the visualizer implements the TransferData method, use the newly added GetDeserializableObject method that is available in the latest version of
VisualizerObjectSource. The IDeserializableObject it returns helps to determine the object's serialization format (binary or JSON) and to deserialize the underlying object so that it may be used.
If the debuggee-side returns data to the debugger-side as part of the
TransferDatacall, serialize the response to the debugger-side's stream via the Serialize method.