Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Visualisaties voor foutopsporingsprogramma's zijn een Visual Studio-functie die een aangepaste visualisatie biedt voor variabelen of objecten van een specifiek .NET-type tijdens een foutopsporingssessie.
Visuals voor foutopsporingsprogramma's zijn toegankelijk via de DataTip die wordt weergegeven wanneer u de muisaanwijzer boven een variabele beweegt, of in de vensters Auto's, Locals en Watch :
Get started
Volg de sectie Het extensieproject maken in de sectie Aan de slag.
Voeg vervolgens een klasse toe die wordt uitgebreid DebuggerVisualizerProvider en pas het VisualStudioContribution kenmerk hierop toe:
/// <summary>
/// Debugger visualizer provider class for <see cref="System.String"/>.
/// </summary>
[VisualStudioContribution]
internal class StringDebuggerVisualizerProvider : DebuggerVisualizerProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="StringDebuggerVisualizerProvider"/> class.
/// </summary>
/// <param name="extension">Extension instance.</param>
/// <param name="extensibility">Extensibility object.</param>
public StringDebuggerVisualizerProvider(StringDebuggerVisualizerExtension extension, VisualStudioExtensibility extensibility)
: base(extension, extensibility)
{
}
/// <inheritdoc/>
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My string visualizer", typeof(string));
/// <inheritdoc/>
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
string targetObjectValue = await visualizerTarget.ObjectSource.RequestDataAsync<string>(jsonSerializer: null, cancellationToken);
return new MyStringVisualizerControl(targetObjectValue);
}
}
De bovenstaande code definieert een nieuwe debugger-visualisator, die toegepast wordt op objecten van het type string:
- De
DebuggerVisualizerProviderConfigurationeigenschap definieert de weergavenaam van de visual en het ondersteunde .NET-type. - De
CreateVisualizerAsyncmethode wordt aangeroepen door Visual Studio wanneer de gebruiker de weergave van het foutopsporingsprogramma voor een bepaalde waarde aanvraagt.CreateVisualizerAsyncgebruikt hetVisualizerTargetobject om de waarde op te halen die moet worden gevisualiseerd en doorgegeven aan een aangepast extern gebruikersbeheer (raadpleeg de documentatie van de externe gebruikersinterface ). Het beheer van de remotegebruiker wordt vervolgens teruggegeven en zal worden weergegeven in een pop-upvenster in Visual Studio.
Meerdere typen instellen
Met de configuratie-eigenschap kan de visualizer zich richten op meerdere typen wanneer dit handig is. Een perfect voorbeeld hiervan is de DataSet Visualizer die ondersteuning biedt voor de visualisatie vanDataSet, DataTableen DataViewDataViewManager objecten. Deze mogelijkheid vereenvoudigt de ontwikkeling van extensies omdat vergelijkbare typen dezelfde gebruikersinterface kunnen delen, modellen kunnen weergeven en objectbron visualiseren.
/// <inheritdoc/>
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new DebuggerVisualizerProviderConfiguration(
new VisualizerTargetType("DataSet Visualizer", typeof(System.Data.DataSet)),
new VisualizerTargetType("DataTable Visualizer", typeof(System.Data.DataTable)),
new VisualizerTargetType("DataView Visualizer", typeof(System.Data.DataView)),
new VisualizerTargetType("DataViewManager Visualizer", typeof(System.Data.DataViewManager)));
/// <inheritdoc/>
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
...
}
De objectbron van de visualr
De visualizer-objectbron is een .NET-klasse die wordt geladen door het foutopsporingsprogramma in het te debuggen proces. De debugger-visualizer kan data ophalen uit de objectbron van de visualizer via methoden die door VisualizerTarget.ObjectSource worden blootgesteld.
Met de standaardvisualisatie-bron kunnen debugger-visualisaties de waarde van het object ophalen dat moet worden gevisualiseerd door de RequestDataAsync<T>(JsonSerializer?, CancellationToken) methode aan te roepen. De standaardvisualisatieobjectbron maakt gebruik van Newtonsoft.Json om de waarde te serialiseren en de VisualStudio.Extensibility-bibliotheken maken ook gebruik van Newtonsoft.Json voor de deserialisatie. U kunt ook RequestDataAsync(CancellationToken) gebruiken om de geserialiseerde waarde als een JToken op te halen.
Als u een .NET-type wilt visualiseren dat systeemeigen wordt ondersteund door Newtonsoft.Json, of als u uw eigen type wilt visualiseren en u het serializeerbaar wilt maken, zijn de vorige instructies voldoende om een eenvoudige foutopsporingsprogramma visualiseren te maken. Lees verder als u complexere typen wilt ondersteunen of meer geavanceerde functies wilt gebruiken.
Een aangepaste visualisatieobjectbron gebruiken
Als het type dat moet worden gevisualiseerd, niet automatisch kan worden geserialiseerd door Newtonsoft.Json, kunt u een aangepaste visualisatieobjectbron maken om de serialisatie te verwerken.
- Maak een nieuw .NET-klassebibliotheekproject gericht op
netstandard2.0. U kunt zich richten op een specifiekere versie van .NET Framework of .NET (bijvoorbeeldnet472ofnet6.0) als dat nodig is om het object te serialiseren dat moet worden gevisualiseerd. - Voeg een pakketreferentie toe aan
DebuggerVisualizersversie 17.6 of hoger. - Voeg een klasse toe die
VisualizerObjectSourceuitbreidt enGetDataoverschrijdt door de geserialiseerde waarde vantargetnaar deoutgoingDatastream te schrijven.
public class MyObjectSource : VisualizerObjectSource
{
/// <inheritdoc/>
public override void GetData(object target, Stream outgoingData)
{
MySerializableType result = Convert(match);
SerializeAsJson(outgoingData, result);
}
private static MySerializableType Convert(object target)
{
// Add your code here to convert target into a type serializable by Newtonsoft.Json
...
}
}
Aangepaste serialisatie gebruiken
U kunt de VisualizerObjectSource.SerializeAsJson methode gebruiken om een object te serialiseren met Newtonsoft.Json aan een object Stream zonder een verwijzing naar Newtonsoft.Json toe te voegen aan uw bibliotheek. Het aanroepen van SerializeAsJson zal via reflectie een versie van de Newtonsoft.Json-assembly in het proces dat wordt gedebugged laden.
Als u naar Newtonsoft.Json wilt verwijzen, moet u dezelfde versie gebruiken waarnaar wordt verwezen door het Microsoft.VisualStudio.Extensibility.Sdk pakket, maar het verdient de voorkeur om te gebruiken DataContract en DataMember kenmerken om objectserialisatie te ondersteunen in plaats van te vertrouwen op Newtonsoft.Json-typen.
U kunt ook uw eigen aangepaste serialisatie (zoals binaire serialisatie) rechtstreeks implementeren naar outgoingData.
Het DLL-bestand van de visualr-objectbron toevoegen aan de extensie
Wijzig het extensiebestand .csproj dat een ProjectReference aan het objectbronbibliotheekproject visualr toevoegt, waardoor de objectbronbibliotheek van de visualr wordt gebouwd voordat de extensie wordt verpakt.
Voeg ook een Content item toe, inclusief de visualizer-objectbronbibliotheek-DLL, in de submap van de netstandard2.0 van de extensie.
<ItemGroup>
<Content Include="pathToTheObjectSourceDllBinPath\$(Configuration)\netstandard2.0\MyObjectSourceLibrary.dll" Link="netstandard2.0\MyObjectSourceLibrary.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyObjectSourceLibrary\MyObjectSourceLibrary.csproj" />
</ItemGroup>
U kunt ook de net4.6.2 of netcoreapp submappen gebruiken als u de bronbibliotheek voor visualisatie hebt gebouwd die gericht is op .NET Framework of .NET. U kunt zelfs alle drie de submappen opnemen met verschillende versies van de bronbibliotheek van de visualizer, maar het is beter om alleen op netstandard2.0 te richten.
Probeer het aantal afhankelijkheden van de DLL van de visualizer-objectbronbibliotheek te minimaliseren. Als uw visualizer-objectbronbibliotheek andere afhankelijkheden heeft dan Microsoft.VisualStudio.DebuggerVisualizers en bibliotheken die al zijn geladen in het proces dat wordt ge-debugged, moet u deze DLL-bestanden ook opnemen in dezelfde submap als de DLL van de visualizer-objectbronbibliotheek.
De visualizerprovider voor de debugger bijwerken om de aangepaste visualizerobjectbron te gebruiken
Vervolgens kunt u uw DebuggerVisualizerProvider configuratie bijwerken om te verwijzen naar de bron van het aangepaste visualr-object:
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My visualizer", typeof(TypeToVisualize))
{
VisualizerObjectSourceType = new(typeof(MyObjectSource)),
};
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
MySerializableType result = await visualizerTarget.ObjectSource.RequestDataAsync<MySerializableType>(jsonSerializer: null, cancellationToken);
return new MyVisualizerUserControl(result);
}
Werken met grote en complexe objecten
Als het ophalen van gegevens uit de objectbron van de visualizer niet kan worden uitgevoerd met één aanroep RequestDataAsynczonder parameters, kunt u in plaats daarvan een complexere berichtuitwisseling uitvoeren met de objectbron visualizer door meerdere keren aan te RequestDataAsync<TMessage, TResponse>(TMessage, JsonSerializer?, CancellationToken) roepen en verschillende berichten naar de objectbron van de visualr te verzenden. Zowel het bericht als het antwoord wordt geserialiseerd door de VisualStudio.Extensibility-infrastructuur met behulp van Newtonsoft.Json. Met andere overschrijvingen van RequestDataAsync kunt u JToken objecten gebruiken of aangepaste serialisatie en deserialisatie implementeren.
U kunt elk aangepast protocol implementeren met behulp van verschillende berichten om informatie op te halen uit de objectbron van de visualizer. De meest voorkomende gebruiksscenario voor deze functie is het ophalen van een potentieel groot object in meerdere aanroepen om te voorkomen dat RequestDataAsync tijd overschrijdt.
Dit is een voorbeeld van hoe u de inhoud van een mogelijk grote verzameling één item tegelijk kunt ophalen:
for (int i = 0; ; i++)
{
MySerializableType? collectionEntry = await visualizerTarget.ObjectSource.RequestDataAsync<int, MySerializableType?>(i, jsonSerializer: null, cancellationToken);
if (collectionEntry is null)
{
break;
}
observableCollection.Add(collectionEntry);
}
De bovenstaande code gebruikt een eenvoudige index als bericht voor de RequestDataAsync aanroepen. De bijbehorende broncode van het visualrobject overschrijft de TransferData methode (in plaats van GetData):
public class MyCollectionTypeObjectSource : VisualizerObjectSource
{
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
var index = (int)DeserializeFromJson(incomingData, typeof(int))!;
if (target is MyCollectionType collection && index < collection.Count)
{
var result = Convert(collection[index]);
SerializeAsJson(outgoingData, result);
}
else
{
SerializeAsJson(outgoingData, null);
}
}
private static MySerializableType Convert(object target)
{
// Add your code here to convert target into a type serializable by Newtonsoft.Json
...
}
}
De bron van het visualisatieobject hierboven maakt gebruik van de VisualizerObjectSource.DeserializeFromJson methode om het bericht te deserialiseren dat door de visualizer-provider verzonden is.incomingData
Bij het implementeren van een debugger visualizer provider die complexe berichtinteractie uitvoert met de visualizer-objectbron, is het meestal beter om de VisualizerTarget door te geven aan de RemoteUserControl van de visualizer, zodat de berichtuitwisseling asynchroon kan plaatsvinden terwijl het besturingselement wordt geladen. Door het VisualizerTarget te passeren, kunt u berichten verzenden naar het visualizer-object om gegevens op te halen op basis van de interacties van de gebruiker met de gebruikersinterface van de visualizer.
public override Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyVisualizerUserControl(visualizerTarget));
}
internal class MyVisualizerUserControl : RemoteUserControl
{
private readonly VisualizerTarget visualizerTarget;
public MyVisualizerUserControl(VisualizerTarget visualizerTarget)
: base(new MyDataContext())
{
this.visualizerTarget = visualizerTarget;
}
public override async Task ControlLoadedAsync(CancellationToken cancellationToken)
{
// Start querying the VisualizerTarget here
...
}
...
Visualisatoren openen als hulpprogrammavensters
Standaard worden alle extensies voor het visualiseren van foutopsporingsprogramma's geopend als modale dialoogvensters op de voorgrond van Visual Studio. Als de gebruiker dus wil blijven communiceren met de IDE, moet de visualisatie worden gesloten. Als de Style eigenschap is ingesteld op ToolWindow in de DebuggerVisualizerProviderConfiguration eigenschap, wordt de visualizer geopend als een niet-modaal gereedschapsvenster dat tijdens de rest van de debugsessie open kan blijven. Als er geen stijl wordt gedeclareerd, wordt de standaardwaarde ModalDialog gebruikt.
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My visualizer", typeof(TypeToVisualize))
{
Style = VisualizerStyle.ToolWindow
};
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
// The control will be in charge of calling the RequestDataAsync method from the visualizer object source and disposing of the visualizer target.
return new MyVisualizerUserControl(visualizerTarget);
}
Wanneer een visualizer ervoor kiest om te worden geopend als een ToolWindow, moet het zich abonneren op de StateChanged-gebeurtenis van de VisualizerTarget. Wanneer een visualizer wordt geopend als een hulpprogrammavenster, kan de gebruiker de foutopsporingssessie hervatten zonder geblokkeerd te worden. De bovengenoemde gebeurtenis wordt dus geactiveerd door het foutopsporingsprogramma wanneer de status van het foutopsporingsdoel wordt gewijzigd. Auteurs van visualizer-extensies moeten speciale aandacht besteden aan deze meldingen, omdat het visualizerdoel alleen beschikbaar is wanneer de debugsessie actief is en het debugdoel gepauzeerd is. Wanneer het doel van de visualisatieroutine niet beschikbaar is, mislukken aanroepen naar ObjectSource methoden met een VisualizerTargetUnavailableException.
internal class MyVisualizerUserControl : RemoteUserControl
{
private readonly VisualizerDataContext dataContext;
#pragma warning disable CA2000 // Dispose objects before losing scope
public MyVisualizerUserControl(VisualizerTarget visualizerTarget)
: base(dataContext: new VisualizerDataContext(visualizerTarget))
#pragma warning restore CA2000 // Dispose objects before losing scope
{
this.dataContext = (VisualizerDataContext)this.DataContext!;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.dataContext.Dispose();
}
}
[DataContract]
private class VisualizerDataContext : NotifyPropertyChangedObject, IDisposable
{
private readonly VisualizerTarget visualizerTarget;
private MySerializableType? _value;
public VisualizerDataContext(VisualizerTarget visualizerTarget)
{
this.visualizerTarget = visualizerTarget;
visualizerTarget.StateChanged += this.OnStateChangedAsync;
}
[DataMember]
public MySerializableType? Value
{
get => this._value;
set => this.SetProperty(ref this._value, value);
}
public void Dispose()
{
this.visualizerTarget.Dispose();
}
private async Task OnStateChangedAsync(object? sender, VisualizerTargetStateNotification args)
{
switch (args)
{
case VisualizerTargetStateNotification.Available:
case VisualizerTargetStateNotification.ValueUpdated:
Value = await visualizerTarget.ObjectSource.RequestDataAsync<MySerializableType>(jsonSerializer: null, CancellationToken.None);
break;
case VisualizerTargetStateNotification.Unavailable:
Value = null;
break;
default:
throw new NotSupportedException("Unexpected visualizer target state notification");
}
}
}
}
De Available melding wordt ontvangen nadat de RemoteUserControl is gemaakt en net voordat deze zichtbaar wordt gemaakt in het nieuw gecreëerde visualisatietoolvenster. Zolang de visualisatie open blijft, kunnen de andere VisualizerTargetStateNotification waarden worden ontvangen telkens wanneer het doel voor foutopsporing de status wijzigt. De ValueUpdated melding wordt gebruikt om aan te geven dat de laatste expressie die door de visualizer is geopend, opnieuw is geëvalueerd waar het foutopsporingsprogramma is gestopt en moet worden vernieuwd door de gebruikersinterface. Aan de andere kant, wanneer het foutopsporingsdoel wordt hervat of de expressie niet opnieuw kan worden geëvalueerd nadat deze is gestopt, wordt de Unavailable melding ontvangen.
De gevisualiseerde objectwaarde bijwerken
Als VisualizerTarget.IsTargetReplaceable waar is, kan de debugger-visualizer de ReplaceTargetObjectAsync-methode gebruiken om de waarde van het gevisualiseerde object bij te werken in het gedebugde proces.
De objectbron van de visualizer moet de CreateReplacementObject methode overschrijven.
public override object CreateReplacementObject(object target, Stream incomingData)
{
// Use DeserializeFromJson to read from incomingData
// the new value of the object being visualized
...
return newValue;
}
Verwante inhoud
Probeer het RegexMatchDebugVisualizer voorbeeld uit om deze technieken in actie te zien.