Brian Hvarregaard
Brian Hvarregaard

Reputation: 4209

Problem with multithreading concurrency in file download in web service

I have a asmx web service that is used to download files to clients. My method for downloading is shown below:

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

My problem is that when i stress it with 100 simultaneous users downloading i get an exception:

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

(file names obscured)

Any one know how to solve this concurrency problem, is my lock not proper?

Upvotes: 2

Views: 1740

Answers (3)

Charles Lambert
Charles Lambert

Reputation: 5132

Quick and dirty, use a static private object to use as a lock:

private static object padlock = new object();

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

Your current lock only exists on the instance of the class that was created. New instances of the class are created for every request. My solution has the issue that all files will be read sequentially. I would only look at a different method if this causes performance problems. You will ultimately need to lock on the file name, if you want concurrent access to different files. That may take a bit more work.

Upvotes: 1

Jim Mischel
Jim Mischel

Reputation: 133975

The following will simplify your code, and might solve the problem if it was caused by not disposing of the FileStream:

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

File.ReadAllBytes opens the file with FileAccess.Read and FileShare.Read.

Upvotes: 0

rasmusvhansen
rasmusvhansen

Reputation: 1522

I would guess disposing the FileStream after using it would help.

Try including it in a using block like so:

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

Upvotes: 0

Related Questions