Skip to content

Commit b81783d

Browse files
committed
VisualDump 2.0
- You no longer need to call `DumpExtensions.EnableDumping()` to activate Dumping! (#4) - Fixed `IOException: The semaphore timeout period has expired` during some calls to DumpExtensions - `Visual Dump` initialization is much faster now! - Fixed Visual Studio 2019 installation exception (#2)
1 parent 6e2d64f commit b81783d

42 files changed

Lines changed: 1097 additions & 234 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

DumpExtensions/DumpExtensions.cs

Lines changed: 110 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.IO;
23
using System.Web;
34
using System.Data;
45
using System.Linq;
@@ -7,25 +8,67 @@
78
using System.Numerics;
89
using System.Reflection;
910
using System.Collections;
11+
using System.Diagnostics;
12+
using VisualDump.Helpers;
1013
using System.ComponentModel;
1114
using VisualDump.ExtraTypes;
1215
using VisualDump.HTMLClients;
1316
using VisualDump.HTMLProviders;
1417
using System.Collections.Generic;
1518
using System.Collections.Concurrent;
19+
using System.Text.RegularExpressions;
20+
using System.Runtime.CompilerServices;
1621
using VisualDump.HTMLProviders.DefaultProviders;
1722

1823
public static class DumpExtensions
1924
{
2025
#region Var
21-
public static bool Enabled { get; private set; }
22-
private static ConcurrentDictionary<Type, HTMLProvider> Providers { get; }
26+
public static bool Enabled
27+
{
28+
get => _enabled;
29+
private set
30+
{
31+
if (_enabled != value)
32+
{
33+
_enabled = value;
34+
CloseClient();
35+
}
36+
}
37+
}
38+
private static bool _enabled = true;
39+
40+
private static HTMLClient Client
41+
{
42+
get
43+
{
44+
if (_client is null && Enabled)
45+
{
46+
if (string.IsNullOrEmpty(ServerName))
47+
ServerName = GetDefaultServerName();
48+
_client = (HTMLClient)Activator.CreateInstance(HTMLClientType, ServerName);
49+
_client.WaitForConnection(MaxWaitTime);
50+
}
51+
return _client;
52+
}
53+
}
54+
private static HTMLClient _client;
55+
56+
private static Assembly EntryAssembly
57+
{
58+
get => _entryAssembly;
59+
set => _entryAssembly = _entryAssembly ?? value;
60+
}
61+
private static Assembly _entryAssembly;
2362

24-
private static HTMLClient Client;
2563
private static string ServerName { get; set; }
2664
private static Type HTMLClientType { get; set; } = typeof(PipeHTMLClient);
27-
65+
private static readonly Regex ProcessRegex = new Regex(@"(.+) - Microsoft Visual Studio", RegexOptions.IgnoreCase | RegexOptions.Compiled);
66+
private static readonly Regex ProcessInActionRegex = new Regex(@"(.+) \(.+\) - Microsoft Visual Studio", RegexOptions.IgnoreCase | RegexOptions.Compiled);
2867
private const int MaxWaitTime = 5000;
68+
69+
private static readonly object _sync = new object();
70+
71+
private static ConcurrentDictionary<Type, HTMLProvider> Providers { get; }
2972
#endregion
3073

3174
#region Init
@@ -63,42 +106,80 @@ static DumpExtensions()
63106
#endif
64107
[typeof(IEnumerable)] = new IEnumerableHTMLProvider()
65108
};
66-
HashSet<string> defaultAssemblies = new HashSet<string> { "mscorlib", "System", "System.Core", "System.Drawing", "System.Windows.Forms" };
67-
foreach (Type p in AppDomain.CurrentDomain.GetAssemblies().Where(x => !defaultAssemblies.Contains(x.GetName().Name)).SelectMany(x => x.GetExportedTypes().Where(y => IsHTMLProvider(y) && y.GetConstructors().Where(z => z.GetParameters().Length == 0).Count() == 1)))
109+
foreach (Type p in AppDomain.CurrentDomain.GetAssemblies()
110+
.Where(x => {
111+
string name = x.GetName().Name;
112+
return !name.StartsWith("System") && !name.StartsWith("Microsoft") && name != "mscorlib" && name != "netstandard";
113+
})
114+
.SelectMany(x => x.GetExportedTypes()
115+
.Where(y => typeof(HTMLProvider).IsAssignableFrom(y) && y.GetConstructor(Type.EmptyTypes) != null)))
68116
Register(p);
69117
}
70118
#endregion
71119

