Try / Catch没有捕获WebException

时间:2013-02-20 09:43:11

标签: c# mono

我构建了一个.NET Mono应用程序,它每分钟将文本文件上传到服务器。这个应用程序确实需要全天候运行,我用它来将.rss提要的数据传输到我们的图文电视服务器,以便在电视上传输。 在我看来,避免崩溃应用程序的最好方法是在上传代码周围使用try catch,以便捕获意外错误。

总是它正确地运行了大约2天,之后它突然崩溃了。我已经找了几个星期的原因,但找不到它。

我得到的错误是:

  

未处理的异常:System.Net.WebException:请求已中止   System.Net.FtpWebRequest.CheckIfAborted()[0x00000] in:0 at System.Net.FtpWebRequest.set_Sate(RequestState value)   [0x00000] in:0 at   System.Net.FtpWebRequest.ProcessRequest(RequestState value)[0x00000]   in:at System.Threading.Thread.StartUnsafe()   [0x00000] in:

上传代码在线程内运行,并且是:

private static readonly ILog log = LogManager.GetLogger(typeof(PheTextConnector));

static String ftp_path = ConfigurationManager.AppSettings["txtServerFTPPath"];
static String ip = ConfigurationManager.AppSettings["txtServerIP"];
static String username = ConfigurationManager.AppSettings["txtServerUsername"];
static String password = ConfigurationManager.AppSettings["txtServerPassword"];

public void UploadToTextServer(String filename, String uploadfolder)
{
  try
  {
    UploadFile(ip, ftp_path, filename, username, password, uploadfolder);
  }
  catch(Exception ex)
  {
    log.Error(ex.ToString());
  }
}

public void UploadFile(string FTPAddress, string directory, string filename, string username, string password, string uploadfolder)
{
    try
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + FTPAddress + "/" + directory + "/" + Path.GetFileName(filename));

        request.Method = WebRequestMethods.Ftp.UploadFile;
        request.Credentials = new NetworkCredential(username, password);
        request.UsePassive = true;
        request.UseBinary = true;
        request.KeepAlive = true;

        FileStream fs = File.OpenRead(uploadfolder + "/" + filename);
        int buffLength = 4096;
        byte[] buffer = new byte[buffLength];
        Stream strm = request.GetRequestStream();                   
        int bytesRead = fs.Read(buffer, 0, buffer.Length);

        while (true)
        {
            if (bytesRead == 0)
            {
                strm.Close();
                fs.Close();
                break;
            }
            else
            {
                strm.Write(buffer, 0, bytesRead);
                bytesRead = fs.Read(buffer, 0, buffLength);
            }
        }

        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
        response.Close();
    }
    catch(Exception ex)
    {
        log.Error(ex.ToString());
    }
}
}

调用上传方法的类的代码是:

using System;
using System.IO;
using System.Threading;
using log4net;
using System.Text.RegularExpressions;
using System.Configuration;

public class PhecapConnectionMain
{
    private static readonly ILog log = LogManager.GetLogger(typeof(PhecapConnectionMain));

private Object thisLock = new Object();
private int waitTimeBetweenTxtUpdates = Int32.Parse(ConfigurationManager.AppSettings["txtServerTimeBetweenUpdates"]);
private String transferDirectory = ConfigurationManager.AppSettings["transferDirectoryName"];

public PhecapConnectionMain ()
{
    try
    {
        log.Debug("Start Phecap Connection");

        CreateDirectoryIfNotExists(transferDirectory);
        FileSystemWatcher _watcher = new FileSystemWatcher();
        _watcher.Path = transferDirectory+"/";

        _watcher.NotifyFilter = System.IO.NotifyFilters.DirectoryName;
        _watcher.NotifyFilter = _watcher.NotifyFilter | System.IO.NotifyFilters.FileName;
        _watcher.NotifyFilter = _watcher.NotifyFilter | System.IO.NotifyFilters.Attributes;

        _watcher.EnableRaisingEvents = true;
        _watcher.IncludeSubdirectories = true;

        _watcher.Created += new FileSystemEventHandler(eventRaised);
    }
    catch(Exception ex)
    {
        log.Error(ex.ToString());
    }
}

/// <summary>
/// Triggered when an event is raised from the folder activity monitoring.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">containing all data send from the event that got executed.</param>
private void eventRaised (object sender, System.IO.FileSystemEventArgs e)
{
    String changedFileName = e.Name;

    changedFileName = Regex.Replace (changedFileName, @"//", @"//");
    changedFileName = String.Format(@"{0}",changedFileName);

    switch(e.ChangeType)
    {
        case WatcherChangeTypes.Created:
            if(changedFileName.Contains("update.sem"))
            {
                Thread thread = new Thread(NewFolderCreatedThread);
                thread.Start(e);
            }
            break;
        default: 
        break;
    }
} 

/// <summary>
/// Creates a directory if not exists.
/// </summary>
/// <param name='folderName'>
/// Folder name.
/// </param>
private void CreateDirectoryIfNotExists(String folderName)
{
    if(Directory.Exists(folderName) == false)
    {
        Directory.CreateDirectory(folderName);          
    }
}

/// <summary>
/// News the folder created thread.
/// </summary>
/// <param name='parameterObject'>
/// Parameter object.
/// </param>/
public void NewFolderCreatedThread(object parameterObject)
{
    // Lock object, one thread at a time may upload files
    lock(thisLock)
    {   
        try
        {
            System.IO.FileSystemEventArgs fileInfo = (System.IO.FileSystemEventArgs) parameterObject;           
            String[] splitted = fileInfo.Name.Split('/');
            String directory = transferDirectory+"/"+splitted[splitted.Length-2]+"/";

            string [] fileEntries = Directory.GetFiles(directory);
            PheTextConnector pheTextConnector = new PheTextConnector();

            int percentage = 0;
            double counter = 1;
            double lengt = fileEntries.Length;

            foreach(string fName in fileEntries)
            {               
                String[] tempSplitted = fName.Split('/');
                String fileName = tempSplitted[tempSplitted.Length-1];

                if(!fileName.Equals("update.sem"))
                {
                    pheTextConnector.UploadToTextServer(fileName, directory);
                }

                double percent = (counter / lengt) * 100.0;
                percentage = (int) percent;
                ConsoleFunctions.RenderConsoleProgress(percentage, '\u2590', ConsoleColor.Yellow, "Uploading file " + fileName);
                counter++;  
            }

            pheTextConnector.UploadToTextServer("update.sem", directory);

            Directory.Delete(directory, true);  
            log.Debug("Files are uploaded to server, wait " + waitTimeBetweenTxtUpdates + " milliseconds for releasing lock");

            Thread.Sleep(waitTimeBetweenTxtUpdates);
            log.Debug("Waiting complete...  release lock and allow new updates to be uploaded to the server");
        }
        catch(Exception ex)
        {
            log.Error(ex.ToString());
        }
    }           
}
}

