2011-03-11 81 views
1

ForEach擴展方法的問題在對ASP.Net(4.0)Request.Files(上傳)集合進行一些基本驗證時,我決定嘗試使用LINQ。通過IEnumerable <Request.Files>

收集是IEnumerable<T>,所以不提供ForEach。愚蠢地,我決定建立一個可以完成這項工作的擴展方法。遺憾地說,沒有那麼多成功...

運行擴展方法(下)提出了一個錯誤:

Unable to cast object of type 'System.String' to type 'System.Web.HttpPostedFile'

很明顯的東西,我沒有得到,但我看不出它是什麼,所以冒着看起來像一個白癡(不會是第一次)的風險,這裏是3個代碼塊的代碼,以及對任何幫助的感謝諾言。

首先,擴展方法與操作參數:

//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; 
} 

當內部foreach循環擊中在「源」的「項目」,將出現錯誤。

下面是調用代碼(變量MaxFileTries和attachPath正確預先設定的):

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)); 

最後,行動目標,保存上傳文件 - 我們不會出現,甚至曾經到這裏,但爲了以防萬一,在這裏它是:

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; 
} 

我承認,有些上面是一個拼湊「中位」的,所以我會得到我應得的,但如果任何人有一個很好的理解(或者至少已經完成了),也許我可以學到一些東西。

謝謝你。

+0

確定我嘗試這樣做:'Request.Files.Cast ()選擇(文件=>新HttpPostedFileWrapper (file => file.ContentLength> 0 && file.ContentLength <= MaxFileSize && file.FileName.Length> 0).ToList ()。ForEach(file => file.SaveUpload(attachPath, MaxFileTries));'具有相同的結果 – Serexx 2011-03-11 06:46:10

+0

爲什麼你是否需要'ForEach '中的'T'? – Heinzi 2011-03-11 07:19:14

回答

1

爲什麼不在原來的IEnumerable<T>上撥打ToList().ForEach()

+1

大聲笑,我有這麼多的樂趣.... durr ..是的,這可能會解決原來的問題,但我仍然想弄清楚它將如何完成......它變成了一個挑戰;-) – Serexx 2011-03-11 06:30:28

+0

k - 我明白你的意思了。我也在這裏閱讀:http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx - 所以,我不是唯一一個嘗試這一點,辯論似乎生活是否值得。在一天結束時,普通的ForEach循環中的簡單擴展似乎更清晰,但如果要完成它,那麼通用的IEnumerable擴展(請參閱下面的abatishchev的第一個代碼段)似乎是答案。 – Serexx 2011-03-11 07:44:02

0

我想這是你想要

你的類,它擴展HttpFileCollection應該

public static class HttpPostedFileExtension 
    { 
    //Extend ForEach to IEnumerated Files 
    public static void ProcessPostedFiles(this HttpFileCollection source, Func<HttpPostedFile, bool> predicate, Action<HttpPostedFile> action) 
    { 
     foreach (var item in source.AllKeys) 
     { 
     var httpPostedFile = source[item]; 
     if (predicate(httpPostedFile)) 
      action(httpPostedFile); 
     } 
    } 
    } 

什麼,那麼你可以使用它像這樣:

Request.Files.ProcessPostedFiles(
    postedFile => 
    { 
    return (postedFile.ContentLength > 0 && postedFile.FileName.Length > 0);  
    }, 
    pFile => 
    { 
    //Do something with pFile which is an Instance of HttpPosteFile 
    }); 
+0

謝謝!我想我明白這一點,但在你檢查內容長度之前,你給的用法是不會爲每個'文件'執行Request.Files.PostedFiles()?如果是這樣,那麼擴展方法不能真正執行保存..或者我錯過了什麼? – Serexx 2011-03-11 07:02:04

+0

@Serexx,好吧,我想我會得到你想要做的。等一下,我會用新的代碼編輯我的答案。 – 2011-03-11 07:38:16

+0

@Shiv @Serexx如何在'Request.Files'包含多於一個項目時重現場景? – abatishchev 2011-03-11 08:14:48

0

首先,寫一個共同的擴展方法:

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    foreach (T item in source) 
     action(item); 
    return source; // or void, without return 
} 

然後,Request.Files是強制轉換爲IEnumerable<string>,不IEnumerable<HttpPostedFile>

IEnumerable<string> requestFiles = this.Request.Files.Cast<string>(); 

但確實System.Web.UI.WebControls.FileUpload.PostedFileHttpPostedFile

HttpPostedFile file = fileUpload.PostedFile; 
HttpPostedFileWrapper wrapper = new HttpPostedFileWrapper(file); 

但它是單一的,不是一個集合。你從哪裏得到你的收藏?


另一種擴展方法:

public static IEnumerable<HttpPostedFile> ToEnumerable(this HttpFileCollection collection) 
{ 
    foreach (var item in collection.AllKeys) 
    { 
     yield return collection[item]; 
    } 
} 

用法:

IEnumerable<HttpPostedFile> files = this.Request.Files.ToEnumerable(); 
IEnumerable<HttpPostedFileWrapper> wrappers = files.Select(f => new HttpPostedFileWrapper(f)); 
+0

好吧,通用擴展現在對我來說更有意義,但HttpPostedFile在我的委託函數中有我需要的屬性。該集合是Request.Files集合。其實我讀了這裏:http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx 看起來像你的通用擴展是答案,但附加到集合。 – Serexx 2011-03-11 07:36:10

+0

@Serexx @abatishchev爲什麼通用方法可以工作,但另一個不能工作 – Midhat 2011-03-11 07:53:53

+0

@Midhat:請詳細說明您的問題 – abatishchev 2011-03-11 08:00:11

相關問題