72120
#region Functions
121+
[MethodImpl(MethodImplOptions.NoInlining)]
73122
public static void EnableDumping()
74123
{
124+
EntryAssembly = Assembly.GetCallingAssembly();
75125
Enabled = true;
76-
SetServerName(string.IsNullOrEmpty(ServerName) ? Assembly.GetCallingAssembly().GetName().Name : ServerName);
77126
}
78-
public static void DisableDumping()
127+
public static void DisableDumping() => Enabled = false;
128+
129+
private static string GetDefaultServerName()
130+
{
131+
string asmName = (EntryAssembly ?? Assembly.GetEntryAssembly()).GetName().Name;
132+
Process activeDevenv = Process.GetProcesses().Where(x => x.ProcessName == "devenv").FirstOrDefault(x => x.EnumerateWindows().Select(WindowsInterop.GetWindowText).Where(title => !string.IsNullOrWhiteSpace(title)).Any(title => {
133+
Match m = ProcessInActionRegex.Match(title);
134+
m = m.Success ? m : ProcessRegex.Match(title);
135+
return m.Success && m.Groups[1].Value == asmName;
136+
}));
137+
if (activeDevenv is null)
138+
return asmName;
139+
string searchPattern = $"VisualDump-{activeDevenv.Id}";
140+
return Directory.EnumerateFiles(@"\\.\pipe\")
141+
.Select(Path.GetFileNameWithoutExtension)
142+
.Where(x => x.StartsWith(searchPattern))
143+
.FirstOrDefault() ?? asmName;
144+
}
145+
private static void CloseClient()
79146
{
80-
Enabled = false;
81-
Client?.Dispose();
147+
lock (_sync)
148+
{
149+
if (_client != null)
150+
{
151+
_client.Dispose();
152+
_client = null;
153+
}
154+
}
82155
}
83156

84-
public static T Dump<T>(this T Obj) => Dump(Obj, string.Empty, new object[0]);
85-
public static T Dump<T>(this T Obj, string Header) => Dump(Obj, Header, new object[0]);
86-
public static T Dump<T>(this T Obj, params object[] Args) => Dump(Obj, string.Empty, Args);
87-
public static T Dump<T>(this T Obj, string Header, params object[] Args)
157+
[MethodImpl(MethodImplOptions.NoInlining)]
158+
public static T Dump<T>(this T Obj) => Dump(Obj, string.Empty, new object[0], Assembly.GetCallingAssembly());
159+
[MethodImpl(MethodImplOptions.NoInlining)]
160+
public static T Dump<T>(this T Obj, string Header) => Dump(Obj, Header, new object[0], Assembly.GetCallingAssembly());
161+
[MethodImpl(MethodImplOptions.NoInlining)]
162+
public static T Dump<T>(this T Obj, params object[] Args) => Dump(Obj, string.Empty, Args, Assembly.GetCallingAssembly());
163+
[MethodImpl(MethodImplOptions.NoInlining)]
164+
public static T Dump<T>(this T Obj, string Header, params object[] Args) => Dump(Obj, Header, Args, Assembly.GetCallingAssembly());
165+
private static T Dump<T>(T Obj, string Header, object[] Args, Assembly EntryAssembly)
88166
{
89167
if (Enabled)
90168
{
91-
string html = GetProvider(Obj?.GetType()).ToHTML(Obj, Args);
169+
string html = GetProvider(Obj?.GetType()).ToHTML(Obj, new Stack<object>(), Args);
92170
if (!string.IsNullOrEmpty(Header))
93171
html = WrapWithHeader(html, Header);
94-
SendHTML(WrapWithWrapper(html));
172+
lock (_sync)
173+
{
174+
DumpExtensions.EntryAssembly = EntryAssembly;
175+
Client?.Send(WrapWithWrapper(html));
176+
}
95177
}
96178
return Obj;
97179
}
98180

99-
private static void SendHTML(string HTML) => Client?.Send(HTML);
100-
private static string WrapWithHeader(string HTML, string Header) => $"<div class='header-box'><div class='header'><h3>{HttpUtility.HtmlEncode(Header)}</h3></div>{HTML}</div>";
101181
private static string WrapWithWrapper(string HTML) => $"<div class='wrapper'>{HTML}</div>";
182+
private static string WrapWithHeader(string HTML, string Header) => $"<div class='header-box'><div class='header'><h3>{HttpUtility.HtmlEncode(Header)}</h3></div>{HTML}</div>";
102183

103184
internal static HTMLProvider GetProvider(Type T)
104185
{
@@ -143,37 +224,25 @@ internal static bool Register(HTMLProvider Provider, Type T)
143224
}
144225
return false;
145226
}
146-
private static bool IsHTMLProvider(Type T)
147-
{
148-
while (T.BaseType != null)
149-
if (T.BaseType == typeof(HTMLProvider))
150-
return true;
151-
else
152-
T = T.BaseType;
153-
return false;
154-
}
155-
private static void InitializeClient()
227+
228+
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
229+
public static void SetHTMLClient<TClient>() where TClient : HTMLClient, new()
156230
{
157-
Client?.Dispose();
158-
Client = (HTMLClient)Activator.CreateInstance(HTMLClientType, ServerName);
159-
Client.WaitForConnection(MaxWaitTime);
231+
HTMLClientType = typeof(TClient);
232+
CloseClient();
160233
}
161-
162234
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
163-
public static void SetHTMLClient(Type T)
235+
private static void SetHTMLClient(Type T)
164236
{
165-
Type tmp = T.BaseType;
166-
while (!(tmp is null) && tmp != typeof(HTMLClient))
167-
tmp = tmp.BaseType;
168-
HTMLClientType = tmp is null ? throw new NotSupportedException() : T;
169-
InitializeClient();
237+
HTMLClientType = typeof(HTMLClient).IsAssignableFrom(T) && T.GetConstructor(Type.EmptyTypes) != null ? T : throw new NotSupportedException();
238+
CloseClient();
170239
}
171240

