首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >上载HTTP进度跟踪

上载HTTP进度跟踪
EN

Stack Overflow用户
提问于 2011-11-18 10:40:30
回答 7查看 14.3K关注 0票数 16

我有WPF应用程序,我正在编写,它将文件发布到一个社交网络中。上传本身工作很好,但我想提供一些指示,我有多远与上传。

我尝试了很多方法来做这个:

1) HttpWebRequest.GetStream方法:

代码语言:javascript
复制
using (
 var FS = File.Open(
  localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    long len = FS.Length;
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.Method = "POST";
    request.ProtocolVersion = HttpVersion.Version11;
    request.ContentType = "multipart/form-data; boundary=--AaB03x";
    //predata and postdata is two byte[] arrays, that contains
    //strings for MIME file upload (defined above and is not important)
    request.ContentLength = predata.Length + FS.Length + postdata.Length;
    request.AllowWriteStreamBuffering = false;
    using (var reqStream = request.GetRequestStream())
    {
        reqStream.Write(predata, 0, predata.Length);
        int bytesRead = 0;
        int totalRead = 0;
        do
        {
            bytesRead = FS.Read(fileData, 0, MaxContentSize);
            totalRead += bytesRead;
            reqStream.Write(fileData, 0, bytesRead);
            reqStream.Flush(); //trying with and without this
            //this part will show progress in percents
            sop.prct = (int) ((100*totalRead)/len);
        } while (bytesRead > 0);
        reqStream.Write(postdata, 0, postdata.Length);
    }
    HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
    using (var respStream = responce.GetResponseStream())
    {
        //do things
    }
}

2) WebClient方式(短得多):

代码语言:javascript
复制
void UploadFile (url, localFilePath)
{
    ...
    WebClient client = new WebClient();
    client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadPartDone);
    client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadComplete);
    client.UploadFileAsync(new Uri(url), localFilePath);
    done.WaitOne();

    //do things with responce, received from UploadComplete
    JavaScriptSerializer jssSer = new JavaScriptSerializer();
    return jssSer.Deserialize<UniversalJSONAnswer>(utf8.GetString(UploadFileResponce));
    //so on...
    ...
}

void UploadComplete(object sender, UploadFileCompletedEventArgs e)
{
    UploadFileResponce=e.Result;
    done.Set();
}

void UploadPartDone(object sender, UploadProgressChangedEventArgs e)
{
    //this part expected to show progress
    sop.prct=(int)(100*e.BytesSent/e.TotalBytesToSend);
}

3)偶数TcpClient方式:

