ASP.NET MVC – File sharing and downloading from another server

Conditions:
We have 2 servers, Server A and B. Admin site is loaded on Server A and we need to share files which are uploaded from the admin site.
Classic ASP does not get a file from other or network drive. So, I decided to write files to Server A and B seperate.
Then classic ASP can load the file.

Preperation:
1. Create folders on both servers
2. Create local users on both servers and the users’ name and password must be same. Windows systems only check user name and password without server or domain name. In other words, there are users which are same id and password on different computers, and all users can access to other computers without credential. It is automatically passed through.
3. Grant read/write permissions to the users.

Implementation:
1. Configuration
a. add below to web.config

<identity impersonate=”true” userName=”USERID” password=”PASSWORD” />

<httpRuntime executionTimeout=”240″ maxRequestLength=”20480″ />
2. Write
3. Read

Issue: I’m on the admin site and trying to download a file which are placed on the other server. (local files are working fine.)


Event Type: Error
Event Source: ASP.NET 2.0.50727.0
Event Category: None
Event ID: 1194
Date: 8/24/2011
Time: 4:48:00 PM
User: N/A
Computer: _servername
Description:
TransmitFile failed. File Name: \\_path\_filename.pdf, Impersonation Enabled: 0, Token Valid: 1, HRESULT: 0x8007052e

My code looks like below


public ActionResult Download(string category, int id)
{
    DataRepository _repository = new DataRepository();
    Item item = _repository.getItem(id);

    string _filename = item.fileName;
    string _filepath;
    if (category.Equals("A"))
        _filepath = ConfigurationSettings.AppSettings["ServerA"];
    else
        _filepath = ConfigurationSettings.AppSettings["ServerB"];
    string _fullpath = Path.Combine(_filepath, _filename);

    FileInfo file = new FileInfo(_fullpath);

    Response.Clear();
    if (file.Exists)
    {
        return File(_filepath, "octet/stream", HttpUtility.UrlEncode(_filename, System.Text.Encoding.UTF8));
    }
    else
    {
        Response.Write("File not found.");
        Response.End();
        return null;
    }
}

Solution:
It needs to have Response.End();.
So, I decided to add more codes as I’ve done before. Then, it’s resolved.


public ActionResult Download(string category, int id)
{
    DataRepository _repository = new DataRepository();
    Item item = _repository.getItem(id);

    string _filename = item.fileName;
    string _filepath;
    if (category.Equals("A"))
        _filepath = ConfigurationSettings.AppSettings["ServerA"];
    else
        _filepath = ConfigurationSettings.AppSettings["ServerB"];
    string _fullpath = Path.Combine(_filepath, _filename);

    FileInfo file = new FileInfo(_fullpath);

    Response.Clear();
    if (file.Exists)
    {
        //return File(_filepath, "octet/stream", HttpUtility.UrlEncode(_filename, System.Text.Encoding.UTF8));
        fileDownload(_filename, _filepath);
    }
    else
        Response.Write("File not found.");
    Response.End();
    return null;
}

private void fileDownload(string _filename, string _filepath)
{
    bool success = ResponseFile(_filename, _filepath, 1024000);
    if (!success)
        Response.Write("Downloading error.");
}

private void ResponseFile(string _filename, string _filepath, long _speed)
{
    try
    {
        FileStream fs = new FileStream(_filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        BinaryReader br = new BinaryReader(fs);
        
        try
        {
            Response.AddHeader("Accept-Ranges", "bytes");
            Response.Buffer = false;
            long fileLength = fs.Length;
            long startBytes = 0;
            
            int pack = 10240;       // 10K bytes
            int sleep = (int)Math.Floor((double)(1000 * pack / _speed)) + 1;
            if (Request.Headers["Range"] != null)
            {
                Response.StatusCode = 206;
                string[] range = Request.Headers["Range"].Split(new char[] {'=', '-'});
                startBytes = Convert.ToInt64(range[1]);
            }
            Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
            if (startBytes != 0)
                Response.AddHeader("Content-Range", string.Format(" byte {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
                
            Response.AddHeader("Connection", "Keep-Alive"); 
            Response.ContentType = "application/octet-stream"; 
            Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_filename, System.Text.Encoding.UTF8)); 

            br.BaseStream.Seek(startBytes, SeekOrigin.Begin); 
            int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1; 

            for (int i = 0; i < maxCount; i++) 
            { 
                if (Response.IsClientConnected) 
                { 
                    Response.BinaryWrite(br.ReadBytes(pack)); 
                    Thread.Sleep(sleep); 
                } 
                else 
                { 
                    i = maxCount; 
                } 
            } 
        } 
        catch 
        { 
            return false; 
        } 
        finally 
        { 
            br.Close(); 
            fs.Close(); 
        }
    }
    catch
    {
        return false;
    }
    
    return true;
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s