172241
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
173242
public static void SetServerName(string ServerName)
174243
{
175-
DumpExtensions.ServerName = ServerName;
176-
InitializeClient();
244+
DumpExtensions.ServerName = string.IsNullOrEmpty(ServerName) ? throw new ArgumentException(nameof(ServerName)) : ServerName;
245+
CloseClient();
177246
}
178-
#endregion
247+
#endregion
179248
}

DumpExtensions/DumpExtensions.csproj

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
<RootNamespace>VisualDump</RootNamespace>
66
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
77
<Authors>Kir_Antipov</Authors>
8-
<Description>This library is paired with the VisualDump extension for VisualStudio.
9-
It allows you to view a visual dump of your objects during the debugging of the program in Visual Studio</Description>
8+
<Description>This library is paired with the VisualDump 2.0 extension for VisualStudio.
9+
It allows you to view a visual dump of your objects during the debugging of the program in Visual Studio 2017/2019</Description>
1010
<Copyright>Kir_Antipov © 2019 - DateTime.Now.Year</Copyright>
11-
<PackageTags>Visual Dump VisualDump Dumping</PackageTags>
12-
<PackageIconUrl>https://raw.githubusercontent.com/Kir-Antipov/VisualDump/master/logo.png</PackageIconUrl>
11+
<PackageTags>Visual Dump VisualDump Dumping LINQPad</PackageTags>
12+
<PackageIconUrl>https://raw.githubusercontent.com/Kir-Antipov/VisualDump/master/logo-64.png</PackageIconUrl>
1313
<PackageProjectUrl>https://github.com/Kir-Antipov/VisualDump</PackageProjectUrl>
1414
<RepositoryUrl>https://github.com/Kir-Antipov/VisualDump</RepositoryUrl>
15-
<Version>1.0.1</Version>
16-
<AssemblyVersion>1.0.1.0</AssemblyVersion>
15+
<Version>2.0.0</Version>
16+
<AssemblyVersion>2.0.0</AssemblyVersion>
17+
<LangVersion>7.3</LangVersion>
18+
<PackageLicenseUrl>GPL-3.0-only</PackageLicenseUrl>
19+
<FileVersion>2.0.0</FileVersion>
1720
</PropertyGroup>
1821

