I maintain an application that has a method in a class for saving uploaded files to filesystem and I want to run asynchronously as it saves multiple files in a single request. I don't know if it's best to use Task.FromResult or Task.Run, but I've modifed the code to use Task.FromResult.
public class AttachmentProcessor
{
public static Task<IEnumerable<Attachment>> SaveAttachmentsToFileSystemAsync(IEnumerable<HttpPostedFileBase> files,
string cOfONumber)
{
if (files == null)
return Task.FromResult(Enumerable.Empty<Attachment>());
string topFolderPath = AppDomain.CurrentDomain.BaseDirectory + "Attachments\\";
string folderName = cOfONumber;
var directory = topFolderPath + folderName;
string folderPath = directory + "\\";
var attachments = new List<Attachment>();
DirectoryInfo subFolder = Directory.CreateDirectory(directory);
foreach (HttpPostedFileBase file in files)
{
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
if (!string.IsNullOrEmpty(fileName))
{
// file is saved to path
file.SaveAs(folderPath + fileName);
attachments.Add(new Attachment
{
CofONumber = cOfONumber,
FileName = fileName,
File = folderPath + fileName
});
}
}
}
return Task.FromResult(attachments.AsEnumerable());
}
}
And the calling code:
[HttpPost]
public async Task<ActionResult> Index(AttachmentViewModel model)
{
if (ModelState.IsValid)
{
try
{
var attachments = await AttachmentProcessor.SaveAttachmentsToFileSystemAsync(model.Others, model.CofONumber).ConfigureAwait(false);
_repository.InsertEntities(attachments.ToList());
_unitOfWork.Save();
return RedirectToAction("Index", "Home");
}
catch (Exception)
{
ModelState.AddModelError("", "Unable to save data");
}
}
return View(new AttachmentViewModel() { CofONumber = model.CofONumber});
}
My other thoughts are: calling Task.Run() within SaveAttachmentsToFileSystemAsync
method
public static async Task<IEnumerable<Attachment>> SaveAttachmentsToFileSystemAsync(IEnumerable<HttpPostedFileBase> files,
string cOfONumber)
{
if (files == null) return null;
var task = Task.Run(() =>
{
string topFolderPath = AppDomain.CurrentDomain.BaseDirectory + "Attachments\\";
string folderName = cOfONumber.Replace(@"/", "_");
var directory = topFolderPath + folderName;
string folderPath = directory + "\\";
var attachments = new List<Attachment>();
DirectoryInfo subFolder = Directory.CreateDirectory(directory);
foreach (HttpPostedFileBase file in files)
{
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
if (!string.IsNullOrEmpty(fileName))
{
// file is saved to path
file.SaveAs(folderPath + fileName);
attachments.Add(new Attachment
{
CofONumber = cOfONumber,
FileName = fileName,
File = folderPath + fileName
});
}
}
}
return attachments;
});
return await task;
}
Or leaving it synchronous as it is and using Task.Run from the calling code:
public static IEnumerable<Attachment> SaveAttachmentsToFileSystemAsync(IEnumerable<HttpPostedFileBase> files,
string cOfONumber)
{
if (files == null) return null;
string topFolderPath = AppDomain.CurrentDomain.BaseDirectory + "Attachments\\";
string folderName = cOfONumber.Replace(@"/", "_");
var directory = topFolderPath + folderName;
string folderPath = directory + "\\";
var attachments = new List<Attachment>();
DirectoryInfo subFolder = Directory.CreateDirectory(directory);
foreach (HttpPostedFileBase file in files)
{
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
if (!string.IsNullOrEmpty(fileName))
{
// file is saved to path
file.SaveAs(folderPath + fileName);
attachments.Add(new Attachment
{
CofONumber = cOfONumber,
FileName = fileName,
File = folderPath + fileName
});
}
}
}
return attachments;
}
//And using Task.Run from the controller
[HttpPost]
public async Task<ActionResult> Index(AttachmentViewModel model)
{
if (ModelState.IsValid)
{
try
{
var attachments = await Task.Run(() => AttachmentProcessor.meT(model.Others, model.CofONumber));
_repository.InsertEntities(attachments.ToList());
_unitOfWork.Save();
return RedirectToAction("Index", "Home");
}
catch (Exception)
{
ModelState.AddModelError("", "Unable to save data");
}
}
return View(new AttachmentViewModel() { CofONumber = model.CofONumber });
}
Task.Run Parallel.ForEach
combination orTask.WhenAll
.. however, there are likely some IO File writting Async Methods \$\endgroup\$