question

RodAtWork avatar image
0 Votes"
RodAtWork asked RodAtWork commented

Classic WebForms and Excel - getting Couldn’t download – network issue when trying to download a generated Excel spreadsheet

I'm trying to use an old ASP.NET app, written using VB.NET by someone (not me) years ago. I've been tasked with maintaining it. It is an Intranet application used twice a year, for about 3 weeks each time. Employees enter data for 3 weeks, twice a year. After they've finished entering data, their managers generate reports, which are then used to report to funding sources. Most of the reports are written in Crystal Reports - they're all working fine. One report generates an Excel spreadsheet, which gets downloaded to the user's machine (a manager), to report to the funding source. It is this part which isn't working. When I run the report in Microsoft Edge, entering the parameters on the page that are then used in the generation of the Excel spreadsheet named Temp.xls, it fails with the error “Couldn’t download – network issue”. When I try using Google Chrome, I get the error "Failed - Network error". So, the same thing that MS Edge is giving me.

Last year I had to make some changes to the app. One of those changes was to the generation of the Excel spreadsheet. This is the code:

Response.ContentType = "application/vnd.ms-excel"  'This needed to be updated https://stackoverflow.com/questions/974079/setting-mime-type-for-excel-document


That changed worked well earlier this year when the app was used by the managers to generate the Excel spreadsheet. I'm now testing the app in preparation for the employees to start using next weekend. But now it doesn't work. It generates that network error.

Nothing has changed in the app since I modified it last year. The only changes that could have occurred would be changes to the server by some Windows update. I don't know where the error could be occurring. And networking isn't in my wheelhouse. I did try to narrow the problem down, by trying to run the report, then looking at both the web server's Event Viewer and my machine's Event Viewer for the timeframe when I was running the report. I looked in the Event Viewer's Windows Logs, the Application, Security and System logs. Both on the web server and my development machine. There were no errors related to this IIS app.

At this point I don't know how to proceed to try and determine why my browsers can't download the Temp.xls file that is being generated at the web server. I'd appreciate some guidance, please.

windows-server-iis
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

You say download in a very general way. Do you mean that you have some code to download it and that code does not work? Or are you trying to download some other way? If so then how? Can you show how the report is being generated?

0 Votes 0 ·

@SimpleSamples, I don't know. I've never looked at that code. Someone else wrote it long before I was hired. And he wrote the app in a convoluted way, so one method does a little bit, like that code snippet I shared which helps generate the HTTP header. Then another generates the .xls file, etc. I'll have to look into what he did to see how he did it.

0 Votes 0 ·

Hum, does the file correctly exist, and path name and rights to the given folder work ok?
I would consider coding up a test page - put some simple code in to get/grab the file(s), and return if they can be read in the first place.

This could be a simple folder permissions issues, or even some kind of path error issue.
I would spend a bit of time checking these types of issues first, in place of chopping away at code that worked before.

0 Votes 0 ·

@AlbertKallal-4360, I think so. In the method where the original coder created the HTTP header, he appears (to me) to send it by a Response to the user's browser, then he deletes the file afterwards. I remember years ago doing something similar and discovering that there was a timing issue, where the ASP.NET project I wrote would delete the file it created before the user had a chance to see it. Since this thing has been running for at least 10 years, without any problems like that, I thought that couldn't be the issue. And I've tried reproducing it on my dev box, but that raise other, unrelated issues, so I stopped trying that.

i think I'd better try adding some debugging code into this to try and save a copy of the generated .xls file somewhere else, so I can see what it looks like.

0 Votes 0 ·

Both browsers are showing this issue - I just doubt that is the problem area.

I mean, are you saying that using older IE works then? (I doubt it).

So, this idea of looking at browser compatibility? I just don't think that is the problem area. I think this is some kind of path, or URL issue, or even a simple folder permissions issue.

Now, if you telling me that this works with older IE, but fails on newer browsers? Ok, then you have a good point. But if older, and newer browsers both fail, then as noted, I just don't see this issue as being a browser compatibility issue - I would spend time and efforts looking at other issues (file/path/folder issues) etc.

0 Votes 0 ·

Hi @RodAtWork ,

Do you have the source code of application generate and download the excel spreadsheet? I think you need to make sure application itself and code are correct at first. Then try to find cause on server or network.

0 Votes 0 ·
RodAtWork avatar image
0 Votes"
RodAtWork answered

Testing. This editor doesn't seem to be working. It's rejected anything I've tried to add. Testing.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RodAtWork avatar image
0 Votes"
RodAtWork answered BruceZhang-MSFT converted comment to answer

