【发布时间】:2017-03-03 22:51:19
【问题描述】:
我正在制作一个将文件上传到 facebook 的 UWP 应用,我正在使用自定义 HttpContent 以 4k 块的形式上传文件,以最大限度地减少大文件 (>100mb) 的内存使用并报告进度。
我的自定义 HttpContent UploadWithProgressHttpContent:
class UploadWithProgressHttpContent : HttpContent
{
private readonly IProgress<OperationProgress> _progress;
private readonly OperationProgress _data;
private readonly Stream _file;
private readonly int _bufferSize;
private readonly CancellationToken _token;
public UploadWithProgressHttpContent(
IProgress<OperationProgress> progress,
OperationProgress data,
Stream file,
int bufferSize,
CancellationToken token)
{
_progress = progress;
_data = data;
_file = file;
_bufferSize = bufferSize;
_token = token;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return CopyStreamWithProgress(_file, stream, _progress, _token, _data, _bufferSize);
}
public static async Task<Stream> CopyStreamWithProgress(
Stream source,
Stream destination,
IProgress<OperationProgress> progress,
CancellationToken token,
OperationProgress progressData,
int bufferSize
)
{
int read, offset = 0;
var buffer = new byte[bufferSize];
using (source)
{
do
{
read = await source.ReadAsync(buffer, 0, bufferSize, token);
await destination.WriteAsync(buffer, 0, read, token);
offset += read;
progressData.CurrentSize = offset;
progress.Report(progressData);
} while (read != 0);
}
return destination;
}
}
我遇到的(使用提琴手)是整个文件在上传开始之前被放入内存中(我的进度表在上传开始之前就达到了 100%)。
我确实尝试将TransferEncodingChunked 设置为true,并设置文件内容长度,但问题仍然存在。
上传源位于 PCL 内(如果重要)。我正在使用最新版本的System.Net.Http。如果需要,我使用的方式与MediaFire SDK中使用的方式完全相同
感谢您的帮助。
编辑:添加了 HttpClient 用法:
public async Task<T> Upload<T>(Stream fileStream, string fileName)
{
var handler = new HttpClientHandler();
var cli = new HttpClient(handler);
foreach (var header in Headers)
{
cli.DefaultRequestHeaders.Add(header.Key, header.Value);
}
var parameters = new MultipartFormDataContent();
foreach (var parameter in Parameters)
{
parameters.Add(new StringContent(parameter.Value), parameter.Key);
}
if (fileStream != null)
{
var fileContent = new UploadWithProgressHttpContent(ProgressOperation, ProgressData, fileStream,
_chunkBufferSize, Token, fileStream.Length);
fileContent.Headers.ContentType = new MediaTypeHeaderValue(MimeTypeHelper.GetMimeType(fileName));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue(StreamParamName);
fileContent.Headers.ContentDisposition.FileName = fileName;
fileContent.Headers.ContentLength = fileStream.Length;
parameters.Add(fileContent, StreamParamName);
}
var req = new HttpRequestMessage(method, Path) { Content = parameters };
if (fileStream != null)
req.Headers.TransferEncodingChunked = true;
var completionOption = HttpCompletionOption.ResponseContentRead;
var resp = await cli.SendAsync(req, completionOption, Token).ConfigureAwait(false);
return await DeserializeObject<T>(resp);
}
【问题讨论】:
-
我无法使用自定义 HttpContent 解决此问题,我的替代方法是使用 StreamContent,并制作报告读取进度的流装饰器。通过使用 StreamContent HttpClient 流式传输内容而不将其(全部)带到内存中。
-
不完全是,我使用的是自定义 httpcontent,我已经检查了使用流内容是否可以按预期工作,我只是想知道为什么它不适用于自定义 httpcontent,或者如果有什么办法。
-
你能分享一下 HttpClient 周围的代码吗?顺便提一句。我会考虑改用wire Shark(不确定添加fiddler作为http代理是否不会影响流量)。
-
完成,感谢您的帮助!
-
您是否尝试过覆盖 HttpContent.TryComputeLength?
标签: c# uwp httpclient portable-class-library dotnet-httpclient