Download file from ajax and ActionResult
Asked Answered
K

2

7

I want to download files on browser with ajax and ActionResult. The file is downloaded and returned from my ActionResult.

I see the Http query is ok and see the data in the response body. The problem is that the file is not proposed to save in the browser.

All seems good. All that I seen in tutorial and forum were like I done but mine don't word XD. I don't understand what is the difference between mine and the others.

Here is my ActionResult :

public ActionResult ShippingDownloadDNPriority(string SALE_GUID)
{
    int supId = -1;
    int.TryParse(Session["SupId"].ToString(), out supId);
    if (supId < 0)
        return null;

    WebResponse response = CallApi.DownloadAndCreateDN(Session["UserLogin"].ToString(), Session["IdentConnect"].ToString(), SALE_GUID, supId, true);
    Stream responseStream = response.GetResponseStream();

    var cd = new System.Net.Mime.ContentDisposition
    {
        FileName = "myfile.pdf",
        Inline = false,
    };
    Response.Headers.Add("Content-Disposition", cd.ToString());
    Response.ContentType = "application/octet-stream";
    return File(responseStream, System.Net.Mime.MediaTypeNames.Application.Pdf, "myfile.pdf");
}

public static WebResponse DownloadAndCreateDN(string login, string session, string SALE_GUID, int supid, bool priority)
{
    string[] res = new string[2];

    StringBuilder postData = new StringBuilder();
    postData.AppendLine("{");
    postData.AppendLine(string.Format("\"login\":\"{0}\",", login));
    postData.AppendLine(string.Format("\"session\":\"{0}\",", session));
    postData.AppendLine(string.Format("\"saleguid\":\"{0}\",", SALE_GUID));
    postData.AppendLine(string.Format("\"supid\":{0},", supid));
    postData.AppendLine(string.Format("\"prority\":{0}", priority.ToString().ToLower()));
    postData.AppendLine("}");

    ASCIIEncoding ascii = new ASCIIEncoding();
    byte[] postBytes = ascii.GetBytes(postData.ToString());

    string url = Properties.Settings.Default.ISAPIAddress + "deliverynote/create";

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/json";
    request.ContentLength = postBytes.Length;

    Stream postStream = request.GetRequestStream();
    postStream.Write(postBytes, 0, postBytes.Length);
    postStream.Flush();
    postStream.Close();

    return request.GetResponse();
}

Here is my javascript :

$.ajax({
    url: '../Shipping/ShippingDownloadDNPriority?SALE_GUID=XXXXXXXXXXXXXX',
    data: { SALE_GUID: DropShipping.GetRowKey(rowIndexSale) },
    async: false,
    //success: function (data) { window.downloadFile = data; }
});

Thanks all

Kapellmeister answered 27/1, 2017 at 18:53 Comment(0)
K
4

I changed of idea. I simply send my pdf (from my controller) in 64 base and make in the ajax :

success: function (data) {
     window.open("data:application/pdf;base64," + data.data, '_blank'); 
}
Kapellmeister answered 1/2, 2017 at 7:5 Comment(0)
J
10

AJAX is just a thin client. Nothing happens with the response returned by default. You are responsible to making the download happen. However, doing that requires the File API that's part of HTML5. As a result, this is only possible in modern browsers (IE10+).

Inside your AJAX success method:

var blob = new Blob(data, { type: 'application/pdf' });
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);

EDIT

jQuery doesn't interpret the response type correctly by default. You'll need to modify your $.ajax call slightly:

$.ajax({
    url: '../Shipping/ShippingDownloadDNPriority?SALE_GUID=XXXXXXXXXXXXXX',
    data: { SALE_GUID: DropShipping.GetRowKey(rowIndexSale) },
    async: false,
    // -- ADD THIS --
    xhrFields: {
        responseType: 'blob'
    },
    success: function (data) {
        // code above here, but no longer need to create blob
        var a = document.createElement('a');
        var url = window.URL.createObjectURL(data);
        a.href = url;
        a.download = 'myfile.pdf';
        a.click();
        window.URL.revokeObjectURL(url);
    }
});

You can check out a CodePen here to see it working.

Jejunum answered 27/1, 2017 at 19:5 Comment(8)
Thanks, I will test this tomorrow moring.Kapellmeister
This doesn't work, I have this error : "Failed to construct 'Blob': The 1st argument is neither an array, nor does it have indexed properties"Kapellmeister
Sorry but this doesn't worrk also. I have the message "DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob')."Kapellmeister
Not sure what you've done, but as you can clearly see from the CodePen I included in my answer, the code works. Look for where your code diverges from mine, or at the very least update your question to include the most current state of your code.Jejunum
Also, what version of jQuery are you using? If you're still on the 1.* branch, that may be part of the issue. Like I said, this code requires modern browsers and jQuery 1.* maintains support for IE7.Jejunum
I changed of idea. I simply send my pdf (from my controller) in 64 base and make in the ajax : success: function (data) { window.open("data:application/pdf;base64," + data.data, '_blank'); },Kapellmeister
That's just as well, I suppose, but it doesn't force a download. The browser will attempt display the PDF in the new window and it's still on the user to save if they want to. Just FYI.Jejunum
The DOMException: Failed to set the 'responseType' property on 'XMLHttpRequest': [..] can be fixed by removing async: false.Simpatico
K
4

I changed of idea. I simply send my pdf (from my controller) in 64 base and make in the ajax :

success: function (data) {
     window.open("data:application/pdf;base64," + data.data, '_blank'); 
}
Kapellmeister answered 1/2, 2017 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.