1

バックグラウンド:

毎年、特定の ASP.Net アプリケーションからのすべてのレポートを実行してアーカイブしています。アーカイブは、システムのデータが特定の時期にどのように見えるかの「スナップショット」を提供します。System.Net.WebClient を使用してレポート サーバーを呼び出し、レポートを特定のディレクトリにダウンロードする .Net Forms を使用して GUI を作成しました。これは過去にうまく機能しました。

今年は、アーカイブに Excel ファイルを含めます。Excel ファイルは、クエリ文字列を取り込んで Excel ファイルを返す .aspx ページ (Windows Sever 2003、IIS6、.Net 4.0) によって作成されます。これは 100 個程度の Excel ファイルではうまく機能しますが、その後問題が発生し始めます。毎年、約 300,000 ファイルをアーカイブしています。

力学:

UI スレッドをロックしないように、WebClient.DownloadFileAsync を使用してファイルをプルダウンします。各ファイルのダウンロードがいつ完了したかを伝えるために、WebClient.DownloadFileCompleted イベントに依存しています。DownloadFileCompleted が発生すると、次のファイルのダウンロードを開始します。

問題:

ウェブサーバーをロックしています。各ファイルのダウンロードにはほんの一瞬しかかからず、約 167 ファイルを超えると Web サーバーがロックされ (ページ タイムアウト)、アーカイブ プロセスが数分間一時停止します。その後、アーカイブ プロセスはさらに 100 個ほどのファイルをダウンロードし、数分間再び停止します。これは、アーカイブ プロセスが約 1 分ごとに 1 つのファイルでクロールを開始するまで、数時間続きます。

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;
    }
}    
4

0 に答える 0