Results 1 to 15 of 15

Thread: [2005] Downloading file

  1. #1

    Thread Starter
    Frenzied Member SomethinCool's Avatar
    Join Date
    Jan 2001
    Location
    Malvern, PA
    Posts
    1,407

    [2005] Downloading file

    I'm trying to download a file from a website and then take this downloaded file and send it to a user as an attachment using e-mail. (SMTP mail using the System.Net.Mail namespace). How can I download the file and attach it? Thanks.

  2. #2
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Re: [2005] Downloading file

    Well, there are several ways to do this.

    The num-num solution would be to simply hold off on sending a response to the client browser until the file is downloaded and e-mailed. Considering that could take anywhere from 5 seconds to 5 hours (depending on file size and network connectivity), you probably don't want to let the browser user sit there in angst staring at an hourglass cursor. This solution could also use Page.RegisterAsync which would at least not bury the rest of your clients' requests in a queue, but of course, still leaves that particular user staring at an empty browser page and an hourglass cursor.

    A second option would be to implement a fire-and-forget operation. The browser user provides the url for the file to download and clicks 'Submit Request', and receives a message stating 'Your request has been submitted. Thank you.' They can then move on to doing other stuff.

    Of course, the user has put blind trust into the web application in actually completing the request. in the grand scheme of things, the success rate is probably close to 99%, provided the URI provided is valid. But, it can always fail some time, and the web application won't have a manner of telling the user, other than perhaps shooting them off an e-mail if the app gathers the sender's e-mail as well the intended recipient.

    Lastly, there's the 'processing request' confirmation, that typically refreshes the browser every 5 seconds to retrieve the status of a request, until it completes or fails. But that's typically reserved for transaction based systems, and would require a little more work.

    So, you have 3 basic options.

    Of course, option 2 ideally has the web app forward the request to a separate process that does all the work. This allows the web app to remain scalable and responsive. Not so ideally, it would use one of its threads in its thread pool to complete the transaction.

    You could implement tokens for tracking with databases in the backend but it all depends on how much you really care that the occasional request doesn't complete.

    Once you decide on a plan of attack, then we can get to writing code with Webclient, HttpWebRequest, or Sockets, or what have you.
    Last edited by nemaroller; Jan 3rd, 2008 at 12:59 AM.

  3. #3
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2005] Downloading file

    Sending the email with attachment won't actually be a problem for you

    Code:
    MailAttachment attachment= new MailAttachment("C:\\abc\\123.txt");
    myEmail.Attachments.Add(attachment);
    But, I'd go with nema's Option 2, sort of. If the URL already exists, don't deal with the intricacies of the third party server, but just provide the link itself and let that website deal with it.

  4. #4

    Thread Starter
    Frenzied Member SomethinCool's Avatar
    Join Date
    Jan 2001
    Location
    Malvern, PA
    Posts
    1,407

    Re: [2005] Downloading file

    I just got it working actually... turns out the path to the attachment file wasn't valid. I thought maybe at first the path was correct on the local machine and turns out it wasnt, so I thought I had to do something special as I thought it was running on the client side. I don't know why I thought that as it was VB code which is server side. I made a mistake.

    But.. I am interested in learning how to do this properly using nema's #2 option... how could I do this using HttpWebRequest or Sockets?

  5. #5
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2005] Downloading file

    It's similar to reading any webpage, but the difference is that you convert the response to a byte array and then write it to a filestream(), which would mean that you save it to your server.

  6. #6
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

  7. #7

    Thread Starter
    Frenzied Member SomethinCool's Avatar
    Join Date
    Jan 2001
    Location
    Malvern, PA
    Posts
    1,407

    Re: [2005] Downloading file

    What exactly is the purpose of converting it to a byte array? Couldn't you just transfer the file using a standard HTTP GET request and download the file that way, or is that pretty much what this is doing by converting it to a bit stream and saving the file?

  8. #8
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2005] Downloading file

    Because the file comes back as a stream. The web does not understand the concept of a 'file' object. Any request on the Internet that goes out always gets a stream as a response. The responding entity will also tell you what the file type is, such as image, text, octet, and so on.

    That's why you have to do it this way.

  9. #9
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Re: [2005] Downloading file

    Here you go.


    Code:
     protected void btnSubmit_Click(object sender, System.EventArgs e)
            {
    
                //we're not going to use your own web application's threadpool, we want our app to 
                //remain responsive, so we use a system thread.
                System.Threading.Thread sendingThread;
    
                Uri sourceUri;
                
                sendingThread = new System.Threading.Thread(SendMailMessage);
                sourceUri = new Uri(txtUrl.Text.Trim());
    
                //here we're just sending the URI to the Thread.Start method, but you would also 
                //want to send the intended recipient's email-address, so you should whip up a small 
                //class that contains both the URI and the recipient address, and convert that
                //on in the SendMailMessage method.
    
                sendingThread.Start(sourceUri);
    
                Response.Write("Your request has been submitted. Thank you.");
                
                
            }
    
            //this method runs on the seperate system thread
            private void SendMailMessage(object untypedSourceUri)
            {
                string toEmail;
                System.Net.Mail.MailMessage message;
                System.Net.Mail.SmtpClient mailClient;
                System.Net.HttpWebRequest request;
                System.Net.HttpWebResponse response;
                System.IO.Stream contentStream;
                Uri sourceUri;
    
                sourceUri = (Uri)untypedSourceUri;
    
                request = (HttpWebRequest)WebRequest.Create(sourceUri);
                response = (HttpWebResponse)request.GetResponse();
    
                if (response.StatusCode == HttpStatusCode.OK)
                {
    
                    contentStream = response.GetResponseStream();
    
                    message = new System.Net.Mail.MailMessage();
    
                    //we're using sourceUri.segments[length] because we're assuming
                    //the Uri ends with the filename. ie.. http://www.foo.com/mymovie.wmv instead
                    //of http://www.foo.com/getmovie?movieid=12
                    //if that's an issue, you'll have to write code to handle those situations
                    System.Net.Mail.Attachment attachment = new System.Net.Mail.Attachment(contentStream, sourceUri.Segments[sourceUri.Segments.Length - 1], response.ContentType);
                    attachment.ContentDisposition.FileName = sourceUri.Segments[sourceUri.Segments.Length - 1];
    
                    message.Attachments.Add(attachment);
    
                    message.From = new System.Net.Mail.MailAddress("[email protected]");
                    message.Sender = new System.Net.Mail.MailAddress("[email protected]");
    
                    toEmail = "[email protected]";
                    message.To.Add(toEmail);
    
                    message.Subject = "An attachment was sent for you.";
                    message.IsBodyHtml = true;
                    message.Body = "<p>The following attachment has been forwarded to you.</p>";
    
                    mailClient = new System.Net.Mail.SmtpClient("localhost");
    
    
    
                    try
                    {
                        // it is in here that the System.Net.MailClient class actually
                        // reads from the socket containing the remote file, as it sends
                        // the message to our smtp server.
                        mailClient.Send(message);
                    }
                    catch (System.Net.Mail.SmtpException mailException)
                    {
                        // well, you might not have smtp enabled on your iis box,
                        // relaying permissions may be denied (enable them)
                        // or the network went down.
                    }
                    finally
                    {
                        contentStream.Dispose();
                        response.Close();
                    }
    
                }
                else
                {
                    //the remote file server didn't like our request, or was busy. 
                    //log it, requeue it, send an e-mail to the sender it didn't work.
                }
    
            }
    Last edited by nemaroller; Jan 3rd, 2008 at 11:41 AM.

  10. #10
    New Member
    Join Date
    Nov 2008
    Location
    VA
    Posts
    9

    Exclamation Re: [2005] Downloading file

    Got "Cannot convert from method group to System.Threading.ThreadStart" error using that...

    -Tom

  11. #11
    New Member
    Join Date
    Nov 2008
    Location
    VA
    Posts
    9

    Unhappy Re: [2005] Downloading file

    Ok, I figured out some things with threading...

    It would seem you can only pass an "object", and then only ONE object, or it starts going crazy on you when you try to build the project. I was able to make it do that part ok, eventually, basically by replicating the same process as was in the code you gave (for which I'm very grateful - hadn't found anything else even remotely similar on the web yet after searching for a while).

    I keep getting "URI formats are not supported" now when it goes to create the attachment (on the Attachment line). Any way around this? Shouldn't it all be able to accept a URL in the form of a string? Have another suggestion?

    Thanks in advance,
    Tom

  12. #12
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2005] Downloading file

    Hello, welcome to VBF!

    Show your code and the exact error message you get; highlight the line that's throwing the error too.

  13. #13
    New Member
    Join Date
    Nov 2008
    Location
    VA
    Posts
    9

    Resolved Re: [2005] Downloading file

    Thanks for the welcome. Ask and ye shall receive. I figured it out, though. I had several different variables defined - one for URL of the file, one of the file name, and a Uri variable. I think I had just mixed up which one was supposed to go where in the ContentDispostion section. I decided to just use strings instead of Uris, though... too prone to those "Uri format not supported" issues, as I saw. This code works, for the benefit of whomever needs this in the future... Sanitized for our protection :-).

    Code:
    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.IO;
    using System.Net;
    using System.Net.Mail;
    using System.Net.Mime;
    using System.Security.Principal;
    using System.Threading;
    using System.Diagnostics;
    using System.Windows.Forms;
    
        protected void Page_Load(object sender, EventArgs e)
        {
            // Decode and parse the received URL for the attachment
            string docUrl= (string)Request.QueryString["docUrl"];
            docUrl= docUrl.Replace("%2F", "/");
            docUrl= docUrl.Replace("+", " ");
            docUrl= docUrl.Replace("%3A", ":");
            docUrl= docUrl.Replace("%2D", "-");
    
             // Use a system thread to allow the web application to remain responsive
            Thread sendingThread = new Thread(SendMailMessage);
            
            // Send the URI to the Thread.Start method
            sendingThread.Start(docUrl);
    
            Response.Write("Your request has been submitted. Thank you.");
        }
    
        public void SendMailMessage(object url)
        {  
            // Set the variables
            string docUrl = (string)url;
            String tempFolderPath = Path.GetTempPath();
            MailMessage message = new MailMessage();
            SmtpClient mailClient = new SmtpClient("localhost");
            Stream contentStream;
            string toEmail;
            string localComputer = System.Environment.MachineName;
            string userId = WindowsIdentity.GetCurrent().Name.ToString();
            string[] userName = new string[1];
            char[] splitter = { '\\' };
    
            // Set the e-mail address
            userName = userId.Split(splitter);
            userId = userName[1];
            toEmail = userId + "@ourdomain.com";
    
            // Set the parentUrl and msgId
            string parentUrl = "";
            string[] urlArray = new String[7];
            urlArray = msgUrl.Split('/');
            for (int i = 0; i < 7; i++)
            {
                parentUrl += urlArray[i] + "/";
            }
            parentUrl = parentUrl.Remove((parentUrl.Length - 1), 1);
            string msgId = urlArray[7];
    
            try
            {
                // Establish the message
                message.From = new MailAddress("[email protected]");
                message.Sender = new MailAddress("[email protected]");
                message.To.Add(toEmail);
                message.Subject = "Your Message Result";
                message.IsBodyHtml = true;
                message.Body = "<p>Attached you should find the message you requested.  Have a nice day! :-)</p>";
                
                // Get the file name for this attachment
                // (done in case it's necessary to have the name)
                string[] fileName = docUrl.Split('/');
                string file = fileName[fileName.Length - 1];
    
                // Use Integrated Authentication to check for a matching message directory
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(docUrl);                
                request.Credentials = CredentialCache.DefaultCredentials;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    
                if (response.ContentLength > 0)  // if the file is found
                {  
                    contentStream = response.GetResponseStream();
    
                    // Uses the file name found by splitting on the URL
                    Attachment data = new Attachment(contentStream, file, response.ContentType);
    
                    // Add the information for the file
                    ContentDisposition disposition = data.ContentDisposition;
                    disposition.FileName = file;
                    disposition.CreationDate = File.GetCreationTime(file);
                    disposition.ModificationDate = File.GetLastWriteTime(file);
                    disposition.ReadDate = File.GetLastAccessTime(file);
    
                    // Add the file attachment to this e-mail message.
                    message.Attachments.Add(data);
    
                    // Set up the SMTP Request
                    try
                    {
                        // Send the message
                        // Add credentials if the SMTP server requires them.
                        mailClient.Credentials = CredentialCache.DefaultNetworkCredentials;
                        mailClient.Send(message);
                    }
                    catch (SmtpException mailException)
                    {
                        // SMTP may not be enabled, relaying permissions may be denied, 
                        // or the network went down
                        EventLog ev = new EventLog("Application");
                        ev.Source = "E-mailFwd";
                        ev.Log = mailException.Message;
                    }
                    finally
                    {
                        contentStream.Dispose();
                        response.Close();
                    }
    
                }
                else
                {
                    // The remote file server didn't like our request, or was busy. 
                    // Log it and send an e-mail to the sender it didn't work.
                    EventLog ev = new EventLog("Application");
                    ev.Source = "E-mailFwd";
                    ev.Log = "Request made by " + userId + " for " + file + " failed.";
    
                    // Establish the message
                    message.From = new MailAddress("[email protected]");
                    message.Sender = new MailAddress("[email protected]");
                    toEmail = userId + "@ourdomain.com";
                    message.To.Add(toEmail);
                    message.Subject = "Your Message Result - FAILURE";
                    message.IsBodyHtml = true;
                    message.Body = "<p>Your message could not be retrieved from the archive.  Please inform the Systems Administrator.</p><p>Respectfully,</p><p>- Us</p>";
    
                    // Set up the SMTP Request
                    try
                    {
                        // Send the failure message
                        // Add credentials if the SMTP server requires them.
                        mailClient.Credentials = CredentialCache.DefaultNetworkCredentials;
                        mailClient.Send(message);
                    }
                    catch (SmtpException mailException)
                    {
                        // SMTP may not be enabled, relaying permissions may be denied, 
                        // or the network went down
                        ev.Source = "E-mailFwd";
                        ev.Log = mailException.Message;
                    }
                    finally
                    {
                        response.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            } 
        }
    Hope this helps someone.

    -Tom
    Last edited by navyjax2; Nov 5th, 2008 at 05:21 PM.

  14. #14
    New Member
    Join Date
    Nov 2008
    Location
    VA
    Posts
    9

    Lightbulb Re: [2005] Downloading file

    Additionally...

    I found that (even though I saw one site that said it couldn't be done!) you can use a stream for MULTIPLE attachments, as well, but you have to move the try...catch... finally block that has the send command out of the if...then and get rid of the finally (with the contentStream.Dispose() and response.Close()). The Sending try...catch has to be put after the if...then and the loop through your array of URL locations.

    Basically, it goes (pseudocode)
    Code:
    fill arrays with URLs (string[] = new string[]....)
    // do loop
    for (int i = 0; i < docUrlCountNum; i++)
    {
    // Establish your URLs and file names
    string fileUrl = urlArray[i];
    string[] fileName = fileUrl.Split('/');
    string file = fileName[fileName.Length - 1];
    
    do your request/response stuff here using HttpWebRequest request = WebRequest.Create(fileUrl)
    and response = (HttpWebResponse)request.GetResponse();
    add credentials for Windows Authentication
    
    if (response.ContentLength > 0)  // if the file is found
    {
    get your Attachment(contentStream, file, response.ContentType);
    get your disposition stuff
    message.Attachments.Add(data);
    }
    else
    {
    // Log it and send a message it failed to find the file to the user
    //  with SMTP try... catch... finally
    }
    } // end loop
    
    // do your sending here with SMTP try...catch - no finally - it won't be able 
    // to close or dispose your stream or response - I found no issues with that, 
    // though.
    -Tom
    Last edited by navyjax2; Nov 5th, 2008 at 09:47 PM.

  15. #15
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,170

    Re: [2005] Downloading file

    Glad you shared, it'll help a future searcher.

    Don't trust those sites, of course it can be done!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width