0

I have a simple ASP.NET webpage using VB with a file upload control. The user will upload a .xls and a new .xls file is created in the project directory with a new format and some calculations. This file saves, opens, and displays without an issue.

Within this button click event, I want the newly-created file to download to the user's browser/Downloads folder. When using Response.WriteFile with a Response.End, the .xls file downloads properly...BUT there's a thread abort exception that is caught and nothing after the Response.WriteFile line is processed even if I put it in the catch statement (i.e. I have a label that I want to tell the user to then display that the file has been successfully downloaded).

Here's the initial code that mostly works:

Protected Sub btnUpload_Click(sender As Object, e As EventArgs) Handles btnUpload.Click
        If fuReport.HasFile Then

'All report processing occurs & report is created without issue

    Try
        Response.Clear()
        Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", strReportName))
        Response.ContentType = "application/vnd.ms-excel"
        'Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        Response.WriteFile(strReportName)
        Response.End()
        lblResult.Text = "Report was successfully downloaded."
     Catch
        lblResult.Text = "Testing1."
     Finally
        lblResult.Text = "Testing2."
        fuReport = New FileUpload()
     End Try
    End If
    End Sub

I've seen some different recommendations for the ContentType of .xls files. Both of the content types above will download the file but nothing in the Catch or Finally statement is processed. lblResult still reads, "Please wait while your report is processing..."

I found online that the issue lies with Response.End(). Per https://support.microsoft.com/en-us/kb/312629/en-us, I replaced this with

HttpContext.Current.ApplicationInstance.CompleteRequest()

This caused a new issue. My .xls file would download, but it seemed to display gibberish, followed by some of the aspx page content. Here, the label is correctly listed even though it has not changed on the webpage. I don't have enough reputation to include a screenshot, but this is some of what the Excel file displays:

ˆdQ_9€`Èb/ecÈ¢l†=gÊC\Œ¬ÀxbY”Â…‘#ˆ,ör6ˆ,Ê…8ëY8ÖæBô?³2º‹CÓž€|^î¯{{<xJñ¯ªç2,FÑ+sbŸ£å›q³žcm"9ŸÛÆ…îâpoŸûñä_õ¥1­K×Ê1Ü–‘äŒä‚$‹’,ÊÞÿ?ëY9ÖÎɺa 9†7(Æ‘E‰c<µŠ$wïå¼Q9çƒìù93vì£Þ¾ŠõXè.î·ÛúÏöX;`>¸w!‚™•ó‘#Ž,8²(ãÞqÖ3q¬M¥dÝ ‚Â7VE¾‰`|mä^@Y”°çÞÌØZXß²‹O•½në›×å­=än½‘°i”EàqÅ^Ê6‹²(×›õìks   žú¦¸Ð½µW§îo[‚‡ÚGÈýz3·!dÑ„@ dq€E9õ×3lfl%Ø™^Vv
@ÈB{)[²èïmÖ³l¬…8óI–½-?o{ÖΤ,÷IJhC ²ØKÙ²hmïÕΞâ}û‡.vÝÌznµ³ð±Lâc¹7†E  ÜOpÁÅ^ÎÆEyüæ=£ÆÚÄÏnïýúº·7åå‡v³Í[;οŠþ•PˆÃp%*0B!ö
ÑÓè¼gÓX›8N—ï\èõXèÞÞ4·íTÏöõeùí$ñõ­~À“Böº/kûϵýõ\Þ8½>SF+/åê1³{þÌœý†éêÔߊ*t-Áwí>ÕnW¿¯ö΀žE” 9åÕÈFY”ùöâ¼gÏX›*Ñ^¸ñÓ*‘uo›ËK;”Áð/. 
½g/D‰ ?KQFþÝF3©ö|š9›1JÖi”¬÷m6‘lB/oD‘s0²èŒ=·fÎvBŒ‘u#ëŒ,JãK#YPdÑ1{ŽÍœ{+<˜WY÷v_ï®Úǽªêë{ñæÑ½Ð–9ÅëÚ–9,À’–,X²(×z›÷ÌkÓÒö;+»>²ì6£®ËÛwÁýë½á0‚,JaRå!‹½œm¥Ê¢×vôúÁìÉï¼éŸ÷<kÁé*øLƒÐýËNÖ|SloŸmë¿ìÍ©ƒ·ú·Å*÷ï½Ðl(Y”PÆ+$YdQv1öü›9‹qT¬kQþk[W‡;+õ…›âš"z÷FÅ@r×   ¤X³rA“Å^ÞV—,:â2¹è:Ö¦Úœ-fþô*t”×Õ·í»©ÁÛþ"„¢D3,K€A
±RˆòMYôÌkç1dÝ †"`È¢Ä0¾JŠ_, r÷DeBìù9vìÌTS±ÐýQnm‹x;©îªƒ³P:‹^ùJ”ÆeÈ?Wdq@EÙïN-zf޵±Cˆ¬‘xV AdQ‚uÈEY”O±çã,Øf°ÃyE±ÝU}gÞøÛò]mŸ;ök‘{öWª¢Û„1®EÑë“Éé“ñ©ûRÃsõ£ŠÜcælÚópì1ÄY7!Gð}U‘nB•ÈÝŠJdqÀE™{΂½…˜!ë†0äC%†|Ÿ!~´àÈ)Y”ɱgà,Ø`˜¬‚… 
Ëþ¨¶—;oì‰q°óFtì    
‡]¹Û„1žM9€ Èb/åJ9cóÔ¢çÞX×4‹¹wY²«!ëþ¨+û4Š8¿z*"xƒaü¸ÛĦRŽ ²ØËÙ²({ø¢çÜX›0Ž‚³n…ì;V£.oǧkŠ Þ HN8Œ‘Ž,öR6Ž,Ê›J—=·ÆÚqí$:£xÛÞ$Ú‹R‡ÏîÂTðŸM    Q"ÈWD…1
±Qˆr?8µìY6ÖÎɺ 9€7 ÅXd›@Æsªˆ  ~Εs6Äže³dG!®FÖ  
€Èˆ,JÃùTü\Á{÷R6†,ÊfØsl–ì'Ì#Ï;Y…ÎÚ5ñäo'›}]í.Gßú“+çà›¨"8¹W“ÅNñDcÙso¬ÍSkD”ußG”cyÃc³,‹Q˜e9‚@Êb/g«Pƒ´çæ,Ùj°"õß¾º?ê݇v+ÇoÍv,{¸coLŒ#‹†pä‚#‹½œ#‹ŽáØst–l5Ìã`²eÝÍÎοY—ûwöBŽ?ÃrßÐÙ&ŽbùÊ]–,X²(oëñ²gèX›gØàb¡û£i®Ì/ªw;ôwrˆGN7q„y•#†,²(w+DzçëX›).¼…‡­|X÷ÇÞöÅÙ!Föjc|ûFDðFÄfUî6QŒ—¯@@d±—²Mª,:fRí;K6숿€#ë†päÞ G%ŽPA€d±—³dÑ W=sÇÚ\sÏfY…î¿ÛÅ÷íƒÇÆM\轿žBuš0†å(zeŠBìS¢c(öœ›¶ïØ·Ë…î¿Û×S‹ªjÿÏ]â}@‘“@‘Š,(²(Ïc]õ\kc†Y§²Þ    
+C%€¼FQENÁË{£òΤØóuVì5ÄeÈ:M‘õÞhE%Šñ5QD¹{/g#È"$øäEy(ýùãMc;ÓêË×û“÷Íîð«_~°ëàáóÇê—vÍY³ûÓü3Û}þÃûomWi{˜[½»;ÙVïöŸþÔnxXrþçš¿ü`“Ä;ûä[sûм©ì½õ}ûØü¾ilGÜ—ÿa1¿ü»çÿð¤ÜÖ×»?l{Î×^ì¿jû}ò©ÙxÈù×ÿÿÿPK-!®ÄñQ"[Content_Types].xmlPK-!ùJ­¬öW 
sxl/styles.xmlPK-!é¦%¸‚Sü  xl/theme/theme1.xmlPK-!òñ%>e¯docProps/core.xmlPK-! pUŠ¡5$docProps/app.xmlPK-!Š¥aú`qûxl/workbook.xmlPK-!'¡Œ=Å5߈xl/worksheets/sheet1.xmlPK

<!DOCTYPE html> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head id="Head1"><title>    

</title>    
    <script type="text/javascript"> 
        function changeLabel(){ 
            document.getElementById("lblResult").innerHTML = "Please wait while your report is processed...";   
        }   
    </script>   
</head> 
<body>  

    <form method="post" action="Uploader.aspx" id="form1" enctype="multipart/form-data">    
<div class="aspNetHidden">  
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="+yve+0TnTzr8dZbqET3gRkZx/Pw9iGFmDqDyyfeTPMoXlPTPVgX3FrRUhTd3lBZE0DkzyUKzhXOi6MqTdxe1jnYL+mdzQiyoaM5w5cv9vij3X1xtsW8P1zACrDj6IqUK87n3GcwFtdHCCblAdgFI8nPQZsJnRv9w8lNIurcrbfad534ICOt8S/++vRi9+s91DFi3woIbFMyxw3rvbUPQwg==" />    
</div>  

<div class="aspNetHidden">  

    <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="C153B6F1" />
    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="c3fKPUwILazJv1aW60quCxYtkspAHgetjdwMb7ugaEBN7qnUTTL7SrAVizVMaqXPAPqmyhDV0rtT1upkWYH9eOzqHjjmjvr9ZHty08BHB9OD/fCIuF8ExZbOqpiXOdGA" />


 </div> 


  <div> 
        <input type="file" name="fuReport" id="fuReport" style="width:306px;" />    
        <br />  
        <span id="lblResult">Report was successfully downloaded.</span> 
        <br />          
        <input type="submit" name="btnUpload" value="Upload" onclick="changeLabel();" id="btnUpload" /> 
    </div>      
    </form> 
</body> 
</html> 

I then tried replace all of the Response code with HTTPContext as shown here:

HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", strReportName))
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.Write(strReportName)
HttpContext.Current.ApplicationInstance.CompleteRequest()

This also downloads a .xls file but with a graphical representation of the webpage. Again, I cannot post a picture, but the Excel file opens to show the button with text, Upload & says:

Report was successfully downloaded.

I have researched this for HOURS with no solution. I have tried pulling this particular code out of the try/catch/finally as someone else had success with but this did not help either.

Does anybody know how I can properly have the browser download the .xls file with the actual contents of my NewReport instead of it containing information from the aspx page??

H--
  • 95
  • 3
  • 14
  • `ThreadAbortException` happens because of `Response.End`. That's normal behavior. The response will literally end, you can't then continue page execution, making your attempts to update the label text pointless. Probably the easier workaround is to do the file download in a separate context: provide a link to the file so that it opens in a new page or window. You don't need an `.aspx` page for that, a `.ashx` generic handler should do. – mason Jun 25 '15 at 15:30
  • Thanks for the comment! Yes, I found that the Response.End was causing the ThreadAbort during my researching of the issue, which is why I tried other alternatives. The thing is, this is going to be a webpage on our company intranet for internal use and for their ease of use, I'd really like to only utilize the one page where the download will occur after the user uploads. I'd like to avoid needing to provide a separate link, if possible. I'm trying to find a working alternative to response.end. – H-- Jun 25 '15 at 15:40
  • It's necessary to call `Response.End` or some equivalent because that's how client-server communications work. If you want to make it more seamless, you could have JavaScript be employed for the download, as in [this question](http://stackoverflow.com/questions/3749231/download-file-using-javascript-jquery). Or since you're in an Intranet environment, you could email the file to the user. – mason Jun 25 '15 at 15:42
  • Unfortunately, I was told not to implement emailing; my requirement is to have it download. Everything that I have read has implied that HttpContext.Current.ApplicationInstance.CompleteRequest() is its equivalent... I'm finding it odd that it is downloading the page's content into an Excel file rather than the initial .xls content that I want to be downloaded, so I'm not sure what other steps need to be taken to make it behave correctly. The link you shared had a lot of references; are you suggesting the selected answer of using an iframe might help accomplish my task? – H-- Jun 25 '15 at 15:55
  • 1
    I'm suggesting you look at all the answers in the provided link and select one that's suitable to your needs. You seem to be under the impression that you can download a file to the user in one response, end the response, then continue trying to modify the response. But that's not how ASP.NET works, which is why you need a separate request to retrieve the file, which is what that iframe based answer does. – mason Jun 25 '15 at 15:57
  • I guess I wasn't fully understanding that ASP.NET does not work this way. I guess I had thought of the Response.End() was merely tying up the ends of the downloading functionality and that I could then continue making commands in the event. Everything I had read seemed like HttpContext.Current.ApplicationInstance.CompleteRequest() was the workaround I needed, so I was looking for some guidance on why I was not getting the end result I wanted. I'm still learning, but I'm beginning to see what I wasn't grasping initially. I will review the suggestions on that thread. Thank you! – H-- Jun 25 '15 at 17:15
  • @mason, your comment is good answer, you should add it as an answer so others will see it – Elisheva Wasserman Jun 25 '15 at 17:25

2 Answers2

0

I like to use BinaryWrite, something like this:

Dim ms As New IO.MemoryStream
xWB.Write(ms)
Dim bytes As Byte() = ms.ToArray
Response.ContentType = "application/vnd.ms-excel"
Response.AddHeader("content-disposition", "attachment;filename=" & strReportName)
Response.BinaryWrite(bytes)
Response.Flush()
Response.End()
Chuck
  • 1,001
  • 1
  • 13
  • 19
  • I appreciate your assistance, but this will unfortunately not work for me. My page requires further processing after the file downloads, so Response.End() is not suitable in this instance. – H-- Jun 25 '15 at 20:22
0

I gave up on the idea of doing both processes automatically. I added in a Download button that only becomes visible once the report has been successfully processed. On the Download button's on click event, I have the excel file download. It's one more click than I wanted, but it gets the job done.

Protected Sub btnUpload_Click(sender As Object, e As EventArgs) Handles btnUpload.Click
If fuReport.HasFile Then
    Try        
        'All report processing occurs & report is created without issue   
        lblResult.Text = "Report was successfully processed."
        btnDownload.Visible = True  
    Catch
        lblResult.Text = "An error occurred. Please try again."
    Finally
        fuReport = New FileUpload()
    End Try
  Else
        lblResult.Text = "Please select a report to upload."
    End If
End Sub

Protected Sub btnDownload_Click(sender As Object, e As EventArgs) Handles btnDownload.Click
        Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}", strReportName))
        Response.ContentType = "application/vnd.ms-excel"
        Response.WriteFile(strReportName)
        Response.End()
    End Sub
End Class
H--
  • 95
  • 3
  • 14