2

I am trying to send an Excel file to the client of an ASP.Net web page, but it doesn't work.

When the user clicks a button, some data from our server-side database is formatted, put in an Excel file and sent to the user (as a direct download).

Everything works well, except the sending part and any help would be greatly appreciated.

Here is the code I'm using right now (client side):

var dataAjax = {};
$.ajax({
    async: false,
    type: "POST",
    url: "Default.aspx/BuildExcelFile",
    contentType: "application/json",
    data: JSON.stringify(dataAjax),
    dataType: "text",
    success: function(html) {
        //alert(html);
    },
    error: function(request, status, error) {
        alert("An error occurred : [" + error + "]");
    }

});

And the server side code:

<WebMethod()> _
Public Shared Function BuildExcelFile() As String
    Dim localExcelPath = "C:\temp1111.xlsx"

    'Build the excel file here...
    '...

    'Delete the old version of the Excel file
    System.IO.File.Delete(localExcelPath)
    'Save the Excel File locally
    xWorkSheet.SaveAs(localExcelPath)
    xWorkBook.Close()
    exc.Quit()

    'The generated excel is valid, can be opened on the server just fine

    'Send the excel file to the client
    'This part is not working! :(
    System.Web.HttpContext.Current.Response.Clear()
    System.Web.HttpContext.Current.Response.ContentType = "MS-Excel/xls"
    System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=" & System.IO.Path.GetFileName(localExcelPath))
    System.Web.HttpContext.Current.Response.TransmitFile(localExcelPath)
    System.Web.HttpContext.Current.Response.End()

    Return "Success"

End Function

I am getting this error when I try to verify the value of Current.Response

Response: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.

Also, if I remove the Response.End() call, the data is received in the html variable of the success function in the ajax. However, I want the file to be downloaded, not received as text...

If I keep Response.End(), I get an Internal Server Error.

Is it not working because my Webmethod is shared? Any clue what's going on here? What can I do to fix this problem?

Edit:

I'm using .Net 3.5, if that matters

I'm not using MVC

Msonic
  • 1,456
  • 15
  • 25
  • I think it is because you called it in ajax. I would say: use ajax load a new url for the browser. then in that url, process the http handle and output the excel file directly. – urlreader Nov 07 '12 at 19:46
  • Thanks for the quick response. Any relevent links or tips on how to do that? I'm still fairly new to web development – Msonic Nov 07 '12 at 19:51
  • http://www.devtechie.com/post/2011/02/19/Export-to-Excel-from-ASPNET-using-HTTP-Handler.aspx , Create a new handler, then in ajax, popup a new browser to show that handler url. – urlreader Nov 07 '12 at 20:00
  • Look here: http://stackoverflow.com/questions/149821/use-jquery-to-send-excel-data-using-ajax – Shai Cohen Nov 07 '12 at 23:06
  • There is a similar question here, see whether it helps: http://stackoverflow.com/questions/10405785/send-excel-file-to-asp-net-web-api –  Nov 08 '12 at 07:45

3 Answers3

2

I had this exact same problem sending data from client to server as well. You could get around it by loading an iFrame dynamically that kicks off the download - the iFrame is basically just filled with a blank aspx page that starts the download in the Page_Load. You could also save the file to the server and provide a link to download it in the client. Those are the workarounds I found that worked.

I don't know if you can do it the way you're trying or not. I checked examples all over and it never worked. If you can't figure it out, these ways worked for me.

Yatrix
  • 13,361
  • 16
  • 48
  • 78
  • Thanks! I've found a solution inspired from your answer. Instead of calling the webmethod via ajax, I have a hidden server-side button which is clicked (with jquery) automatically when I want to start the download. Everything works fine now :) – Msonic Nov 08 '12 at 15:24
  • Well, glad I could kinda help. =) – Yatrix Nov 08 '12 at 15:33
1
Public Shared Function BuildExcelFile() As String
    Dim localExcelPath = "C:\temp1111.xlsx"

    'Build the excel file here...
    '...
    xWorkSheet.SaveAs(localExcelPath)
    xWorkBook.Close()
    exc.Quit()

    'The generated excel is valid, can be opened on the server just fine

    'Send the excel file to the client
    'This part is not working! :(
    System.Web.HttpContext.Current.Response.Clear()
    System.Web.HttpContext.Current.Response.ContentType = "MS-Excel/xls"
    System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=" & System.IO.Path.GetFileName(localExcelPath))
    System.Web.HttpContext.Current.Response.TransmitFile(localExcelPath)
    System.IO.File.Delete(localExcelPath)

    System.Web.HttpContext.Current.Response.End()

    Return "Success"
End Function
  1. Use postbacktrigger on your button click if you are using Ajax
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Anand
  • 11
  • 1
0

This works for me:

string fileName = "ExampleFileName.xlsx";
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;  filename=" + fileName);
Response.BinaryWrite(excelPackage.GetAsByteArray());
// Response.End(); Replaced with below 3 lines to avoid ThreadAbortException
Response.Flush(); // Sends all currently buffered output to the client.
Response.SuppressContent = true;  // Gets or sets a value indicating whether to send HTTP content to the client.
ApplicationInstance.CompleteRequest(); // Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event.

I am using a dll called 'EPPlus.dll' as my Excel library. There is no need for an Ajax call as you can instantiate the download from an Asp.net button, or simply call a method from your server-side code when you want to start the download.

leviathon
  • 51
  • 3