1922
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">

DumpExtensions/HTMLProviders/DefaultProviders/ArrayHTMLProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
using System;
22
using System.Data;
33
using System.Collections;
4+
using System.Collections.Generic;
45
using VisualDump.HTMLProviderArgs;
56

67
namespace VisualDump.HTMLProviders.DefaultProviders
78
{
89
public class ArrayHTMLProvider : HTMLProvider
910
{
10-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<Array>(Obj, arr =>
11+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<Array>(Obj, CallStack, (arr, s) =>
1112
{
1213
Type arrType = Obj.GetType();
1314
Type elType = arr.GetType().GetElementType();
@@ -48,9 +49,9 @@ public override string ToHTML(object Obj, params object[] Args) => ToHTML<Array>
4849
DataTableDumpStyle.CountFields |
4950
DataTableDumpStyle.ShowRowIndices |
5051
DataTableDumpStyle.ShowColumnNames;
51-
return GetProvider<DataTable>().ToHTML(table, arrType.Namespace.StartsWith("System") || elType.IsAnonymous() ? new DataTableArgs(style) : new DataTableArgs(style, fullType));
52+
return GetProvider<DataTable>().ToHTML(table, s, arrType.Namespace.StartsWith("System") || elType.IsAnonymous() ? new DataTableArgs(style) : new DataTableArgs(style, fullType));
5253
}
53-
return GetProvider<IEnumerable>().ToHTML(arr, Args);
54+
return GetProvider<IEnumerable>().ToHTML(arr, s, Args);
5455
});
5556
}
5657
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System.Reflection;
2+
using VisualDump.Helpers;
3+
using System.Collections.Generic;
24

35
namespace VisualDump.HTMLProviders.DefaultProviders
46
{
57
public class AssemblyHTMLProvider : HTMLProvider
68
{
79
#region Functions
8-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<Assembly>(Obj, a => GetProvider<string>().ToHTML(a.FullName));
10+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<Assembly>(Obj, CallStack, (a, s) => GetProvider<string>().ToHTML(a.FullName, s.CloneAndPush(a)));
911
#endregion
1012
}
1113
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
namespace VisualDump.HTMLProviders.DefaultProviders
1+
using System.Collections.Generic;
2+
3+
namespace VisualDump.HTMLProviders.DefaultProviders
24
{
35
public class BooleanHTMLProvider : HTMLProvider
46
{
5-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<bool>(Obj, x => $"<div class='keyword'>{(x ? "true" : "false")}</div>");
7+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<bool>(Obj, CallStack, (x, s) => $"<div class='keyword'>{(x ? "true" : "false")}</div>");
68
}
79
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System.Web;
2+
using System.Collections.Generic;
23

34
namespace VisualDump.HTMLProviders.DefaultProviders
45
{
56
public class CharHTMLProvider : HTMLProvider
67
{
7-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<char>(Obj, x => $"<div class='string'>'{HttpUtility.HtmlEncode(x)}'</div>");
8+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<char>(Obj, CallStack, (x, s) => $"<div class='string'>'{HttpUtility.HtmlEncode(x)}'</div>");
89
}
910
}

DumpExtensions/HTMLProviders/DefaultProviders/CyclicalReferenceHTMLProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using System;
22
using System.Text;
33
using VisualDump.ExtraTypes;
4+
using System.Collections.Generic;
45

56
namespace VisualDump.HTMLProviders.DefaultProviders
67
{
78
public class CyclicalReferenceHTMLProvider : HTMLProvider
89
{
9-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<CyclicalReference>(Obj, reference =>
10+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<CyclicalReference>(Obj, CallStack, (reference, stack) =>
1011
{
1112
Type t = reference.CyclicalObject.GetType();
1213
return new StringBuilder()

DumpExtensions/HTMLProviders/DefaultProviders/DataTableHTMLProvider.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
using System;
22
using System.Data;
33
using System.Text;
4+
using VisualDump.Helpers;
5+
using System.Collections.Generic;
46
using VisualDump.HTMLProviderArgs;
57

68
namespace VisualDump.HTMLProviders.DefaultProviders
79
{
810
public class DataTableHTMLProvider : HTMLProvider
911
{
10-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<DataTable, DataTableArgs>(Obj, Args, (table, a) =>
12+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<DataTable, DataTableArgs>(Obj, CallStack, Args, (table, stack, a) =>
1113
{
14+
Stack<object> newCallStack = stack.CloneAndPush(table);
1215
Type t = table.GetType();
1316
bool showRowIndex = a.Style.HasFlag(DataTableDumpStyle.ShowRowIndices);
1417
bool showColName = a.Style.HasFlag(DataTableDumpStyle.ShowColumnNames);
@@ -51,7 +54,7 @@ public override string ToHTML(object Obj, params object[] Args) => ToHTML<DataTa
5154
Append("<td class='name'>").Append(i).Append("</td>");
5255
DataRow row = table.Rows[i];
5356
for (int j = 0; j < table.Columns.Count; ++j)
54-
Append("<td class='value'>").Append(GetProvider(row[j]).ToHTML(row[j])).Append("</td>");
57+
Append("<td class='value'>").Append(GetProvider(row[j]).ToHTML(row[j], newCallStack)).Append("</td>");
5558
Append("</tr>");
5659
}
5760
Append("</tbody>")
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System;
2+
using System.Collections.Generic;
23

34
namespace VisualDump.HTMLProviders.DefaultProviders
45
{
56
public class DateTimeHTMLProvider : HTMLProvider
67
{
7-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<DateTime>(Obj, x => $"<div class='date'>{x}</div>");
8+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<DateTime>(Obj, CallStack, (x, s) => $"<div class='date'>{x}</div>");
89
}
910
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using System;
22
using System.Linq;
33
using System.Reflection;
4+
using System.Collections.Generic;
45

56
namespace VisualDump.HTMLProviders.DefaultProviders
67
{
78
public class EnumHTMLProvider : HTMLProvider
89
{
9-
public override string ToHTML(object Obj, params object[] Args) => ToHTML<Enum>(Obj, x => $"<div><span class='enum'>{x.GetType().Name}</span><span class='text'>.{x}</span> (<span class='number'>{x.GetType().GetMembers().OfType<FieldInfo>().FirstOrDefault(y => y.Name == "value__")?.GetValue(x) ?? 0}</span>)</div>");
10+
public override string ToHTML(object Obj, Stack<object> CallStack, params object[] Args) => ToHTML<Enum>(Obj, CallStack, (x, s) => $"<div><span class='enum'>{x.GetType().Name}</span><span class='text'>.{x}</span> (<span class='number'>{x.GetType().GetMembers().OfType<FieldInfo>().FirstOrDefault(y => y.Name == "value__")?.GetValue(x) ?? 0}</span>)</div>");
1011
}
1112
}

0 commit comments

Comments
 (0)