File download in chunks in http-context response C#

916 views Asked by At

I have a below scenario.

Client send request to Server-1 for file download Server-1 send request to Server-2 for file.

To make this work I need to create a mechanism where once client send request to the Server-1, Server-1 will request to Server-2 which will send file as response output-stream in chunks. Server-1 will send this file chunks to client browser continuously as it keep receiving from server-2.

I have done code as below, theoretically it looks fine but still it is not working. It is not downloading entire file in client browser, it seems like last chunk is not transferred to the Server-1 or it is not downloading to client browser from Server-1

Server-1 Code (Where client request for File download)

    private void ProccesBufferedResponse(HttpWebRequest webRequest, HttpContext context)
    {
        char[] responseChars = null;
        byte[] buffer = null;

        if (webRequest == null)
            logger.Error("Request string is null for Perfios Docs Download at ProccesBufferedResponse()");

        context.Response.Buffer = false;
        context.Response.BufferOutput = false;
        try
        {

            WebResponse webResponse = webRequest.GetResponse();
            context.Response.ContentType = "application/pdf";
            context.Response.AddHeader("Content-disposition", webResponse.Headers["Content-disposition"]);

            StreamReader responseStream = new StreamReader(webResponse.GetResponseStream());
            while (!responseStream.EndOfStream)
            {
                responseChars = new char[responseStream.ToString().ToCharArray().Length];
                responseStream.Read(responseChars, 0, responseChars.Length);
                buffer = Encoding.ASCII.GetBytes(responseChars);

                context.Response.Clear();
                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
                context.Response.Flush();

            }

        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            context.Response.Flush();
            context.Response.End();
        }
    }

Server-2 Code (Where Server-1 will send request for file)

    private void DownloadInstaPerfiosDoc(int CompanyID, string fileName, string Foldertype)
    {
        string folderPath;
        string FilePath;
        int chunkSize = 1024;
        int startIndex = 0;
        int endIndex = 0;
        int length = 0;
        byte[] bytes = null;
        DirectoryInfo dir;

        folderPath = GetDocumentDirectory(CompanyID, Foldertype);
        FilePath = folderPath + "\\" + fileName;
        dir = new DirectoryInfo(folderPath);
        HttpContext.Current.Response.Buffer = false;
        HttpContext.Current.Response.BufferOutput = false;

        if (dir.Exists && dir.GetFiles().Length > 0)
        {
            foreach (var file in dir.GetFiles(fileName))
            {
                FilePath = folderPath + "\\" + file.Name;
                FileStream fsReader = new FileStream(FilePath, FileMode.Open, FileAccess.Read);

                HttpContext.Current.Response.ContentType = "application/pdf";
                HttpContext.Current.Response.AddHeader("Content-disposition", string.Format("attachment; filename = \"{0}\"", fileName));

                int totalChunks = (int)Math.Ceiling((double)fsReader.Length / chunkSize);
                for (int i = 0; i < totalChunks; i++)
                {
                    startIndex = i * chunkSize;

                    if (startIndex + chunkSize > fsReader.Length)
                        endIndex = (int)fsReader.Length;
                    else
                        endIndex = startIndex + chunkSize;

                    length = (int)endIndex - startIndex;
                    bytes = new byte[length];
                    fsReader.Read(bytes, 0, bytes.Length);
                    HttpContext.Current.Response.Clear();
                    HttpContext.Current.Response.OutputStream.Write(bytes, 0, bytes.Length);
                    HttpContext.Current.Response.Flush();
                }
            }
        }
    }

Please help me to resolve this issue.

1

There are 1 answers

2
Tolga Evcimen On

It is possible and feasible. I'll give a pseudo procedure for you to understand the overall idea.

Server1

download action gets hit
create a request to server2
get the response stream of your server2 request
read the response stream in desired chunk sizes until it's consumed completely
write each chunk (as soon as you read) to current response stream

Server2

download action gets hit
write your stream onto your current response stream however you like