├── .github
└── workflows
│ └── dotnet-desktop.yml
├── .gitignore
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── DNSSpeedTester.csproj
├── DNSSpeedTester.sln
├── Helpers
├── NetworkDiagnostics.cs
├── RelayCommand.cs
└── ViewModelBase.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Models
├── DnsServer.cs
├── NetworkAdapter.cs
└── TestDomain.cs
├── README.MD
├── Services
├── DataPersistenceService.cs
├── DnsServerDto.cs
├── DnsSettingService.cs
├── DnsTestService.cs
└── IPAddressConverter.cs
├── ViewModels
└── MainViewModel.cs
└── global.json
/.github/workflows/dotnet-desktop.yml:
--------------------------------------------------------------------------------
1 | name: .NET Publish and Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*' # 当匹配 'v*.*.*' 格式的标签被推送时触发
7 | workflow_dispatch: # 允许手动触发
8 |
9 | jobs:
10 | build-and-release:
11 | name: Build and Release
12 | runs-on: windows-latest # 使用 Windows 环境
13 |
14 | permissions:
15 | contents: write # 需要写入权限来创建 Release 和上传构建产物
16 |
17 | steps:
18 | - name: Checkout code
19 | uses: actions/checkout@v4
20 |
21 | - name: Setup .NET
22 | uses: actions/setup-dotnet@v4
23 | with:
24 | dotnet-version: '9.0.x'
25 |
26 | - name: Build and publish for win-x64
27 | run: dotnet publish DNSSpeedTester.csproj -c Release -r win-x64 --output ./publish-x64
28 |
29 | - name: Rename win-x64 executable
30 | run: ren publish-x64\DNSSpeedTester.exe DNSSpeedTester-x64.exe
31 |
32 | - name: Archive win-x64 artifact
33 | uses: actions/upload-artifact@v4
34 | with:
35 | name: DNSSpeedTester-win-x64-files
36 | path: ./publish-x64
37 |
38 | - name: Build and publish for win-x86
39 | run: dotnet publish DNSSpeedTester.csproj -c Release -r win-x86 --output ./publish-x86
40 |
41 | - name: Rename win-x86 executable
42 | run: ren publish-x86\DNSSpeedTester.exe DNSSpeedTester-x86.exe
43 |
44 | - name: Archive win-x86 artifact
45 | uses: actions/upload-artifact@v4
46 | with:
47 | name: DNSSpeedTester-win-x86-files
48 | path: ./publish-x86
49 |
50 | - name: Create Release and Upload Assets
51 | if: startsWith(github.ref, 'refs/tags/') # 仅当事件是标签推送时执行
52 | uses: softprops/action-gh-release@v2
53 | with:
54 | files: |
55 | ./publish-*/*.exe
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # 忽略Rider生成的文件
2 | .run/
3 | riderModule.iml
4 | /_ReSharper.Caches/
5 |
6 | # 忽略所有编译输出目录
7 | bin/
8 | obj/
9 |
10 | # 忽略Visual Studio生成的用户特定文件
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # 忽略Visual Studio项目文件中的临时文件
17 | **/*.csproj.user
18 | **/*.csproj.vspscc
19 | **/*.vssscc
20 |
21 | # 忽略NuGet包缓存
22 | packages/
23 |
24 | # 忽略Visual Studio Code生成的文件
25 | .vscode/
26 | .idea/
27 | .vs/
28 | *.code-workspace
29 |
30 | # 忽略操作系统生成的文件
31 | .DS_Store
32 | Thumbs.db
33 |
34 | # 忽略日志文件
35 | *.log
36 |
37 | # 忽略测试结果文件
38 | TestResults/
39 |
--------------------------------------------------------------------------------
/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
17 |
19 |
21 |
23 |
25 |
27 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Threading;
3 |
4 | namespace DNSSpeedTester;
5 |
6 | public partial class App : Application
7 | {
8 | protected override void OnStartup(StartupEventArgs e)
9 | {
10 | base.OnStartup(e);
11 |
12 | // 注册全局未捕获异常处理
13 | AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
14 | DispatcherUnhandledException += HandleDispatcherException;
15 | }
16 |
17 | private void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
18 | {
19 | if (e.ExceptionObject is Exception ex) ShowErrorMessage($"发生未处理的异常: {ex.Message}");
20 | }
21 |
22 | private void HandleDispatcherException(object sender,
23 | DispatcherUnhandledExceptionEventArgs e)
24 | {
25 | ShowErrorMessage($"发生未处理的异常: {e.Exception.Message}");
26 | e.Handled = true;
27 | }
28 |
29 | private static void ShowErrorMessage(string message)
30 | {
31 | MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
32 | }
33 | }
--------------------------------------------------------------------------------
/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
--------------------------------------------------------------------------------
/DNSSpeedTester.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net9.0-windows
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 | true
13 |
14 | false
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | true
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/DNSSpeedTester.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DNSSpeedTester", "DNSSpeedTester.csproj", "{C1E8B880-38CF-4268-B742-ACDCC6813EC7}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | EndGlobalSection
10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 | {C1E8B880-38CF-4268-B742-ACDCC6813EC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12 | {C1E8B880-38CF-4268-B742-ACDCC6813EC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
13 | {C1E8B880-38CF-4268-B742-ACDCC6813EC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
14 | {C1E8B880-38CF-4268-B742-ACDCC6813EC7}.Release|Any CPU.Build.0 = Release|Any CPU
15 | EndGlobalSection
16 | EndGlobal
17 |
--------------------------------------------------------------------------------
/Helpers/NetworkDiagnostics.cs:
--------------------------------------------------------------------------------
1 | using System.Management;
2 | using System.Security.Principal;
3 | using System.Text;
4 | using System.Windows;
5 |
6 | namespace DNSSpeedTester.Helpers;
7 |
8 | public static class NetworkDiagnostics
9 | {
10 | public static void RunDiagnostics()
11 | {
12 | try
13 | {
14 | var sb = new StringBuilder();
15 | sb.AppendLine("=== 网络适配器诊断 ===");
16 | sb.AppendLine($"时间: {DateTime.Now}");
17 | sb.AppendLine($"操作系统: {Environment.OSVersion.VersionString}");
18 | sb.AppendLine($"64位系统: {Environment.Is64BitOperatingSystem}");
19 | sb.AppendLine($"进程权限: {(IsRunningAsAdmin() ? "管理员" : "普通用户")}");
20 | sb.AppendLine();
21 |
22 | // 检查 WMI 服务
23 | sb.AppendLine("检查 WMI 服务状态...");
24 | CheckWmiService(sb);
25 | sb.AppendLine();
26 |
27 | // 尝试获取网络适配器
28 | sb.AppendLine("尝试获取网络适配器信息...");
29 | GetNetworkAdaptersInfo(sb);
30 |
31 | // 显示诊断信息
32 | MessageBox.Show(sb.ToString(), "网络适配器诊断", MessageBoxButton.OK, MessageBoxImage.Information);
33 | }
34 | catch (Exception ex)
35 | {
36 | MessageBox.Show($"运行诊断时出错: {ex.Message}", "诊断错误", MessageBoxButton.OK, MessageBoxImage.Error);
37 | }
38 | }
39 |
40 |
41 | private static bool IsRunningAsAdmin()
42 | {
43 | try
44 | {
45 | var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
46 | return principal.IsInRole(WindowsBuiltInRole.Administrator);
47 | }
48 | catch
49 | {
50 | return false;
51 | }
52 | }
53 |
54 | private static void CheckWmiService(StringBuilder sb)
55 | {
56 | try
57 | {
58 | using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service WHERE Name='Winmgmt'"))
59 | {
60 | foreach (var service in searcher.Get())
61 | {
62 | var state = service["State"]?.ToString() ?? "未知";
63 | var startMode = service["StartMode"]?.ToString() ?? "未知";
64 | sb.AppendLine($"WMI 服务状态: {state}");
65 | sb.AppendLine($"WMI 服务启动模式: {startMode}");
66 | return;
67 | }
68 | }
69 |
70 | sb.AppendLine("未找到 WMI 服务信息");
71 | }
72 | catch (Exception ex)
73 | {
74 | sb.AppendLine($"检查 WMI 服务时出错: {ex.Message}");
75 | }
76 | }
77 |
78 | private static void GetNetworkAdaptersInfo(StringBuilder sb)
79 | {
80 | try
81 | {
82 | sb.AppendLine("方法 1: Win32_NetworkAdapter");
83 | using (var searcher =
84 | new ManagementObjectSearcher(
85 | "SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL"))
86 | {
87 | var adapters = searcher.Get();
88 | var count = 0;
89 | foreach (var adapter in adapters)
90 | {
91 | count++;
92 | sb.AppendLine($"- 适配器 {count}: {adapter["Description"]}");
93 | sb.AppendLine($" ID: {adapter["DeviceID"]}");
94 | sb.AppendLine($" 名称: {adapter["NetConnectionID"]}");
95 | sb.AppendLine($" MAC: {adapter["MACAddress"]}");
96 | }
97 |
98 | sb.AppendLine($"总共找到 {count} 个适配器");
99 | }
100 |
101 | sb.AppendLine("\n方法 2: Win32_NetworkAdapterConfiguration");
102 | using (var searcher =
103 | new ManagementObjectSearcher(
104 | "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True"))
105 | {
106 | var configs = searcher.Get();
107 | var count = 0;
108 | foreach (var config in configs)
109 | {
110 | count++;
111 | sb.AppendLine($"- 配置 {count}: {config["Description"]}");
112 | sb.AppendLine($" 索引: {config["Index"]}");
113 | sb.AppendLine($" DHCP启用: {config["DHCPEnabled"]}");
114 |
115 | if (config["IPAddress"] is string[] ipAddresses && ipAddresses.Length > 0)
116 | sb.AppendLine($" IP地址: {string.Join(", ", ipAddresses)}");
117 |
118 | if (config["DNSServerSearchOrder"] is string[] dnsServers && dnsServers.Length > 0)
119 | sb.AppendLine($" DNS服务器: {string.Join(", ", dnsServers)}");
120 | }
121 |
122 | sb.AppendLine($"总共找到 {count} 个网络配置");
123 | }
124 | }
125 | catch (Exception ex)
126 | {
127 | sb.AppendLine($"获取网络适配器信息时出错: {ex.Message}");
128 | sb.AppendLine($"异常类型: {ex.GetType().FullName}");
129 | sb.AppendLine($"堆栈跟踪: {ex.StackTrace}");
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/Helpers/RelayCommand.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 |
3 | namespace DNSSpeedTester.Helpers;
4 |
5 | public class RelayCommand : ICommand
6 | {
7 | private readonly Func