民间,
我的应用程序存在一个问题,该问题严重影响了该领域的用户,我需要一些帮助。对于上下文:现场用户接收工作票,并且必须在他们处理完票证后使用某些代码和信息对其进行响应。对于任何给定的响应,他们的公司可能需要上传图片(有时是图片)。当用户拍照时,它会保存到Environment.SpecialFolder.MyDocuments
中的目录中。当用户从其图库中选择图片时,它/它们被提取为具有AssetResult
属性的类Image
的对象,然后使用此语句将其转换为NSData
:NSData data = i.AsJPEG(new nfloat(0.8));
,然后随后使用此语句保存:data.Save(picturesPath, true);
我正在使用标题中所述的NSUrlSession
NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(string identifier)
方法。包含NSUrlSession
代码的代码文件名为UploadWrapper
;我做了一个简单的UploadWrapper upload = new UploadWrapper("PolarisPicture")
,"PolarisPicture"
作为会话标识符。
这是我的NSUrlSession配置和实例化的代码/构造函数:
public UploadWrapper (string identifier)
{
using (var config = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(identifier))
{
config.HttpMaximumConnectionsPerHost = 10;
config.TimeoutIntervalForRequest = 600.0;
config.TimeoutIntervalForResource = 120.0;
config.AllowsCellularAccess = true;
bgSession = NSUrlSession.FromConfiguration(config, new UploadDelegate(), new NSOperationQueue());
}
}
以下是用于启动NSUrlSessionUploadTask
的方法:
public void PrepareUpload(string filename, string database, int num, string member, string org, string ticket, string locator, string folder)
{
try
{
Console.WriteLine("PrepareUpload called...");
//var file = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PolarisPictures2/IMAGE.jpeg");
Console.WriteLine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
Console.WriteLine(filename);
var boundary = "FileBoundary";
string webApiAddress = "OURWEBAPI";
NSUrl uploadHandleURL = NSUrl.FromString(webApiAddress);
var bodyPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "BodyData" + num + ".tmp");
NSMutableUrlRequest req = new NSMutableUrlRequest(uploadHandleURL);
req.HttpMethod = "POST";
req["Content-Type"] = "multipart/form-data; boundary=" + boundary;
req["Filename"] = System.IO.Path.GetFileName(filename);
req["database"] = database;
req["folder"] = folder;
req["member"] = member;
req["org"] = org;
req["ticket"] = ticket;
req["locator"] = locator;
Console.WriteLine(req["Filename"]);
if (System.IO.File.Exists(bodyPath))
{
System.IO.File.Delete(bodyPath);
}
Console.WriteLine("Building the string...");
StringBuilder sb = new StringBuilder("");
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"database\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", database)); // Add database param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"member\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", member)); // Add member param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"org\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", org)); // Add org param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"ticket\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", ticket)); // Add ticket param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"locator\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", locator)); // Add locator param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"folder\"\r\n\r\n");
sb.Append(String.Format("{0}\r\n", folder)); // Add folder param
sb.AppendFormat("--{0}\r\n", boundary);
sb.AppendFormat("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\n", System.IO.Path.GetFileName(filename));
sb.Append("Content-Type: application/octetstream\r\n\r\n");
var fileBytes = System.IO.File.ReadAllBytes(filename);
using( var writeStream = new System.IO.FileStream(bodyPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read) )
{
writeStream.Write(Encoding.Default.GetBytes(sb.ToString()), 0, sb.Length);
writeStream.Write(fileBytes, 0, fileBytes.Length);
Console.WriteLine(sb.ToString());
sb.Clear();
sb.AppendFormat("\r\n--{0}--\r\n", boundary);
writeStream.Write(Encoding.Default.GetBytes(sb.ToString()), 0, sb.Length);
writeStream.Close();
writeStream.Dispose();
}
sb = null;
fileBytes = null;
var uploadTask = bgSession.CreateUploadTask(req, NSUrl.FromFilename(bodyPath));
uploadTask.TaskDescription = filename;
Console.WriteLine($"New TaskID: {uploadTask.TaskIdentifier}");
uploadTask.Resume();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
每次在foreach
循环中调用此方法,该循环遍历当前附加的图片。完成此foreach
后,将调用upload.Finish();
,这只不过是调用基础NSUrlSession对象的FinishTasksAndInvalidate()
方法:
foreach (var att in currTick.Origin.GetAttachedFiles(currTick))
{
upload.PrepareUpload(att, info.Database, 0, currTick.Fields["Member"], currTick.Fields["Org"], currTick.Fields["Ticket"], info.FirstName + " " + info.LastName, folder);
index = index + 1;
}
upload.Finish();
att
是“附加”文件的路径。
最后,这是我的DidCompleteWithError()
委托方法以及如果上传成功且没有错误则调用它的方法:
public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError error)
{
Console.WriteLine(string.Format("DidCompleteWithError TaskId: {0}{1}", task.TaskIdentifier, (error == null ? "" : " Error: " + error.Description)));
if (error == null)
{
Console.WriteLine("Deleting the picture copy since the upload succeeded");
DeletePictureCopy(task.TaskDescription);
task.Dispose();
}
}
DeletePictureCopy();
用于删除图片的本地副本以节省空间:
public void DeletePictureCopy(string path)
{
try
{
System.IO.File.Delete(path);
Console.WriteLine("We deleted the copy of the picture successfully!");
} catch( Exception ex )
{
Console.WriteLine(ex.ToString());
}
}
这里可能导致System.IO.IOException: Too many open files
的原因是什么?这是每次PrepareUpload()
方法都会出现的行:
var fileBytes = System.IO.File.ReadAllBytes(filename);
(见上面的代码)
对于我的生活,我不能弄清楚为什么会这样。我甚至关闭用于写FileStream
内部字节的using
只是为了确保它被关闭。
用户上传3到4张图片后会出现此问题。我从来没有在第一张或第二张照片上遇到过这个问题。从不。
延迟后NSUrlSessionUploadTask
关闭文件了吗?垃圾收集器是否未正确处理文件,即使在我手动完成后也是如此?
我无法找到解决方案,并希望得到任何帮助或指导。
感谢。