从 Xamarin Android 应用程序崩溃将大文件上传到 WCF
Posted
技术标签:
【中文标题】从 Xamarin Android 应用程序崩溃将大文件上传到 WCF【英文标题】:Uploading Large Files to WCF from Xamarin Android App Crashes 【发布时间】:2020-09-21 15:01:01 【问题描述】:我正在尝试从我的 xamarin 应用程序上传一个大视频 (1 GB+),一旦达到我的文件的大约 0.5 GB,它就会一直崩溃。我发现在发送数据的同时将视频发布到我的 WCF 服务的唯一方法是使用 MultiPart 逻辑,但我不确定我是内存不足还是什么,因为即使在调试模式下,它只是崩溃而没有任何真正的错误消息。
我正在尝试在本机设备(不是 sim)上运行它,它是搭载 android 9 的三星 Galaxy S9。
这是我正在使用的上传代码:(ps - 作为测试,我尝试将 WriteAsync 放入 for 循环中,认为可能尝试编写整个演出是问题所在,但结果是相同的。那是为什么你会在那里看到 MAXFILESIZEPART 常量,它只是一个等于 10000000 的 int。)
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\n2",
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 应用程序上传大型视频的操作,以便在您继续工作时在后台上传。它在处理较小的文件(即 -
注意:这发生在它开始向服务器发布任何内容之前,因此它与 IIS 或 WCF 无关。此代码仅将字节写入内存流就会崩溃。
有什么建议吗?
谢谢!
【问题讨论】:
IIS/WCF 的许多配置设置限制了请求的大小。我建议你看看那些。我还会检查 IIS 日志。 这发生在它开始向服务器发布任何内容之前。此代码在将数据写入内存流时崩溃。 我不确定将 1 GB 的文件作为单个请求传输是否会很好地工作 - 无论您是否修复此特定错误 【参考方案1】:根据你的描述,服务会在某个时间点停止,并且因为你传输的文件是1G左右,很可能是sendtimeout。在指定时间内没有完成传输,导致异常。指定的SendTimeout写操作在超时之前必须完成多长时间。默认值为 1 分钟。
我在我的配置文件中将sendtimeout设置为15秒。如果数据耗时超过15秒,就会出现异常。您可以将其设置为更高的值以避免超时和异常。
有关发送超时的信息,请参考以下链接:
https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.binding.sendtimeout?view=dotnet-plat-ext-3.1
更新
我认为可能是内存溢出问题。大文件可能导致内存溢出,无法同时读取。
解决方法可以参考以下链接
https://docs.microsoft.com/en-us/archive/blogs/johan/are-you-getting-outofmemoryexceptions-when-uploading-large-files
【讨论】:
这发生在它开始向服务器发布任何内容之前。此代码在将数据写入内存流时崩溃。 我更新我的回复,我觉得可能是内存溢出问题。以上是关于从 Xamarin Android 应用程序崩溃将大文件上传到 WCF的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin.Android 应用程序在选中“共享运行时选项”时崩溃
本机 Xamarin.Android 应用程序在发布模式下不断崩溃
Samsung / Android 8.0 Oreo 更新导致应用程序崩溃? (Xamarin.Forms 应用程序)