While doing some basic validation on the ASP.Net (4.0) Request.Files (upload) collection I decided to try it with LINQ.
The collection is IEnumerable<T> and so doesn’t offer ForEach. Foolishly I decided to build an extension method that would do the job. Sorry to say not so much success…
Running the extension method (below) raises next error:
Unable to cast object of type ‘System.String’ to type ‘System.Web.HttpPostedFile’
There is clearly something I am not getting, but I can’t see what it is, so at the risk of looking like an idiot (wont be the first time) here is the code in 3 chunks, along with a promise of gratitude for any help.
First, the extension method with an Action parameter:
//Extend ForEach to IEnumerated Files
public static IEnumerable<HttpPostedFileWrapper> ForEach<T>(this IEnumerable<HttpPostedFileWrapper> source, Action<HttpPostedFileWrapper> action)
{
//breaks on first 'item' init
foreach (HttpPostedFileWrapper item in source)
action(item);
return source;
}
The error occurs when the internal foreach loop hits the ‘item’ in ‘source’.
Here is the calling code (variables MaxFileTries and attachPath are properly set previously) :
var files = Request.Files.Cast<HttpPostedFile>()
.Select(file => new HttpPostedFileWrapper(file))
.Where(file => file.ContentLength > 0
&& file.ContentLength <= MaxFileSize
&& file.FileName.Length > 0)
.ForEach<HttpPostedFileWrapper>(f => f.SaveUpload(attachPath, MaxFileTries));
And lastly, the Action target, Saving the upload file – we don’t appear to ever even get to here, but just in case, here it is:
public static HttpPostedFileWrapper SaveUpload(this HttpPostedFileWrapper f, string attachPath, int MaxFileTries)
{
// we can only upload the same file MaxTries times in one session
int tries = 0;
string saveName = f.FileName.Substring(f.FileName.LastIndexOf("\\") + 1); //strip any local
string path = attachPath + saveName;
while (File.Exists(path) && tries <= MaxFileTries)
{
tries++;
path = attachPath + " (" + tries.ToString() + ")" + saveName;
}
if (tries <= MaxFileTries)
{
if (!Directory.Exists(attachPath)) Directory.CreateDirectory(attachPath);
f.SaveAs(path);
}
return f;
}
I confess that some of the above is a cobbling together of “bits found”, so I am likely getting what I deserve, but if anyone has a good understanding of (or has at least been through) this, maybe I can learn something.
Thanks for any.
Why don’t you just call
ToList().ForEach()on the originalIEnumerable<T>.