Web服务中文件下载中的多线程并发问题

时间:2011-05-02 17:22:59

标签: c# asp.net multithreading web-services

我有一个asmx 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

(文件名遮挡)

任何人都知道如何解决这个并发问题,我的锁不正确吗?

3 个答案:

答案 0 :(得分:1)

快速而脏,使用静态私有对象作为锁:

private static object padlock = new object();

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

您当前的锁只存在于已创建的类的实例上。为每个请求创建类的新实例。我的解决方案存在所有文件将按顺序读取的问题。如果这会导致性能问题,我只会看一个不同的方法。如果要同时访问不同的文件,最终需要锁定文件名。这可能需要更多的工作。

答案 1 :(得分:0)

我想在使用它之后处理FileStream会有所帮助。

尝试将其包含在如下的使用块中:

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

答案 2 :(得分:0)

以下内容将简化您的代码,并可能解决问题,如果它是由于不处理FileStream而导致的:

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

File.ReadAllBytes使用FileAccess.ReadFileShare.Read打开文件。