नीचे दिए गए WPF कोड को हमेशा के लिए लटका दिया जाता है जब नेटवर्क कनेक्शन 3 या अधिक मिनटों के लिए खो जाता है। जब कनेक्शन बहाल किया जाता है तो न तो फेंकता है और न ही डाउनलोड जारी रहता है और न ही टाइमआउट। यदि छोटी अवधि के लिए नेटवर्क कनेक्शन गुम हो जाता है तो आधे मिनट का कहना है, कनेक्शन बहाल होने के बाद यह फेंकता है। मैं नेटवर्क आउटेज से बचने के लिए इसे और अधिक मजबूत कैसे बना सकता हूं?.Net DownloadFileTaskAsync मजबूत WPF कोड
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
NetworkChange.NetworkAvailabilityChanged +=
(sender, e) => Dispatcher.Invoke(delegate()
{
this.Title = "Network is " + (e.IsAvailable ? " available" : "down");
});
}
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = @"d:\stuff\10Mio.dat";
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
try {
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
btnDownload.Content = "Downloaded";
}
}
catch (Exception ex)
{
btnDownload.Content = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
btnDownload.IsEnabled = true;
}
}
}
अद्यतन
वर्तमान समाधान DownloadProgressChangedEventHandler
में Timer
को पुन: प्रारंभ करने पर आधारित है, इसलिए टाइमर आग कोई DownloadProgressChanged घटनाओं टाइमआउट के भीतर हो ही अगर। एक बदसूरत हैक की तरह लग रहा है, अभी भी एक बेहतर समाधान की तलाश में है।
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = @"d:\stuff\10Mio.dat";
// Time needed to restore network connection
const int TIMEOUT = 30 * 1000;
public MainWindow()
{
InitializeComponent();
}
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Timer timer = new Timer((o) =>
{
// Force async cancellation
cts.Cancel();
}
, null //state
, TIMEOUT
, Timeout.Infinite // once
);
DownloadProgressChangedEventHandler handler = (sa, ea) =>
{
// Restart timer
if (ea.BytesReceived < ea.TotalBytesToReceive && timer != null)
{
timer.Change(TIMEOUT, Timeout.Infinite);
}
};
btnDownload.Content = await DownloadFileTA(token, handler);
// Note ProgressCallback will fire once again after awaited.
timer.Dispose();
btnDownload.IsEnabled = true;
}
private async Task<string> DownloadFileTA(CancellationToken token, DownloadProgressChangedEventHandler handler)
{
string res = null;
WebClient wcl = new WebClient();
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
wcl.DownloadProgressChanged += handler;
try
{
using (token.Register(() => wcl.CancelAsync()))
{
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
}
res = "Downloaded";
}
catch (Exception ex)
{
res = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
wcl.Dispose();
return res;
}
}
}
मेरा सुझाव है कि आप डाउनलोड के कोड को शामिल करने के लिए एक नई कक्षा बना रहे हैं, फिर btnDownload_Click से इस क्लास को डाउनलोड करें इस फ़ाइल को डाउनलोड करें। फिर आप कोड को साफ कर सकते हैं, और डीबग आसान कर सकते हैं। – Tony