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

Gobelet
  • 453
  • 2
  • 7
  • 18

2 Answers2

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.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks, I will test this tomorrow moring. – Gobelet Jan 29 '17 at 19:27
  • 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" – Gobelet Jan 30 '17 at 17:01
  • 2
    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')." – Gobelet Jan 31 '17 at 13:44
  • 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. – Chris Pratt Jan 31 '17 at 13:54
  • 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. – Chris Pratt Jan 31 '17 at 13:58
  • 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'); }, – Gobelet Jan 31 '17 at 18:02
  • 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. – Chris Pratt Jan 31 '17 at 18:08
  • The `DOMException: Failed to set the 'responseType' property on 'XMLHttpRequest': [..]` can be fixed by removing `async: false`. – jerone Sep 26 '19 at 19:55
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'); 
}
Gobelet
  • 453
  • 2
  • 7
  • 18