2011-05-02 83 views
2

我有一個用於將文件下載到客戶端的asmx web服務。如下所示我的下載方法:Web服務中文件下載中的多線程併發問題

[WebMethod] 
     public byte[] DownloadFile(int id) 
     {    
      lock (this) 
      { 
       if (id == 0) 
       { 
        throw new ArgumentException("Input value is not valid"); 
       } 
       IGWFileRepository fileRepository = new GWFileRepository(); 
       GWFile file = fileRepository.GetFileById(id); 
       string path = Server.MapPath(RepositoryDir + "/" + file.DiscName); 
       BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read)); 
       reader.BaseStream.Position = 0; 
       byte[] content = reader.ReadBytes(Convert.ToInt32(reader.BaseStream.Length)); 
       reader.Close(); 
       return content; 
      } 
     } 

我的問題是,當我有100個用戶同時下載強調它,我得到一個異常:

Exception: System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.IO.IOException: The process cannot access the file 'C:\Subversion\Repository\cb0a27e2-2d23-43b1-a12e-f07fb401cfc9.jpg' because it is being used by another process. 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath) 
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 
    at System.IO.File.Open(String path, FileMode mode, FileAccess access) 
    at GrenWebRepository.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\RepositoryService.asmx.cs:line 62 
    --- End of inner exception stack trace --- 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) 
    at RepositoryTester.RS.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\Web References\RS\Reference.cs:line 174 
    at RepositoryTester.User.DownloadAction() in C:\Subversion\Repository\RepositoryTester\RepositoryTester\User.cs:line 110 

(文件名稱被遮擋)

任何一個知道如何解決這個併發問題,我的鎖不正確?

+0

其他進程是否有可能更新該.jpg文件?在相關說明中,您不需要'BinaryReader',因爲您可以直接從'FileStream'中讀取。或者,想一想,你可以調用'File.ReadAllBytes'。 – 2011-05-02 17:31:05

+1

關於鎖,通常不是一個好主意(做)鎖,這將是更好的有一個私人鎖定令牌鎖定,因爲這確保鎖不能在課堂以外。 – rasmusvhansen 2011-05-02 17:34:53

回答

1

快速和骯髒的,使用一個靜態的私有對象作爲鎖的使用方法:

private static object padlock = new object(); 

public byte[] DownloadFile(int id) { 
    lock(padlock) { 
     // code here 
    } 
} 

您當前的鎖只存在於已創建的類的實例。每個請求都會創建該類的新實例。我的解決方案存在所有文件將被順序讀取的問題。如果這會導致性能問題,我只會看一個不同的方法。如果你想同時訪問不同的文件,你最終需要鎖定文件名。這可能需要更多的工作。

+0

即使您這樣做,仍然需要處理文件流(或使用File.ReadAllBytes),因爲您無法確定在下次下載開始之前文件句柄已釋放。來自[MSDN] [1]的 – rasmusvhansen 2011-05-03 08:17:19

+0

:「Close的這個實現調用Dispose方法傳遞一個真實值。」 [1] http://msdn.microsoft.com/en-us/library/system.io.binaryreader.close(v = VS.100).aspx – 2011-05-03 14:39:12

0

我想在使用它之後部署FileStream會有所幫助。

嘗試,包括它在使用塊,像這樣:

using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read)) 
{ 
    .... 
} 
0

下面將簡化代碼,並沒有處置的FileStream的,如果它是造成可能會解決這個問題:

string path = Server.MapPath(RepositoryDir + "/" + file.DiscName); 
byte[] content = File.ReadAllBytes(path); 

File.ReadAllBytesFileAccess.ReadFileShare.Read打開文件。