I've found how the Excel spreadsheet is created, so sort of solved one problem, but came up with another one. Here's the code as it was:

 Private Sub MakeExcel(ByVal withReport As ReportClass)
    
  Dim ps As WicReportBasics.ReportParameters = Session.Item("Parameters")
    
  'Dim tempDir As String = "c:\temp\"
  Dim tempDir As String = Common.GetTempDir()
    
  ' Write the xls file to a local directory temporarily
  Dim Fname As String = tempDir & Session.SessionID.ToString & ".xls"
  Dim DiskOptions As DiskFileDestinationOptions = New DiskFileDestinationOptions
  DiskOptions.DiskFileName = Fname
    
  Dim ExportOptions As ExportOptions = withReport.ExportOptions
  With ExportOptions
  .DestinationOptions = DiskOptions
  .ExportDestinationType = ExportDestinationType.DiskFile
  .ExportFormatType = ExportFormatType.Excel
  End With
  withReport.Export()
    
  ' The following code writes the excel file 
  ' to the Client’s browser.
  Response.ClearContent()
  Response.ClearHeaders()
  Response.ContentType = "application/vnd.ms-excel"  'This needed to be updated https://stackoverflow.com/questions/974079/setting-mime-type-for-excel-document
  Response.AddHeader("Content-Disposition", "attachment; filename=" & ps.OutputFileName & ".xls")
  WriteFile(Fname)
  Response.Close()
    
  ' delete the exported file from disk
  System.IO.File.Delete(Fname)
    
 End Sub

The assigning of tempDir to Common.GetTempDir() was something I put in, some time back.

Please note that I had made a mistake with the Response.AddHeader call. ps.OutputFileName returned "Temp". But as you can see, I'd created a different filename, so it couldn't find Temp.xls. I fixed that then tested it. It worked fine on my dev box. So, I published it to the web server. There it failed, again with a network error. I'm thinking the problem is with the System.IO.File.Delete(Fname) call that was put there by the original developer. That it was going too fast and deleting the .xls file before the browser had a chance to download it to the user's machine. So I changed it like so:

 Private Sub MakeExcel(ByVal withReport As ReportClass)
    
  Dim ps As WicReportBasics.ReportParameters = Session.Item("Parameters")
    
  'Dim tempDir As String = "c:\temp\"
  Dim tempDir As String = Common.GetTempDir()
    
  ' Write the xls file to a local directory temporarily
  Dim Fname As String = tempDir & Session.SessionID.ToString & ".xls"
  Dim DiskOptions As DiskFileDestinationOptions = New DiskFileDestinationOptions
  DiskOptions.DiskFileName = Fname
    
  Dim ExportOptions As ExportOptions = withReport.ExportOptions
  With ExportOptions
  .DestinationOptions = DiskOptions
  .ExportDestinationType = ExportDestinationType.DiskFile
  .ExportFormatType = ExportFormatType.Excel
  End With
  withReport.Export()
    
  ' The following code writes the excel file 
  ' to the Client’s browser.
  Response.ClearContent()
  Response.ClearHeaders()
  Response.ContentType = "application/vnd.ms-excel"  'This needed to be updated https://stackoverflow.com/questions/974079/setting-mime-type-for-excel-document
  'Response.AddHeader("Content-Disposition", "attachment; filename=" & ps.OutputFileName & ".xls")    'old way of handling the file
  Response.AddHeader("Content-Disposition", "attachment; filename=" & Fname)
  WriteFile(Fname)
  Response.Close()
    
  DeleteTemporaryExportFileAsync(Fname)
 End Sub
    
 Private Shared Async Sub DeleteTemporaryExportFileAsync(Fname As String)
  Await Task.Delay(5000)   'give the browser time to download the Excel spreadsheet
    
  Try
  ' delete the exported file from disk
  System.IO.File.Delete(Fname)
  Catch ex As Exception
  ' if the deletion fails, ignore it and move on
  End Try
 End Sub

This gives a weird filename that looks something like this:

C_Windows_Temp_hsnceshdnntdiul.xls

