user1298857
user1298857

Reputation: 43

How to download a file in javascript or jquery from a webmethod that is in byte[]?

I am having problems to download an excel file using jquery. I have read in some forums that this is not possible using ajax and in some they say that you can achieve this sending the results to an iframe. So far I have not been able to solve my problem.

Technical details: I generate a query to a database with some parameters, a webservice performs this query and returns an excel file generated in openxml and returns the bytes. I am using asp.net 4.0. If I use the regular webcontrols and ajax the file is downloaded with no problem if in the update panel I set the triggers to asp:postbacktrigger to the button control.

I am trying to achieve the same results using only jqueryUi controls and jquery.

In the server side I have two methods:

ExportToExcel: This method receives the parameters to call a rest webservice that returns the excelfile.

SendExcelFileByBytes This one is the method that returns the file in the request.

Here is the C# code:

[WebMethod]
    public static void ExportToExcel(List<int> status, List<Guid> companyId, List<DateTime> dateFrom, List<DateTime> dateTo, bool isGroupedByStore)
    {
        ReconciliationModule server = new ReconciliationModule(ConfigurationManager.AppSettings["serviceNamespace"], ConfigurationManager.AppSettings["ACSHostUrl"], ConfigurationManager.AppSettings["scopeAddress"]);
        SummaryReport summaryReport = new SummaryReport();

        List<Tuple<Guid, DateTime, DateTime, int>> parameters = new List<Tuple<Guid, DateTime, DateTime, int>>();

        for (int i = 0; i < dateTo.Count; i++)
        {
            parameters.Add(new Tuple<Guid, DateTime, DateTime, int>(
                companyId[i],
                dateFrom[i],
                dateTo[i],
                status[i]
            ));
        }

        byte[] x = server.GetSummaryReportInExcel(ConfigurationManager.AppSettings["userName"], ConfigurationManager.AppSettings["pwdOrSymmetricKey"], bool.Parse(ConfigurationManager.AppSettings["isSymmetricKey"]), isGroupedByStore, parameters);

        SendExcelFileByBytes(x);
    }

    private static void SendExcelFileByBytes(byte[] x)
    {
        System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"SummaryReport.xlsx\"");
        System.Web.HttpContext.Current.Response.AddHeader("Content-Type", "application/force-download");
        System.Web.HttpContext.Current.Response.AddHeader("Content-Type", "application/download");
        //System.Web.HttpContext.Current.Response.AddHeader("Content-Transfer-Encoding", "binary");
        System.Web.HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";//excel file
        System.Web.HttpContext.Current.Response.Clear();

        System.Web.HttpContext.Current.Response.BinaryWrite(x);
        //System.Web.HttpContext.Current.Response.Close();
        System.Web.HttpContext.Current.Response.Flush();
        System.Web.HttpContext.Current.Response.End();
    }

For the jscript my callAjaxFunction is failing and returning a 200 OK message with the results in the responseText. So in the function that is performed when something fails i am showing the responseText in a table. If someone can help me to do this in a better way it will be greatly appreciated. And here is the jscript code:

//Executes Ajax Calls using json as data type
function callAjax(callType, urlAddress, dataToSend, fnSucceeded, fnFailed) {
    $.ajax({
        type: callType,
        url: urlAddress,
        contentType: "application/json; charset=utf-8",
        data: dataToSend,
        dataType: "json",
        success: fnSucceeded,
        error: fnFailed
    });
}

//TODO: This function is the one i need to correct
function getSummaryReportInExcel() {

    ShowLoader('#reconciliation');
    var isGroupedByStore = new Boolean($('#CompanyTypes :checkbox').attr('checked'));
    var stat = getStatus();
    var status = new Array();
    var companyId = new Array();
    var dateFrom = new Array();
    var dateTo = new Array();
    var companiesToSearch = $('#CompanyConfigurations :checkbox:checked');

    //populating the parameters
    $(companiesToSearch).each(function (i, currentCompany) {
        status.push(stat);
        companyId.push($(currentCompany).select('checkbox').attr('value'));
        dateFrom.push($(currentCompany).parents().find('td:eq(2) :input').attr('value'));
        dateTo.push($(currentCompany).parents().find('td:eq(3) :input').attr('value'));
    });

    var data = "{ status : " + JSON.stringify(status) + ", companyId : " +  JSON.stringify(companyId) + ", dateFrom : " +  JSON.stringify(dateFrom) + ", dateTo : " +  JSON.stringify(dateTo) + ", isGroupedByStore : " + isGroupedByStore + " }";

    alert(data);

    callAjax(
        "POST", "UIJquery.aspx/ExportToExcel",
        data,
        //is not entering here
        function () {
            alert('Hola' + result.toString());

            //header.
            HideLoader();
        },
        //AjaxFailed
        function (result) {
            //alert(concatObject( result));
            $('#SearchResults').append(concatObject(result));
            //var iFrame = "<iframe src=" + result.responseText + "></iframe>";


            $('#IResults').html(result.responseText);
            //window.open(result.responseText, 'Download');
            HideLoader();
            //alert(concatObject(result));
        }
    );
}

Here is what i see in the Developer tools in google chrome

HeadersPreviewResponseTiming
Request URL:http://localhost:53144/UIJquery.aspx/ExportToExcel
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json, text/javascript, */*; q=0.01
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:216
Content-Type:application/json; charset=UTF-8
Host:localhost:53144
Origin:http://localhost:53144
Referer:http://localhost:53144/UIJQuery.aspx
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.83 Safari/535.11
X-Requested-With:XMLHttpRequest
Request Payload
{ status : [15,15], companyId : ["15afbacb-5c0c-4402-a5af-0f5a53221bbb","041d6a48-35ca-4d55-97ec-4fd5f4bdd11f"], dateFrom : ["11/06/2011","11/06/2011"], dateTo : ["11/12/2011","11/12/2011"], isGroupedByStore : true }
Response Headersview source
Cache-Control:private, max-age=0
Connection:Close
Content-Disposition:attachment; filename="SummaryReport.xlsx"
Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Date:Wed, 28 Mar 2012 18:22:32 GMT
Server:ASP.NET Development Server/10.0.0.0
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319

Any suggestions or better ways to do it let me know thanks.

Upvotes: 3

Views: 8444

Answers (1)

poncha
poncha

Reputation: 7866

Something along these lines...

<script type="text/javascript">
function downloadExcelFile(url, dataToSend) {
   url += '?';
   for(var k in dataToSend) {
      url += k + '=' + encodeURIComponent(dataTosend[k]) + '&';
      }
   window.location = url;
   }
</script>

this will take the base url as first argument, and an object containing the parameters as a second, construct a full url from this and redirect the browser to it... eg

downloadExcelFile('http://www.example.com/myWebservice/downloadExcel.aspx', {
   param1: 'value1',
   param2: 'value2'
   });

the browser in this case will be redirected to

http://www.example.com/myWebservice/downloadExcel.aspx?param1=value1&param2=value2&

Upvotes: 1

Related Questions