【问题标题】:WebClient upload file errorWebClient上传文件错误
【发布时间】:2010-12-05 07:09:18
【问题描述】:

我正在使用 VSTS 2008 + C# + .Net 3.5 + ASP.Net + IIS 7.0 在客户端开发控制台应用程序以上传文件,并在服务器端使用 aspx 文件接收此文件。

从客户端,我总是注意到(从控制台输出)文件的上传百分比从 1% 增加到 50%,然后突然增加到 100%。有什么想法有什么问题吗?

这是我的客户端代码,

class Program
{
    private static WebClient client = new WebClient();
    private static ManualResetEvent uploadLock = new ManualResetEvent(false);

    private static void Upload()
    {
        try
        {
            Uri uri = new Uri("http://localhost/Default.aspx");
            String filename = @"C:\test\1.dat";

            client.Headers.Add("UserAgent", "TestAgent");
            client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
            client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
            client.UploadFileAsync(uri, "POST", filename);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.StackTrace.ToString());
        }
    }

    public static void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
    {
        Console.WriteLine("Completed! ");
        uploadLock.Set();
    }

    private static void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
    {
        Console.WriteLine (e.ProgressPercentage);
    }

    static void Main(string[] args)
    {
        Upload();

        uploadLock.WaitOne();

        return;
    }
}

这是我的服务器端代码,

    protected void Page_Load(object sender, EventArgs e)
    {
        string agent = HttpContext.Current.Request.Headers["UserAgent"];
        using (FileStream file = new FileStream(@"C:\Test\Agent.txt", FileMode.Append, FileAccess.Write))
        {
            byte[] buf = Encoding.UTF8.GetBytes(agent);
            file.Write(buf, 0, buf.Length);
        }

        foreach (string f in Request.Files.AllKeys)
        {
            HttpPostedFile file = Request.Files[f];
            file.SaveAs("C:\\Test\\UploadFile.dat");
        }
    }

提前致谢, 乔治

【问题讨论】:

    标签: c# .net asp.net webclient


    【解决方案1】:

    这是 WebClient 类中已知的bug。它将在 .NET 4.0 中修复。在此之前,您可以使用HttpWebRequest 来实现此功能。


    更新:这是一个使用同步 HttpWebRequest 上传文件并跟踪进度的示例:

    public sealed class Uploader
    {
        public const int CHUNK_SIZE = 1024; // 1 KB
    
        public void Upload(string url, string filename, Stream streamToUpload, Action<int> progress)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            string boundary = string.Format("---------------------{0}", DateTime.Now.Ticks.ToString("x"));
            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
            request.KeepAlive = true;
    
            using (var requestStream = request.GetRequestStream())
            {
                var header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", boundary, filename);
                var headerBytes = Encoding.ASCII.GetBytes(header);
                requestStream.Write(headerBytes, 0, headerBytes.Length);
    
                byte[] buffer = new byte[CHUNK_SIZE];
                int bytesRead;
                long total = streamToUpload.Length;
                long totalBytesRead = 0;
                while ((bytesRead = streamToUpload.Read(buffer, 0, buffer.Length)) > 0)
                {
                    totalBytesRead += bytesRead;
                    progress((int)(100 * totalBytesRead / total));
                    byte[] actual = new byte[bytesRead];
                    Buffer.BlockCopy(buffer, 0, actual, 0, bytesRead);
                    requestStream.Write(actual, 0, actual.Length);
                }
            }
            using (var response = request.GetResponse()) { }
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var url = "http://localhost:2141/Default.aspx";
            var filename = "1.dat";
            var uploader = new Uploader();
            using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                uploader.Upload(url, filename, fileStream, progress => Console.WriteLine("{0}% of \"{1}\" uploaded to {2}", progress, filename, url));
            }
        }
    }
    

    【讨论】:

    • 使用 HttpWebRequest 可以将进度更改信息作为回调?
    • 更新了我的帖子以包含一个使用 HttpWebRequest 将文件上传到给定 url 并在回调中跟踪进度的示例。
    • 是否需要 byte[] 实际变量?难道你不能只调用 requestStream.Write(buffer, 0, bytesRead) 并避免内存分配和缓冲区复制吗?
    • @GuyIncognito,绝对是,非常好的建议。随意编辑我的帖子并使用此建议进行改进。
    • 我是否遗漏了某些内容,或者是否缺少在最后写出边界的调用?请参阅此处的 RFC:vivtek.com/rfc1867.html
    【解决方案2】:

    您可以阅读webclient.UploadProgressChanged的代码。然后您就会知道原因。代码如下。

    private void PostProgressChanged(AsyncOperation asyncOp, WebClient.ProgressData progress)
      {
          if (asyncOp == null || progress.BytesSent + progress.BytesReceived <= 0L)
              return;
          if (progress.HasUploadPhase)
          {
              int progressPercentage = progress.TotalBytesToReceive >= 0L || progress.BytesReceived != 0L
                  ? (progress.TotalBytesToSend < 0L
                      ? 50
                      : (progress.TotalBytesToReceive == 0L
                          ? 100
                          : (int) (50L*progress.BytesReceived/progress.TotalBytesToReceive + 50L)))
                  : (progress.TotalBytesToSend < 0L
                      ? 0
                      : (progress.TotalBytesToSend == 0L ? 50 : (int) (50L*progress.BytesSent/progress.TotalBytesToSend)));
    
    
    
    
              asyncOp.Post(this.reportUploadProgressChanged,
                  (object)
                      new UploadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState,
                          progress.BytesSent, progress.TotalBytesToSend, progress.BytesReceived,
                          progress.TotalBytesToReceive));
          }
          else
          {
              int progressPercentage = progress.TotalBytesToReceive < 0L
                  ? 0
                  : (progress.TotalBytesToReceive == 0L
                      ? 100
                      : (int) (100L*progress.BytesReceived/progress.TotalBytesToReceive));
              asyncOp.Post(this.reportDownloadProgressChanged,
                  (object)
                      new DownloadProgressChangedEventArgs(progressPercentage, asyncOp.UserSuppliedState,
                          progress.BytesReceived, progress.TotalBytesToReceive));
          }
      }
    

    【讨论】:

      【解决方案3】:

      这种行为是设计使然,它的 50% 上传文件和 50% 的服务器响应。 不是错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-01
        • 2011-01-06
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        相关资源
        最近更新 更多