Why has it changed the backslash character ("\") to an underscore, when run from the web server?

· 12
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Well that conversion of spaces to "_" is ONLY at the other end - and will not stop this from working.

but, yes, URL encoding is a issue of the browser, and depending on the client side - it might not even support spaces in the file name. I mean, that suggested/used file name on the target side does not matter ONE TINY bit.

You can if you want swap/change/encode the spaces to a %20 if you want.

Just remember:
Any code behind that touches a file? Code behind is just like desktop software. the path + filename is a PLANE JANE valid windows path name.

If the user can type in a URL to resolve to the path name, or your code is going to take a web URL, then of course it is web encoded, and a valid web path name. (you would use server.MapPath() to convert to a internal plane jane windows path name.

but at this point? Who cares what the target file name is going to be? You can NEVER really set the path name client side (since YOU can't mess with my computer!!!). But, so what if the download file name is that way. But, YOUR code behind in ALL cases that opens a file, deletes a file? Yes, that is PLAIN JANE windows full valid path name. So I would not worry about what file name they see, and spaces to un-score should not matter. But your code behind should work with, and ALWAYS have a full plan jane windows file path. And you ONLY EVER want to have + pass ONLY the file name to the client side and ALWAYS without a path name.

So, ps.OutFileName MUST be file name only. And WriteFile(Fname) must be that full valid windows path and filename on disk.

0 Votes 0 ·

About an hour after posting more detail, I realized that the issue is probably related to permissions in the folder that is being used to write the .xls file to. That something/some account, doesn't have the necessary permissions to it. So, I searched for possible answers to this. I came across this website Configure Access Permission To A Folder For An IIS Application Pool. This looked very promising. And watching the folder on the server I can see that it does write the .xls file to folder. I decided that it would be better to go back to use C:\Temp as the folder to write the .xls file to. I tried to set the permissions on C:\Temp as the linked to website suggests, but it still didn't work. Then I noticed that the linked to site mentions its good for IIS 7.5 and above.

Unfortunately, this server is using IIS 7. (Yeah, I'm working with old equipment.)

So, how do I give permissions to the folder, to the application pool, with IIS 7, so that it will allow sending the .xls file to the user's browser?


0 Votes 0 ·

Hi @RodAtWork ,

Actually, the operation on IIS7 is same as on IIS7.5+. You have seen that .xls file was written to folder. So it means success. If it failed when go back to use C:\Temp, why not continue to use the previous folder?

In additional to the permission of app pool, one thing also need to be pay attention to. IUSR is the identity of authentication when your site use anonymous authentication. Anonymous authentication is enable by default. So make sure that IIS_IUSRS and IUSR also have permission to the folder.

0 Votes 0 ·

Hi @BruceZhang-MSFT,

Thank you for letting me know that IIS7 is the same as IIS7.5.

II've checked the website's authentication in IIS. Anonymous Authentication is disabled. Only Windows Authentication is enabled. I presume that means I've got to give all the users access to the folder where the .xls file is generated, correct? Or do I have to do something else?

0 Votes 0 ·
Show more comments
BruceZhang-MSFT avatar image
1 Vote"
BruceZhang-MSFT answered RodAtWork commented

Hi @RodAtWork ,

I will continue to discuss with you in this thread. There are three points that I think you need to confirm.

  1. Check MIME types on IIS. Make sure that .xls application/vdn.ms-excel exist in MIME types at the server and site level. This ensures that IIS allows such file transfers.126985-4.jpg

  2. Use Response.End() to replace Response.Close(). Response.Close sends a reset packet to the client and using it in anything other than error condition will lead to all sorts of problems - eg, if you are talking to a client with enough latency, the reset packet can cause any other response data buffered on the server, client or somewhere in between to be dropped.

  3. Use other browsers and try to download. Sometime network issue only report in chrome but other browsers can work well. IE, Edge and firefox are also great choices.

  4. When you removed the line that deletes the .xls file, does the file exist in folder?





4.jpg (69.9 KiB)
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @BruceZhang-MSFT,

Thank you for your continued help.

I've checked in IIS on the server, the MIME type .xltm exists, but at the server and site levels.

I've just tested using Chrome, it fails with a "Network error" message. Same thing, I believe as MS Edge does when it reports a "Network issue".

The generation of the .xls files are still in the C:\Temp folder from when I created them yesterday and today.

When using VS 2019's Publish function, does it temporarily put an App_Offline.htm file in place, so users will know that I'm deploying to the web server? Or is that only done when I'm debugging the app in VS 2019?

0 Votes 0 ·

Hi @BruceZhang-MSFT,

Your last suggestion of changing Response.Close() to Response.End() seems to have fixed it. Thank you!

0 Votes 0 ·

Hi @RodAtWork ,

I am glad your problem has been solved.

1 Vote 1 ·

Me too. And I'd mark your response from 4 days ago as the answer, if I could find a way of doing so.

0 Votes 0 ·

HI @BruceZhang-MSFT,

I've checked both the server and site level MIME's. They both have the .xltm MIME you specified.

Unfortunately, at the moment I've got a fire so will have to get back to the rest of this later.

0 Votes 0 ·
AgaveJoe avatar image
1 Vote"
AgaveJoe answered AgaveJoe edited

For some reason your other thread redirects here so my response is lost.

Your code uses the file path on the server as the file name. You want the actual file name. Use the Path.GetFileName() method to grab the file name from the path.

 Response.AddHeader("Content-Disposition", "attachment; filename=" & Path.GetFileName(Fname))

Response.Close() can cause problems. The reference documentation recommends Response.End() or HttpContext.Current.ApplicationInstance.CompleteRequest()

 Response.ClearContent()
 Response.ClearHeaders()
 Response.ContentType = "application/vnd.ms-excel"
 Response.AddHeader("Content-Disposition", "attachment; filename=" & Path.GetFileName(Fname))
 WriteFile(Fname)
 Response.End()

I'm pretty sure you not using ascyn methods correctly but it does not matter because execution never reaches DeleteTemporaryExportFileAsync() due to the Response.Close(). Secondly, there is no logical reason to implement an async method because the code is synchronous. Just delete the file once the WriteFile completes.

 Response.ClearContent()
 Response.ClearHeaders()
 Response.ContentType = "application/vnd.ms-excel"
 Response.AddHeader("Content-Disposition", "attachment; filename=" & Path.GetFileName(Fname))
 WriteFile(Fname)
 File.Delete(Fname)
 Response.End()

If you really want to implement an async delete then replace Response.End() with HttpContext.Current.ApplicationInstance.CompleteRequest()

Lastly, I tested the WriteFile() method with a 350,000 KB using the updated code above and logic worked as expected. WriteFile() methods writes to the response stream in 300,000 byte blocks. Once the WriteFile() finished the file is deleted. Below is my test code.

 Public Class _Default11
     Inherits System.Web.UI.Page
    
     Dim Fname As String = "C:\Temp\largefile.xls"
     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
     End Sub
    
     Protected Sub Button1_Click(sender As Object, e As EventArgs)
         Response.ClearContent()
         Response.ClearHeaders()
         Response.ContentType = "application/vnd.ms-excel"
         Response.AddHeader("Content-Disposition", "attachment; filename=" & Path.GetFileName(Fname))
         WriteFile(Fname)
         File.Delete(Fname)
         Response.End()
     End Sub
    
     Private Sub WriteFile(ByVal Fname As String)
    
         Dim MyFileInfo As FileInfo
         Dim StartPos As Long = 0
         Dim FileSize, ThisWrite, LeftToWrite As Long
    
         MyFileInfo = New FileInfo(Fname)
         FileSize = MyFileInfo.Length
         LeftToWrite = FileSize
    
         While LeftToWrite > 0
             ThisWrite = IIf(LeftToWrite > 300000, 300000, LeftToWrite)
             Response.WriteFile(Fname, StartPos, ThisWrite)
             Response.Flush()
             StartPos += ThisWrite
             LeftToWrite -= ThisWrite
         End While
    
     End Sub
    
    
 End Class

It would be very helpful if you can revert back to a code base that worked as expected. It's not clear if this bug is due to your updates or is an existing bug.




· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @AgaveJoe (love your handle, BTW),

You're correct in that the code as is, does write to a temporary .xls file in the C:\Temp folder on the server. And it does that fine. Since I've commended out the code to delete the file, I can see that various versions of the .xls file are still there.

I tested using Path.GetFileName(Fname). That just returns the name of the .xls file, but not the path to that file. That doesn't seem like it would work. Or should I change it to something like this:

 Response.AddHeader("Content-Disposition", "attachment; filename=C:\Temp\" & Path.GetFileName(Fname))


0 Votes 0 ·

I tested using Path.GetFileName(Fname). That just returns the name of the .xls file, but not the path to that file. That doesn't seem like it would work. Or should I change it to something like this:

You misunderstand the content-disposition header. The filename is the actual filename not the path. The way you've code this, the downloaded file will be named "C__Temp_TheFileName.xsl" on the user's machine. Surely, you must have experienced the odd file name when testing the code? Or perhaps you expect the file to be saved at a specific location on the user's machine? If so, that's not possible either.

Did you try replacing Respsone.Close() with Response.End()?

0 Votes 0 ·
MarkDsirl-3914 avatar image
0 Votes"
MarkDsirl-3914 answered MarkDsirl-3914 edited

I think Access permission is for application pool. I saw website where mention these details. This might be works

https://www.thedummyprogrammer.com/asp-net/configure-access-permission-to-a-folder-for-an-iis-application-pool

For you.


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.