Слишком быстрая загрузка и блокировка сервера - использование WebClient.DownloadFileCompleted, чтобы сообщить нам, когда DownloadFileAsync будет завершен

Фон:

Каждый год мы запускаем, а затем архивируем все отчеты из определенного приложения ASP.Net. Архив предоставляет "снимок" того, как выглядели данные системы в определенное время года. Мы создали графический интерфейс с использованием.Net Forms, который использует System.Net.WebClient для вызова сервера отчетов и загрузки отчетов в определенный каталог. Это хорошо работало в прошлом.

В этом году мы включаем файлы Excel в наш архив. Файлы Excel создаются на странице ASPX (Windows Sever 2003, IIS6, .Net 4.0), которая принимает строку запроса, а затем возвращает файл Excel. Это прекрасно работает для 100 или около того файлов Excel, но после этого у нас начинаются проблемы. Мы архивируем около 300000 файлов каждый год.

Механика:

Мы используем WebClient.DownloadFileAsync для удаления наших файлов, чтобы не блокировать поток пользовательского интерфейса. Мы полагаемся на событие WebClient.DownloadFileCompleted, чтобы сообщить нам о завершении загрузки каждого файла. Когда DownloadFileCompleted повышен, мы начинаем загрузку следующего файла.

Проблема:

Мы закрываем веб-сервер. Каждый файл загружается всего за доли секунды, и после примерно 167 файлов веб-сервер блокируется (время ожидания страниц), и процесс архивации приостанавливается на несколько минут. Затем процесс архивирования загружает еще около 100 файлов и снова останавливается на несколько минут. Это продолжается в течение нескольких часов, пока процесс архива не начнет сканировать один файл каждую минуту или около того.

Похоже, что в IIS6 заканчиваются потоки, но как мы можем предотвратить это?

Ниже приведена уменьшенная версия кода, который мы запускаем. Я убрал логи и другие предметы, не связанные с нашей проблемой. У кого-нибудь есть советы?

public class DownloadExample
{
    private WebClient _WebClient = new WebClient();

    public string DownloadDirectory { get; set; }
    public List<Report> ReportList { get; set; }

    /// <summary>
    /// Constructor - sets all the attributes needed to access the report server, download, and archive the reports
    /// </summary>
    /// <param name="userName">Username</param>
    /// <param name="userPassword">Password for the user's domain username</param>
    /// <param name="userDomain">Domain of the username</param>
    /// <param name="downloadDirectory">Network path where the files will be archived</param>
    public DownloadExample(string userName, string userPassword, string userDomain, string downloadDirectory, List<Report> reportList)
    {
        DownloadDirectory = downloadDirectory;
        _WebClient.Credentials = new NetworkCredential(userName, userPassword, userDomain);
        _WebClient.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(WebClient_DownloadFileCompleted);
        ReportList = reportList;
    }

    /// <summary>
    /// Kicks off the archive process
    /// </summary>
    public void StartDownloading()
    {
        if (ReportList.Count > 0)
        {
            Report rpt = ReportList[0];
            DoDownload(rpt.URL, CreateFileName(rpt), rpt.ReportTitle, rpt.ReportFormatType);
        }
    }

    /// <summary>
    /// Run the report and then download it to the archive directory
    /// </summary>
    /// <param name="url">URL of the Report</param>
    /// <param name="fileName">File name used to name the report file once it is downloaded</param>
    /// <param name="folderName">Name of the folder where the report will be downloaded to</param> 
    /// <param name="reportFormatType">Type of report being run, PDF or Excel</param>
    private bool DoDownload(string url, string fileName, string folderName, ReportFormatTypes reportFormatType)
    {
        bool isSuccess = false;

        string folderPath = DownloadDirectory + "\\" + folderName;
        DirectoryInfo dir = new DirectoryInfo(folderPath);
        if (!dir.Exists)
        {
            dir.Create();
            dir = null;
            dir = new DirectoryInfo(folderPath);
        }

        if (dir.Exists)
        {
            string path = folderPath + "\\" + fileName + ".xls";
            System.Uri uri = new Uri(url);
            try
            {
                _WebClient.DownloadFileAsync(uri, path);
            }
            catch (Exception exp)
            {
                //log error
            }
            FileInfo file = new FileInfo(path);
            isSuccess = file.Exists;
        }
        return isSuccess;
    }

    /// <summary>
    /// This event is fired after a file is downloaded
    /// After each file is downloaded, we remove the downloaded file from the list, 
    /// then download the next file.
    /// </summary>
    void WebClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    {
        //Remove the report that was just run
        ReportList.RemoveAt(0);
        if (ReportList.Count > 0)
        {
            //Download the next report
            Report rpt = ReportList[0];
            DoDownload(rpt.URL, CreateFileName(rpt), rpt.ReportTitle, rpt.ReportFormatType);
        }
    }

    /// <summary>
    /// Does a bunch of stuff to create the file name...
    /// </summary>
    string CreateFileName(Report rpt)
    {
        return rpt.FileName;
    }
}    

0 ответов

Другие вопросы по тегам