diff --git a/Netch/.gitignore b/Netch/.gitignore index a8b0b13e..60cd5cf8 100644 --- a/Netch/.gitignore +++ b/Netch/.gitignore @@ -1,3 +1,4 @@ /bin /obj /*.csproj.user +FodyWeavers.xsd \ No newline at end of file diff --git a/Netch/Constants.cs b/Netch/Constants.cs index 4323f845..c94e8851 100644 --- a/Netch/Constants.cs +++ b/Netch/Constants.cs @@ -25,6 +25,6 @@ public static class Constants public const string WintunDllFile = "bin\\wintun.dll"; public const string DisableModeDirectoryFileName = "disabled"; - public const string DefaultPrimaryDNS = "1.1.1.1:53"; - public const string DefaultCNPrimaryDNS = "223.5.5.5:53"; + public const string DefaultPrimaryDNS = "1.1.1.1"; + public const string DefaultCNPrimaryDNS = "223.5.5.5"; } \ No newline at end of file diff --git a/Netch/Controllers/DNSController.cs b/Netch/Controllers/DNSController.cs index 5aee6a3f..270f48dc 100644 --- a/Netch/Controllers/DNSController.cs +++ b/Netch/Controllers/DNSController.cs @@ -23,8 +23,8 @@ public class DNSController : IController throw new MessageException("AioDNS start failed."); } - public async Task StopAsync() + public Task StopAsync() { - await FreeAsync(); + return FreeAsync(); } } \ No newline at end of file diff --git a/Netch/Controllers/Guard.cs b/Netch/Controllers/Guard.cs index c0d78c94..7cd5b140 100644 --- a/Netch/Controllers/Guard.cs +++ b/Netch/Controllers/Guard.cs @@ -67,7 +67,7 @@ public abstract class Guard { State = State.Starting; - _logFileStream = File.Open(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read); + _logFileStream = new FileStream(LogPath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096, true); _logStreamWriter = new StreamWriter(_logFileStream) { AutoFlush = true }; Instance.StartInfo.Arguments = argument; @@ -79,8 +79,8 @@ public abstract class Guard if (RedirectOutput) { - Task.Run(() => ReadOutput(Instance.StandardOutput)).Forget(); - Task.Run(() => ReadOutput(Instance.StandardError)).Forget(); + ReadOutputAsync(Instance.StandardOutput).Forget(); + ReadOutputAsync(Instance.StandardError).Forget(); if (!StartedKeywords.Any()) { @@ -110,12 +110,12 @@ public abstract class Guard } } - private void ReadOutput(TextReader reader) + private async Task ReadOutputAsync(TextReader reader) { string? line; - while ((line = reader.ReadLine()) != null) + while ((line = await reader.ReadLineAsync()) != null) { - _logStreamWriter!.WriteLine(line); + await _logStreamWriter!.WriteLineAsync(line); OnReadNewLine(line); if (State == State.Starting) @@ -133,9 +133,9 @@ public abstract class Guard State = State.Stopped; } - public virtual async Task StopAsync() + public virtual Task StopAsync() { - await StopGuardAsync(); + return StopGuardAsync(); } protected async Task StopGuardAsync() diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index dd66e14e..b8e64c28 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -169,18 +169,18 @@ public static class MainController PortCheck(port, portName, PortType.TCP); } - public static async Task DiscoveryNatTypeAsync(CancellationToken ctx = default) + public static Task DiscoveryNatTypeAsync(CancellationToken ctx = default) { Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null"); - return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx); + return Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx); } - public static async Task HttpConnectAsync(CancellationToken ctx = default) + public static Task HttpConnectAsync(CancellationToken ctx = default) { Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null"); try { - return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx); + return Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx); } catch (OperationCanceledException) { @@ -191,6 +191,6 @@ public static class MainController Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception"); } - return null; + return Task.FromResult(null); } } \ No newline at end of file diff --git a/Netch/Controllers/NFController.cs b/Netch/Controllers/NFController.cs index 18399095..50373f43 100644 --- a/Netch/Controllers/NFController.cs +++ b/Netch/Controllers/NFController.cs @@ -76,9 +76,9 @@ public class NFController : IModeController throw new MessageException("Redirector start failed."); } - public async Task StopAsync() + public Task StopAsync() { - await FreeAsync(); + return FreeAsync(); } #region CheckRule diff --git a/Netch/Controllers/TUNController.cs b/Netch/Controllers/TUNController.cs index f9d0f91a..4d2da0ea 100644 --- a/Netch/Controllers/TUNController.cs +++ b/Netch/Controllers/TUNController.cs @@ -92,10 +92,11 @@ public class TUNController : Guard, IModeController _tun = NetRoute.TemplateBuilder(_tunConfig.Gateway, tunIndex); Global.MainForm.StatusText(i18N.Translate("Assign Unicast IP")); - if (!RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, - _tunConfig.Address, - (byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask), - (ulong)tunIndex)) + if (!await Task.Run(() => RouteHelper.CreateUnicastIP(AddressFamily.InterNetwork, + _tunConfig.Address, + (byte)Utils.Utils.SubnetToCidr(_tunConfig.Netmask), + (ulong)tunIndex)) + ) { Log.Error("Create Unicast IP failed"); throw new MessageException("Create Unicast IP failed"); diff --git a/Netch/FodyWeavers.xml b/Netch/FodyWeavers.xml new file mode 100644 index 00000000..00e1d9a1 --- /dev/null +++ b/Netch/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Netch/Forms/AboutForm.cs b/Netch/Forms/AboutForm.cs index 076d6d80..25837553 100644 --- a/Netch/Forms/AboutForm.cs +++ b/Netch/Forms/AboutForm.cs @@ -3,6 +3,7 @@ using Netch.Utils; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class AboutForm : Form { public AboutForm() diff --git a/Netch/Forms/BindingForm.cs b/Netch/Forms/BindingForm.cs index 4d9f4355..37333e51 100644 --- a/Netch/Forms/BindingForm.cs +++ b/Netch/Forms/BindingForm.cs @@ -2,6 +2,7 @@ namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public class BindingForm : Form { private readonly Dictionary> _checkActions = new(); diff --git a/Netch/Forms/GlobalBypassIPForm.cs b/Netch/Forms/GlobalBypassIPForm.cs index 06d082dd..9c1ab811 100644 --- a/Netch/Forms/GlobalBypassIPForm.cs +++ b/Netch/Forms/GlobalBypassIPForm.cs @@ -4,6 +4,7 @@ using Netch.Utils; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class GlobalBypassIPForm : Form { public GlobalBypassIPForm() diff --git a/Netch/Forms/LogForm.cs b/Netch/Forms/LogForm.cs index 1ead9918..a7b1d5e3 100644 --- a/Netch/Forms/LogForm.cs +++ b/Netch/Forms/LogForm.cs @@ -5,6 +5,7 @@ using static Windows.Win32.PInvoke; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class LogForm : Form { private readonly Form _parent; diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index cacc1a82..ef056450 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -18,6 +18,7 @@ using Netch.Utils; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class MainForm : Form { #region Start @@ -447,10 +448,13 @@ public partial class MainForm : Form var downloaded = false; if (File.Exists(updateFileFullName)) - if (Utils.Utils.SHA256CheckSum(updateFileFullName) == sha256) + { + var fileHash = await Utils.Utils.Sha256CheckSumAsync(updateFileFullName); + if (fileHash == sha256) downloaded = true; else File.Delete(updateFileFullName); + } if (!downloaded) { @@ -464,7 +468,8 @@ public partial class MainForm : Form throw new MessageException($"Download Update File Failed: {e1.Message}"); } - if (Utils.Utils.SHA256CheckSum(updateFileFullName) != sha256) + var fileHash = await Utils.Utils.Sha256CheckSumAsync(updateFileFullName); + if (fileHash != sha256) throw new MessageException(i18N.Translate("The downloaded file has the wrong hash")); } diff --git a/Netch/Forms/ModeForms/ProcessForm.cs b/Netch/Forms/ModeForms/ProcessForm.cs index d33b02dc..6ab85d00 100644 --- a/Netch/Forms/ModeForms/ProcessForm.cs +++ b/Netch/Forms/ModeForms/ProcessForm.cs @@ -9,6 +9,7 @@ using Netch.Utils; namespace Netch.Forms.ModeForms; +[Fody.ConfigureAwait(true)] public partial class ProcessForm : BindingForm { private readonly bool IsCreateMode; diff --git a/Netch/Forms/ModeForms/RouteForm.cs b/Netch/Forms/ModeForms/RouteForm.cs index 40037083..10fd741e 100644 --- a/Netch/Forms/ModeForms/RouteForm.cs +++ b/Netch/Forms/ModeForms/RouteForm.cs @@ -6,6 +6,7 @@ using Netch.Utils; namespace Netch.Forms.ModeForms; +[Fody.ConfigureAwait(true)] public partial class RouteForm : BindingForm { private readonly bool IsCreateMode; diff --git a/Netch/Forms/ServerForm.cs b/Netch/Forms/ServerForm.cs index fb6d6c79..5c02a216 100644 --- a/Netch/Forms/ServerForm.cs +++ b/Netch/Forms/ServerForm.cs @@ -7,6 +7,7 @@ using Netch.Utils; namespace Netch.Forms; [DesignerCategory(@"Code")] +[Fody.ConfigureAwait(true)] public abstract class ServerForm : Form { private const int ControlLineHeight = 28; diff --git a/Netch/Forms/SettingForm.cs b/Netch/Forms/SettingForm.cs index da34a76a..36ffd5dc 100644 --- a/Netch/Forms/SettingForm.cs +++ b/Netch/Forms/SettingForm.cs @@ -4,6 +4,7 @@ using Netch.Utils; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class SettingForm : BindingForm { public SettingForm() diff --git a/Netch/Forms/SubscriptionForm.cs b/Netch/Forms/SubscriptionForm.cs index 0c49f3c3..97bb72ef 100644 --- a/Netch/Forms/SubscriptionForm.cs +++ b/Netch/Forms/SubscriptionForm.cs @@ -4,6 +4,7 @@ using Netch.Utils; namespace Netch.Forms; +[Fody.ConfigureAwait(true)] public partial class SubscriptionForm : Form { public SubscriptionForm() diff --git a/Netch/Interops/AioDNS.cs b/Netch/Interops/AioDNS.cs index dc67f388..5c08a9f0 100644 --- a/Netch/Interops/AioDNS.cs +++ b/Netch/Interops/AioDNS.cs @@ -13,14 +13,14 @@ public static class AioDNS return aiodns_dial(name, Encoding.UTF8.GetBytes(value)); } - public static async Task InitAsync() + public static Task InitAsync() { - return await Task.Run(Init).ConfigureAwait(false); + return Task.Run(Init); } - public static async Task FreeAsync() + public static Task FreeAsync() { - await Task.Run(Free).ConfigureAwait(false); + return Task.Run(Free); } [DllImport(aiodns_bin, CallingConvention = CallingConvention.Cdecl)] diff --git a/Netch/Interops/Redirector.cs b/Netch/Interops/Redirector.cs index 6d0517f7..21cd3e67 100644 --- a/Netch/Interops/Redirector.cs +++ b/Netch/Interops/Redirector.cs @@ -43,14 +43,14 @@ public static class Redirector return aio_dial(name, value); } - public static async Task InitAsync() + public static Task InitAsync() { - return await Task.Run(aio_init).ConfigureAwait(false); + return Task.Run(aio_init); } - public static async Task FreeAsync() + public static Task FreeAsync() { - return await Task.Run(aio_free).ConfigureAwait(false); + return Task.Run(aio_free); } private const string Redirector_bin = "Redirector.bin"; diff --git a/Netch/Models/Server.cs b/Netch/Models/Server.cs index 59df4959..f94e1b6c 100644 --- a/Netch/Models/Server.cs +++ b/Netch/Models/Server.cs @@ -77,17 +77,15 @@ public abstract class Server : ICloneable var list = new Task[3]; for (var i = 0; i < 3; i++) { - async Task PingCoreAsync() + Task PingCoreAsync() { try { - return Global.Settings.ServerTCPing - ? await Utils.Utils.TCPingAsync(destination, Port) - : await Utils.Utils.ICMPingAsync(destination); + return Global.Settings.ServerTCPing ? Utils.Utils.TCPingAsync(destination, Port) : Utils.Utils.ICMPingAsync(destination); } catch (Exception) { - return -4; + return Task.FromResult(-4); } } diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj index 7d23448b..287e01f4 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -37,6 +37,13 @@ + + all + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Netch/Program.cs b/Netch/Program.cs index df8cbc24..6482a014 100644 --- a/Netch/Program.cs +++ b/Netch/Program.cs @@ -91,7 +91,7 @@ public static class Program i18N.Load(Global.Settings.Language); // log environment information - Task.Run(LogEnvironment).Forget(); + LogEnvironmentAsync().Forget(); CheckClr(); CheckOS(); @@ -108,11 +108,11 @@ public static class Program #pragma warning restore VSTHRD002 - private static void LogEnvironment() + private static async Task LogEnvironmentAsync() { Log.Information("Netch Version: {Version}", $"{UpdateChecker.Owner}/{UpdateChecker.Repo}@{UpdateChecker.Version}"); Log.Information("OS: {OSVersion}", Environment.OSVersion); - Log.Information("SHA256: {Hash}", $"{Utils.Utils.SHA256CheckSum(Global.NetchExecutable)}"); + Log.Information("SHA256: {Hash}", $"{await Utils.Utils.Sha256CheckSumAsync(Global.NetchExecutable)}"); Log.Information("System Language: {Language}", CultureInfo.CurrentCulture.Name); #if RELEASE diff --git a/Netch/Properties/AssemblyInfo.cs b/Netch/Properties/AssemblyInfo.cs index 62965d69..7bb236ef 100644 --- a/Netch/Properties/AssemblyInfo.cs +++ b/Netch/Properties/AssemblyInfo.cs @@ -14,6 +14,7 @@ using Netch.Controllers; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: System.Runtime.Versioning.SupportedOSPlatformAttribute("Windows7.0")] +[assembly: Fody.ConfigureAwait(false)] // 将 ComVisible 设置为 false 会使此程序集中的类型 //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 diff --git a/Netch/Servers/Shadowsocks/ShadowsocksForm.cs b/Netch/Servers/Shadowsocks/ShadowsocksForm.cs index b5a23a16..8f9a9343 100644 --- a/Netch/Servers/Shadowsocks/ShadowsocksForm.cs +++ b/Netch/Servers/Shadowsocks/ShadowsocksForm.cs @@ -3,6 +3,7 @@ using Netch.Utils; namespace Netch.Servers; +[Fody.ConfigureAwait(true)] public class ShadowsocksForm : ServerForm { public ShadowsocksForm(ShadowsocksServer? server = default) diff --git a/Netch/Servers/ShadowsocksR/ShadowsocksRForm.cs b/Netch/Servers/ShadowsocksR/ShadowsocksRForm.cs index 8c92ff06..b307e61b 100644 --- a/Netch/Servers/ShadowsocksR/ShadowsocksRForm.cs +++ b/Netch/Servers/ShadowsocksR/ShadowsocksRForm.cs @@ -3,6 +3,7 @@ using Netch.Utils; namespace Netch.Servers; +[Fody.ConfigureAwait(true)] public class ShadowsocksRForm : ServerForm { public ShadowsocksRForm(ShadowsocksRServer? server = default) diff --git a/Netch/Servers/Socks5/Socks5Controller.cs b/Netch/Servers/Socks5/Socks5Controller.cs index 89fffd6a..f793dcce 100644 --- a/Netch/Servers/Socks5/Socks5Controller.cs +++ b/Netch/Servers/Socks5/Socks5Controller.cs @@ -6,12 +6,12 @@ public class Socks5Controller : V2rayController { public override string Name { get; } = "Socks5"; - public override async Task StartAsync(Server s) + public override Task StartAsync(Server s) { var server = (Socks5Server)s; if (!server.Auth()) throw new ArgumentException(); - return await base.StartAsync(s); + return base.StartAsync(s); } } \ No newline at end of file diff --git a/Netch/Servers/Socks5/Socks5Form.cs b/Netch/Servers/Socks5/Socks5Form.cs index a9f86571..21ba26b7 100644 --- a/Netch/Servers/Socks5/Socks5Form.cs +++ b/Netch/Servers/Socks5/Socks5Form.cs @@ -2,6 +2,7 @@ namespace Netch.Servers; +[Fody.ConfigureAwait(true)] public class Socks5Form : ServerForm { public Socks5Form(Socks5Server? server = default) diff --git a/Netch/Servers/Trojan/TrojanForm.cs b/Netch/Servers/Trojan/TrojanForm.cs index 8d007476..210a3c06 100644 --- a/Netch/Servers/Trojan/TrojanForm.cs +++ b/Netch/Servers/Trojan/TrojanForm.cs @@ -2,6 +2,7 @@ namespace Netch.Servers; +[Fody.ConfigureAwait(true)] public class TrojanForm : ServerForm { public TrojanForm(TrojanServer? server = default) diff --git a/Netch/Servers/VLESS/VLESSForm.cs b/Netch/Servers/VLESS/VLESSForm.cs index 1f32e7a7..fe8365ab 100644 --- a/Netch/Servers/VLESS/VLESSForm.cs +++ b/Netch/Servers/VLESS/VLESSForm.cs @@ -2,6 +2,7 @@ using Netch.Forms; namespace Netch.Servers; +[Fody.ConfigureAwait(true)] internal class VLESSForm : ServerForm { public VLESSForm(VLESSServer? server = default) diff --git a/Netch/Servers/VMess/VMessForm.cs b/Netch/Servers/VMess/VMessForm.cs index 00a76b64..956d7ba9 100644 --- a/Netch/Servers/VMess/VMessForm.cs +++ b/Netch/Servers/VMess/VMessForm.cs @@ -2,6 +2,7 @@ namespace Netch.Servers; +[Fody.ConfigureAwait(true)] public class VMessForm : ServerForm { public VMessForm(VMessServer? server = default) diff --git a/Netch/Utils/Configuration.cs b/Netch/Utils/Configuration.cs index e5ab58aa..5f94799f 100644 --- a/Netch/Utils/Configuration.cs +++ b/Netch/Utils/Configuration.cs @@ -64,7 +64,7 @@ public static class Configuration await using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true)) { - settings = (await JsonSerializer.DeserializeAsync(fs, JsonSerializerOptions).ConfigureAwait(false))!; + settings = (await JsonSerializer.DeserializeAsync(fs, JsonSerializerOptions))!; } CheckSetting(settings); @@ -126,7 +126,7 @@ public static class Configuration { if (!File.Exists(FileFullName)) { - await File.Create(FileFullName).DisposeAsync(); + await using var fs = new FileStream(FileFullName, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, true); } } } \ No newline at end of file diff --git a/Netch/Utils/DnsUtils.cs b/Netch/Utils/DnsUtils.cs index aff6a395..935d9014 100644 --- a/Netch/Utils/DnsUtils.cs +++ b/Netch/Utils/DnsUtils.cs @@ -39,7 +39,7 @@ public static class DnsUtils private static async Task LookupNoCacheAsync(string hostname, AddressFamily inet = AddressFamily.Unspecified, int timeout = 3000) { using var task = Dns.GetHostAddressesAsync(hostname); - using var resTask = await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false); + using var resTask = await Task.WhenAny(task, Task.Delay(timeout)); if (resTask == task) { diff --git a/Netch/Utils/SubscriptionUtil.cs b/Netch/Utils/SubscriptionUtil.cs index 0aa2fde8..910af883 100644 --- a/Netch/Utils/SubscriptionUtil.cs +++ b/Netch/Utils/SubscriptionUtil.cs @@ -7,9 +7,9 @@ public static class SubscriptionUtil { private static readonly object ServerLock = new(); - public static async Task UpdateServersAsync(string? proxyServer = default) + public static Task UpdateServersAsync(string? proxyServer = default) { - await Task.WhenAll(Global.Settings.Subscription.Select(item => UpdateServerCoreAsync(item, proxyServer))); + return Task.WhenAll(Global.Settings.Subscription.Select(item => UpdateServerCoreAsync(item, proxyServer))); } private static async Task UpdateServerCoreAsync(Subscription item, string? proxyServer) diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index 144bea81..2c0b037c 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -92,12 +92,12 @@ public static class Utils return country; } - public static string SHA256CheckSum(string filePath) + public static async Task Sha256CheckSumAsync(string filePath) { try { - using var fileStream = File.OpenRead(filePath); - return SHA256ComputeCore(fileStream); + await using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true); + return await Sha256ComputeCoreAsync(fileStream); } catch (Exception e) { @@ -106,10 +106,11 @@ public static class Utils } } - private static string SHA256ComputeCore(Stream stream) + private static async Task Sha256ComputeCoreAsync(Stream stream) { using var sha256 = SHA256.Create(); - return string.Concat(sha256.ComputeHash(stream).Select(b => b.ToString("x2"))); + var hash = await sha256.ComputeHashAsync(stream); + return string.Concat(hash.Select(b => b.ToString("x2"))); } public static string GetFileVersion(string file) diff --git a/Netch/Utils/WebUtil.cs b/Netch/Utils/WebUtil.cs index 84c9cde6..bd775415 100644 --- a/Netch/Utils/WebUtil.cs +++ b/Netch/Utils/WebUtil.cs @@ -28,69 +28,55 @@ public static class WebUtil return req; } - /// - /// 异步下载 - /// - /// - /// public static async Task DownloadBytesAsync(HttpWebRequest req) { using var webResponse = await req.GetResponseAsync(); - await using var memoryStream = new MemoryStream(); - await using var input = webResponse.GetResponseStream(); - - await input.CopyToAsync(memoryStream); - return memoryStream.ToArray(); + var memoryStream = new MemoryStream(); + await using (memoryStream) + { + var input = webResponse.GetResponseStream(); + await using (input) + { + await input.CopyToAsync(memoryStream); + return memoryStream.ToArray(); + } + } } - /// - /// 异步下载并编码为字符串 - /// - /// - /// 编码,默认UTF-8 - /// - public static (HttpStatusCode, string) DownloadString(HttpWebRequest req, Encoding? encoding = null) - { - encoding ??= Encoding.UTF8; - using var rep = (HttpWebResponse)req.GetResponse(); - using var responseStream = rep.GetResponseStream(); - using var streamReader = new StreamReader(responseStream, encoding); - - return (rep.StatusCode, streamReader.ReadToEnd()); - } - - /// - /// 异步下载并编码为字符串 - /// - /// - /// 编码,默认UTF-8 - /// public static async Task<(HttpStatusCode, string)> DownloadStringAsync(HttpWebRequest req, Encoding? encoding = null) { encoding ??= Encoding.UTF8; using var webResponse = (HttpWebResponse)await req.GetResponseAsync(); - await using var responseStream = webResponse.GetResponseStream(); - using var streamReader = new StreamReader(responseStream, encoding); - return (webResponse.StatusCode, await streamReader.ReadToEndAsync()); + var responseStream = webResponse.GetResponseStream(); + await using (responseStream) + { + using var streamReader = new StreamReader(responseStream, encoding); + + return (webResponse.StatusCode, await streamReader.ReadToEndAsync()); + } } - public static async Task DownloadFileAsync(string address, string fileFullPath, IProgress? progress = null) + public static Task DownloadFileAsync(string address, string fileFullPath, IProgress? progress = null) { - await DownloadFileAsync(CreateRequest(address), fileFullPath, progress); + return DownloadFileAsync(CreateRequest(address), fileFullPath, progress); } public static async Task DownloadFileAsync(HttpWebRequest req, string fileFullPath, IProgress? progress) { - await using (var fileStream = File.Open(fileFullPath, FileMode.Create, FileAccess.Write)) - using (var webResponse = (HttpWebResponse)await req.GetResponseAsync()) - await using (var input = webResponse.GetResponseStream()) - using (var downloadTask = input.CopyToAsync(fileStream)) + var fileStream = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true); + await using (fileStream) { - if (progress != null) - ReportProgressAsync(webResponse.ContentLength, downloadTask, fileStream, progress, 200).Forget(); + using var webResponse = (HttpWebResponse)await req.GetResponseAsync(); + var input = webResponse.GetResponseStream(); + await using (input) + { + using var downloadTask = input.CopyToAsync(fileStream); + if (progress != null) + ReportProgressAsync(webResponse.ContentLength, downloadTask, fileStream, progress, 200).Forget(); - await downloadTask; + await downloadTask; + } } progress?.Report(100); @@ -108,7 +94,7 @@ public static class WebUtil progress.Report(n); } - await Task.Delay(interval).ConfigureAwait(false); + await Task.Delay(interval); } } } \ No newline at end of file