代码语言:javascript
复制
using (
 var FS = File.Open(
  localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    long len = FS.Length;
    long totalRead = 0;
    using (var client = new TcpClient(urli.Host, urli.Port))
    {
        using (var clearstream = client.GetStream())
        {
            using (var writer = new StreamWriter(clearstream))
            using (var reader = new StreamReader(clearstream))
            {
                //set progress to 0
                sop.prct = 0;
                // Send request headers
                writer.WriteLine("POST " + urli.AbsoluteUri + " HTTP/1.1");
                writer.WriteLine("Content-Type: multipart/form-data; boundary=--AaB03x");
                writer.WriteLine("Host: " + urli.Host);
                writer.WriteLine("Content-Length: " + (predata.Length + len + postdata.Length).ToString());
                writer.WriteLine();
                //some data for MIME
                writer.Write(utf8.GetString(predata));
                writer.Flush();
                int bytesRead;
                do
                {
                    bytesRead = FS.Read(fileData, 0, MaxContentSize);
                    totalRead += bytesRead;
                    writer.BaseStream.Write(fileData, 0, bytesRead);
                    writer.BaseStream.Flush();
                    sop.prct = (int) ((100*totalRead)/len);
                } while (bytesRead > 0)
                writer.Write(utf8.GetString(postdata));
                writer.Flush();
                //read line of response and do other thigs...
                respStr = reader.ReadLine();
                ...
            }
        }
    }
}

在所有情况下,该文件都已成功地发送到服务器。但是,进度总是这样:在几秒钟内,它从0运行到100,然后等待直到文件真正上传(大约5分钟-文件是400 is )。

因此,我认为文件中的数据是缓冲的,我跟踪的不是上传,而是缓冲数据。然后必须等到上传完毕。

我的问题是:

( 1)是否有任何方法可追踪实际上载的资料?方法Stream.Write()或()(正如我在某个地方看到的,对NetworkStream不起作用)直到收到服务器确认接收到的TCP数据包后才返回。

或者我可以拒绝缓冲(AllowWriteStreamBUffering for HttpWebRequest不起作用)?

( 3)进一步“下跌”并尝试与索克斯合作是否有意义?

更新:

为了避免在UI上显示进度方面的任何疑问,我重写了代码来记录一个文件。下面是代码:

代码语言:javascript
复制
using (var LogStream=File.Open("C:\\123.txt",FileMode.Create,FileAccess.Write,FileShare.Read))
using (var LogWriter=new StreamWriter(LogStream))
using (var FS = File.Open(localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    long len = FS.Length;
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.Timeout = 7200000; //2 hour timeout
    request.Method = "POST";
    request.ProtocolVersion = HttpVersion.Version11;
    request.ContentType = "multipart/form-data; boundary=--AaB03x";
    //predata and postdata is two byte[] arrays, that contains
    //strings for MIME file upload (defined above and is not important)
    request.ContentLength = predata.Length + FS.Length + postdata.Length;
    request.AllowWriteStreamBuffering = false;
    LogWriter.WriteLine(DateTime.Now.ToString("o") + " Start write into request stream. ");
    using (var reqStream = request.GetRequestStream())
    {
        reqStream.Write(predata, 0, predata.Length);
        int bytesRead = 0;
        int totalRead = 0;
        do
        {
            bytesRead = FS.Read(fileData, 0, MaxContentSize);
            totalRead += bytesRead;
            reqStream.Write(fileData, 0, bytesRead);
            reqStream.Flush(); //trying with and without this
            //sop.prct = (int) ((100*totalRead)/len); //this part will show progress in percents
            LogWriter.WriteLine(DateTime.Now.ToString("o") + " totalRead= " + totalRead.ToString() + " / " + len.ToString());
        } while (bytesRead > 0);
        reqStream.Write(postdata, 0, postdata.Length);
    }
    LogWriter.WriteLine(DateTime.Now.ToString("o") + " All sent!!! Waiting for responce... ");
    LogWriter.Flush();
    HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
    LogWriter.WriteLine(DateTime.Now.ToString("o") + " Responce received! ");
    using (var respStream = responce.GetResponseStream())
    {
        if (respStream == null) return null;
        using (var streamReader = new StreamReader(respStream))
        {
            string resp = streamReader.ReadToEnd();
            JavaScriptSerializer jssSer = new JavaScriptSerializer();
            return jssSer.Deserialize<UniversalJSONAnswer>(resp);
        }
    }
}

这就是结果(我切中间):

代码语言:javascript
复制
2011-11-19T22:00:54.5964408+04:00 Start write into request stream. 
2011-11-19T22:00:54.6404433+04:00 totalRead= 1048576 / 410746880
2011-11-19T22:00:54.6424434+04:00 totalRead= 2097152 / 410746880
2011-11-19T22:00:54.6434435+04:00 totalRead= 3145728 / 410746880
2011-11-19T22:00:54.6454436+04:00 totalRead= 4194304 / 410746880
2011-11-19T22:00:54.6464437+04:00 totalRead= 5242880 / 410746880
2011-11-19T22:00:54.6494438+04:00 totalRead= 6291456 / 410746880
.......    
2011-11-19T22:00:55.3434835+04:00 totalRead= 408944640 / 410746880
2011-11-19T22:00:55.3434835+04:00 totalRead= 409993216 / 410746880
2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
2011-11-19T22:00:55.3464837+04:00 All sent!!! Waiting for responce... 
2011-11-19T22:07:23.0616597+04:00 Responce received! 

正如你所看到的,程序认为它上传了大约2秒钟的~400 as。而7分钟后,文件实际上上传,我收到了响应。

再次更新:

这似乎发生在WIndows 7下(而不是关于x64或x86的shure )。当我运行我的代码uder XP时,一切都工作得很完美,进度显示是绝对正确的。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-12-07 19:04:51

这个问题发布已经一年多了,但我认为我的帖子对某人是有用的。

我在展示进步方面也有同样的问题,它的表现与你所描述的完全一样。因此,我决定使用HttpClient,它可以正确显示上传进度。然后,我遇到了有趣的bug --当我启动Fiddler时,HttpClient开始以意想不到的方式显示它的上传进度,就像上面的WebClient/HttpWebRequest那样,所以我想这可能是WebClient显示上传进度不正确的一个问题(我想我已经启动了)。因此,我再次尝试使用WebClient (没有推出类似于摆弄的应用程序),而且所有的程序都能正常工作,上传进度具有正确的价值。我已经用win7和XP在几台PC上进行了测试,在所有情况下进展都是正确的。

因此,我认为像Fiddler这样的程序(可能不仅仅是一个小提琴)对WebClient和其他.net类显示上传进度有一定的影响。

这一讨论核准了以下内容:

HttpWebRequest doesn't work except when fiddler is running

票数 4
EN

Stack Overflow用户

发布于 2011-12-13 15:59:38

您可以使用WebClientUploadFile上传文件,而不是使用写入文件作为文件流。为了跟踪接收和上传的数据的百分比,可以使用UploadFileAsyn并订阅其事件。

在下面的代码中,我使用了UploadFileAsyn来同步上传文件,但只要不释放上传器的实例,它就不需要是同步的。

代码语言:javascript
复制
class FileUploader : IDisposable
{
    private readonly WebClient _client;
    private readonly Uri _address;
    private readonly string _filePath;
    private bool _uploadCompleted;
    private bool _uploadStarted;
    private bool _status;

    public FileUploader(string address, string filePath)
    {
        _client = new WebClient();
        _address = new Uri(address);
        _filePath = filePath;
        _client.UploadProgressChanged += FileUploadProgressChanged;
        _client.UploadFileCompleted += FileUploadFileCompleted;
    }

    private void FileUploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        _status = (e.Cancelled || e.Error == null) ? false : true;
        _uploadCompleted = true;
    }

    private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        if(e.ProgressPercentage % 10 == 0)
        {
            //This writes the pecentage data uploaded and downloaded
            Console.WriteLine("Send: {0}, Received: {1}", e.BytesSent, e.BytesReceived);
            //You can have a delegate or a call back to update your UI about the percentage uploaded
            //If you don't have the condition (i.e e.ProgressPercentage % 10 == 0 )for the pecentage of the process 
            //the callback will slow you upload process down
        }
    }

    public bool Upload()
    {

        if (!_uploadStarted)
        {
            _uploadStarted = true;
            _client.UploadFileAsync(_address, _filePath);
        }
        while (!_uploadCompleted)
        {
            Thread.Sleep(1000);
        }
        return _status;
    }

    public void Dispose()
    {
        _client.Dispose();
    }
}

