c# - 从 Xamarin Android 应用程序崩溃将大文件上传到 WCF
问题描述
我正在尝试从我的 xamarin 应用程序上传一个大视频(1 GB+),一旦它达到我的文件的大约 0.5 GB,它就会不断崩溃。我发现在发送数据的同时将视频发布到我的 WCF 服务的唯一方法是使用 MultiPart 逻辑,但我不确定我是否内存不足或什么原因,因为即使在调试模式下,它只是崩溃而没有任何真正的错误消息。
我正在尝试在本机设备(不是 sim)上运行它,它是带有 Android 9 的三星 Galaxy S9。
这是我正在使用的上传代码:(ps - 作为测试,我尝试将 WriteAsync 放入 for 循环中,认为可能尝试编写整个演出是问题,但结果是一样的。这就是为什么你会看到那里的 MAXFILESIZEPART 常量,它只是一个等于 10000000 的整数。)
private async Task<byte[]> GetMultipartFormDataAsync(Dictionary<string, object> postParameters, string boundary)
{
try
{
using (Stream formDataStream = new System.IO.MemoryStream())
{
bool needsCLRF = false;
foreach (var param in postParameters)
{
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
await formDataStream.WriteAsync(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n"));
needsCLRF = true;
if (param.Value is FileParameter)
{
FileParameter fileToUpload = (FileParameter)param.Value;
// Add just the first part of this param, since we will write the file data directly to the Stream
string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
fileToUpload.FileName ?? param.Key,
fileToUpload.ContentType ?? "application/octet-stream");
await formDataStream.WriteAsync(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
// Write the file data directly to the Stream, rather than serializing it to a string.
if (fileToUpload.File.Length > MAXFILESIZEPART)
{
for (var i = 0; i < fileToUpload.File.Length; i += MAXFILESIZEPART)
{
var len = i + MAXFILESIZEPART > fileToUpload.File.Length
? fileToUpload.File.Length - i
: MAXFILESIZEPART;
await formDataStream.WriteAsync(fileToUpload.File, i, len);
}
}
else
{
await formDataStream.WriteAsync(fileToUpload.File, 0, fileToUpload.File.Length);
}
}
else
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
boundary,
param.Key,
param.Value);
await formDataStream.WriteAsync(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData));
}
}
// Add the end of the request. Start with a newline
string footer = "\r\n--" + boundary + "--\r\n";
await formDataStream.WriteAsync(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer));
// Dump the Stream into a byte[]
formDataStream.Position = 0;
byte[] formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
return formData;
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
它最终在下一行失败了
await formDataStream.WriteAsync(fileToUpload.File, i, len);
但只有在某个点(大约 500MB)之后,所以我假设这是一个内存问题,但事实并非如此。有没有更好的方法来完成这项任务?我这样做是为了在上传时记录进度。我正在尝试完成类似于通过 facebook 应用程序上传大型视频的操作,以便在您继续工作时它会在后台上传。它在处理较小的文件(即 - < 500 MB)时效果很好,但这是我第一次尝试一个几乎是 gig 的文件。
注意:这发生在它开始向服务器发布任何内容之前,因此它与 IIS 或 WCF 无关。此代码仅将字节写入内存流就会崩溃。
有什么建议么?
谢谢!
解决方案
根据你的描述,服务会在某个时间点停止,并且因为你传输的文件是1G左右,很可能是sendtimeout。在指定时间内没有传输完成,导致异常。SendTimeout指定了多长时间写操作必须在超时之前完成。默认值为 1 分钟。
我在我的配置文件中将sendtimeout设置为15秒。如果数据耗时超过15秒,就会出现异常。您可以将其设置为更高的值以避免超时和异常。
有关 sendtimeout 的信息,请参阅以下链接:
更新
我认为可能是内存溢出问题。大文件可能导致内存溢出,无法同时读取。
您可以参考以下链接获取解决方案
推荐阅读
- javascript - JS 可调整大小的 div
- android - 根本不在 Android 中缓存 Firebase 数据库的特定部分
- aws-cdk - aws-cdk 文档 - elbv2
- android - Google 驱动器 file.getId() 仅在发布版本时为空
- c - 'sizeof' 对不完整类型问题的无效应用
- php - IIS 10 应用程序池停止响应 PHP REST API
- vuejs2 - 如何在 Vue 2 中计算数字
- php - 向 preg_replace_callback 模式添加额外的匹配
- c# - 如何使用亚马逊 MWS API 下载亚马逊报告
- json - Avro 编码二进制文件