- 编辑:

我使用using语句改进了UploadMethod。并找到了通过将FTPWebRequest的超时值设置为100毫秒来重现此错误的方法。 而不是try catch捕获的超时错误,应用程序完全崩溃。

using System;
using System.IO;
using System.Net;
using System.Configuration;
using log4net;

public class PheTextConnector
{
    private static readonly ILog log = LogManager.GetLogger(typeof(PheTextConnector));
    static String ftp_path = ConfigurationManager.AppSettings["txtServerFTPPath"];
    static String ip = ConfigurationManager.AppSettings["txtServerIP"];
    static String username = ConfigurationManager.AppSettings["txtServerUsername"];
    static String password = ConfigurationManager.AppSettings["txtServerPassword"];

    public void UploadToTextServer(String filename, String uploadfolder)
    {
        try
        {
            UploadFile(ip, ftp_path, filename, username, password, uploadfolder);
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        catch(Exception ex)
        {   
            log.Error(ex.ToString());
        }
    }

    public void UploadFile(string FTPAddress, string directory, string filename, string username, string password, string uploadfolder)
    {
    try
        {
            FtpWebRequest request = (FtpWebRequest) WebRequest.Create("ftp://" + FTPAddress + "/" + directory + "/" + Path.GetFileName(filename));
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(username, password); 
            request.UsePassive = true;
            request.UseBinary = true;
            request.KeepAlive = true;
            request.Timeout = 100;

            byte[] buffer = new byte[4096];
            using (FileStream fs = File.OpenRead(uploadfolder + "/" + filename))
            { 
                using(Stream stream = request.GetRequestStream())
                {
                    int bytesRead = fs.Read(buffer, 0, buffer.Length);
                    while (true)
                    {
                        if (bytesRead == 0)
                        {
                            stream.Close();
                            break;
                        }
                        else
                        {
                            stream.Write(buffer, 0, bytesRead);
                            bytesRead = fs.Read(buffer, 0, 4096);
                        }
                    }
                }
            }
            using(FtpWebResponse response = (FtpWebResponse)request.GetResponse())
            {
                response.Close();
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        catch(Exception ex)
        {
            log.Error(ex.ToString());
        }
    }
}

System.Net.WebException: Request timed out
at System.Net.FtpWebRequest.EndGetRequestStream (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.GetRequestStream () [0x00000] in <filename unknown>:0
at PheTextConnector.UploadFile (System.String FTPAddress, System.String directory,   
System.String filename, System.String username, System.String password, System.String
uploadfolder) [0x00094] in /svn/WOSTeletekst/WOSTxT/PheCapConnector
/PheTextConnector.cs:47

System.Net.WebException: Request aborted
at System.Net.FtpWebRequest.CheckIfAborted () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.set_State (RequestState value) [0x00000] in <filename    unknown>:0
at System.Net.FtpWebRequest.UploadData () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessMethod () [0x00000] in <filename unknown>:0
at System.Net.FtpWebRequest.ProcessRequest () [0x00000] in <filename unknown>:0

2 个答案:

答案 0 :(得分:1)

你的电视机可能没什么问题,我的意思是你的代码。

问题是Mono的FtpWebRequest实现不是很强大(在FTP会话的各个阶段处理不当)。我对类似的案例进行了分析并在那里发表了我的发现:

Mono for Android / MonoTouch System.Net.WebException: Request aborted

你的案例虽然不尽相同,但却指出了Mono的FtpWebRequest问题的常见“包”。

答案 1 :(得分:0)

这些错误很难找到。 你说你在一个线程中运行这个函数。所以我猜它是从while循环而不是Thread.Sleep(1000*60);fire and forget调用的。原因可能是,在下一次调用之前函数没有完成,或FtpWebRequest仍未关闭,并且无关紧要,它在不同的上下文中运行。

我有类似的问题,你可以试试这里:

1)使FtpWebRequest request全局并在函数调用之前检查它是否仍然存活。

2)在函数端调用垃圾收集器:

GC.Collect();
GC.WaitForPendingFinalizers();

如果有效,请告诉我。