客户代码:

代码语言:javascript
复制
            using (FileUploader uploader = new FileUploader("http://www.google.com", @"C:\test.txt"))
        {
            uploader.Upload();
        }

您可以在FileUploadProgressChanged事件处理程序上注册自定义回调(可能是委托),以更新WPF UI。

如果您对事件的回调做了任何IO操作,则会更频繁地调用上传进度更改事件,这将减缓下载进度。最好是不经常更新,例如,下面的代码更新只增加了10%。

代码语言:javascript
复制
    private int _percentageDownloaded;

    private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        if (e.ProgressPercentage % 10 == 0 && e.ProgressPercentage > _percentageDownloaded)
        {

            _percentageDownloaded = e.ProgressPercentage;
            //Any callback instead of printline
            Console.WriteLine("Send: {0} Received: {1}", e.BytesSent, e.BytesReceived);
        }
    }
票数 3
EN

Stack Overflow用户

发布于 2012-11-16 15:45:38

我的建议是使用新的HTTPClient类( .NET 4.5中提供)。它支持取得进展。

这篇文章对我帮助很大:http://www.strathweb.com/2012/06/drag-and-drop-files-to-wpf-application-and-asynchronously-upload-to-asp-net-web-api/

我的上传文件代码:

代码语言:javascript
复制
    private void HttpSendProgress(object sender, HttpProgressEventArgs e)
    {
        HttpRequestMessage request = sender as HttpRequestMessage;
        Console.WriteLine(e.BytesTransferred);
    }

    private void Window_Loaded_1(object sender, RoutedEventArgs e)
    {
        ProgressMessageHandler progress = new ProgressMessageHandler();
        progress.HttpSendProgress += new EventHandler<HttpProgressEventArgs>(HttpSendProgress);

        HttpRequestMessage message = new HttpRequestMessage();
        StreamContent streamContent = new StreamContent(new FileStream("e:\\somefile.zip", FileMode.Open));

        message.Method = HttpMethod.Put;
        message.Content = streamContent;
        message.RequestUri = new Uri("{Here your link}");

        var client = HttpClientFactory.Create(progress);

        client.SendAsync(message).ContinueWith(task =>
        {
            if (task.Result.IsSuccessStatusCode)
            { 

            }
        });
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8181114

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档