【问题标题】:How to clean up resources if FtpWebRequest goes wrong如果 FtpWebRequest 出错如何清理资源
【发布时间】:2019-11-05 10:08:47
【问题描述】:

我想知道这个 FtpWebRequest 是否出错,它会进入 catch 事件。我看过一个示例代码,他们在其中发布了我在 catch 事件中未注释的内容,以清理资源。

但我不知道在这种情况下这样做的正确方法是什么?我应该把所有这些都放在:= null;或者这是错误的做法?正确的做法是什么?

cleanUp(sourceStream, ref response, ref requestStream, ref request);

void uploadimage()
        {
            String sourceimage = "C:/ESD/image_2.jpg";
            Task<bool> task = FtpUploadFile(sourceimage);
            if (task.IsFaulted == false)
            {
                MessageBox.Show(task.Result.ToString());
            }
        }
        private Task closeRequestStreamAsync(Stream requestStream) { return Task.Run(() => { requestStream.Close(); }); }
        public async Task<bool> FtpUploadFile(string filename)
        {
            //if exception occurs we want to be able to close these
            FtpWebResponse response = null;
            FtpWebRequest request = null;
            FileStream sourceStream = null;
            Stream requestStream = null;
            try
            {
                bool isimage = false; String ext = Path.GetExtension(filename);
                if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".bmp") { isimage = true; }

                request = (FtpWebRequest)WebRequest.Create("ftp://someurl.com/Folder1/test1.jpg");
                request.UsePassive = true;
                if (isimage == true) { request.UseBinary = true; } //for images
                if (isimage == false) { request.UseBinary = false; } //for text
                request.KeepAlive = true; //keep the connection open
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.ConnectionGroupName = "Group1";
                request.ServicePoint.ConnectionLimit = 4;

                //These are the credentials.
                request.Credentials = new NetworkCredential("username", "password");


                sourceStream = File.OpenRead(filename);
                byte[] buffer = new byte[sourceStream.Length];
                await sourceStream.ReadAsync(buffer, 0, buffer.Length);
                sourceStream.Close();

                requestStream = await request.GetRequestStreamAsync();
                await requestStream.WriteAsync(buffer, 0, buffer.Length);
                //MPM  This is the call that takes the time     
                await closeRequestStreamAsync(requestStream);

                //response = (FtpWebResponse)request.GetResponse();
                WebResponse responseWeb = await request.GetResponseAsync();
                response = (FtpWebResponse)responseWeb;
                if (response.StatusDescription.Contains("226"))
                {
                    //This means that we successfully have uploaded the file!
                }
                response.Close();
                return true;
            }
            catch (Exception ex)
            {
                string errMSG = string.Format("Upload File failed, exception: {0}", ex.Message);
        //cleanUp(sourceStream, ref response, ref requestStream, ref request);
                return false;
            }
        }

【问题讨论】:

  • 不要在方法开始时声明变量。这是一个非常糟糕的做法,给了他们比他们需要的更大的范围,并使代码更难阅读。仅在需要时声明变量,最好在定义时为其赋值。至于FtpWebRequest,在using 块内声明变量,例如using (var FtpWebRequest)WebRequest.Create(..){ ....}。这样可以确保即使发生异常也会释放该值。
  • 也不要只吞下异常。要么处理它们,要么让它们传播给任何可以决定如何处理它们的人。如果请求失败,调用者会做什么? true/false 结果是什么意思?授权错误? DNS错误?还有什么?
  • BTW 流也需要关闭。 sourceStreamresponseStream 也应该在 using 块中声明
  • 这是一个好主意,可以在发生异常时使用它来处理它们。我试图声明这一点,但它似乎不正确?:using (FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://someurl.com/Folder1/test1.jpg"){ }
  • 打错字了。

标签: c# ftpwebrequest


【解决方案1】:

为确保 Web 请求、响应和流对象即使发生异常也关闭,应在 using 块中定义它们。

代码可以简化为:

var ext = Path.GetExtension(filename);
var imageExtensions=new[]{".jpg",".jpeg",".png",".gif",".bmp"};
var isimage = imageExtensions.Contains(ext);

var request = (FtpWebRequest)WebRequest.Create("ftp://someurl.com/Folder1/test1.jpg");

request.UseBinary =isimage;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.ConnectionGroupName = "Group1";
request.ServicePoint.ConnectionLimit = 4;

//These are the credentials.
request.Credentials = new NetworkCredential("username", "password");

using(var sourceStream = File.OpenRead(filename))
using(var requestStream = await request.GetRequestStreamAsync())
{
    await sourceStream.CopyToAsync(requestStream);
}

using(var responseWeb = await request.GetResponseAsync())
{
    var response = (FtpWebResponse)responseWeb;
    if (response.StatusDescription.Contains("226"))
    {
         return true;
    }
}
.....

我删除了 KeepAliveUsePassive 设置器,因为 true 是它们的默认值。

WebRequest 本身不包含任何资源,因此它不实现 IDisposable。调用GetRequestStream() 时会建立与服务器的连接。需要处理/关闭的值是sourceStreamrequestStreamresponseWeb

【讨论】:

  • 太好了,谢谢你告诉我这是怎么做的!我想知道我能看到 sourceStreamrequestStream 正在使用 using 语句。 responserequest,我在代码中看不到它们使用后的 .Close() 吗?我错过了那里的东西还是不应该关闭它们?
  • 这就是using 的意义所在。当执行退出using 块的范围时,它会在这些对象上调用Dispose()Dispose 又调用Close()。如果需要,您可以提前致电Close(),但using 确保流和响应无论如何都会关闭
  • 是的,我明白了,所以requestresponseClose() 因为他们参与使用语句? (我在 FTP 方面有点糟糕,Signomi :))
  • 我只提到“响应”会Close(),因为它在 using 语句中。
猜你喜欢
  • 2011-09-12
  • 1970-01-01
  • 2022-12-07
  • 2022-10-19
  • 1970-01-01
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多