简体   繁体   中英

How do I download a file that is returned by the server in an Ajax call?

I have a download function where the idea is that when the user clicks a button, it does an ajax call to a function that will create a csv file containing all of the information the user was viewing, and will return the file as a download. I have the server function creating a csv file, but I'm not sure how to make it download. This is my server-side code:

public ActionResult Download(Guid customerOrderId)
{
    var order = this.UnitOfWork.GetRepository<CustomerOrder>().Get(customerOrderId);

    var csv = new StringBuilder();

    csv.Append("Customer,Bill To Name,Ship To Name,Patient,Order#,Order Date," +
        "Line,Item#,Item Description,Qty,UOM,Price,Ext Price,Carrier," +
        "Notes,Purchase Order");

    var customer = order.CustomerNumber;
    var billToName = order.BTDisplayName;
    var shipToName = order.ShipTo.CustomerName;
    var orderNum = order.OrderNumber;
    var orderDate = order.OrderDate;
    var carrier = order.ShippingDisplay;
    var notes = order.Notes;
    var subtotal = order.OrderSubTotalDisplay;
    var total = order.OrderGrandTotalDisplay;
    var shipping = order.ShippingAndHandling;
    var tax = order.TotalSalesTaxDisplay;
    var patient = "";
    var purchaseOrder = order.CustomerPO;
    foreach (var cartLine in order.OrderLines)
    {
        var line = cartLine.Line;
        var itemNum = cartLine.Product.ProductCode;
        var itemDesc = cartLine.Description;
        var qty = cartLine.QtyOrdered;
        var uom = cartLine.UnitOfMeasure;
        var price = cartLine.ActualPriceDisplay;
        var ext = cartLine.ExtendedActualPriceDisplay;

        //Customer,Bill To Name,Ship To Name,Patient,Order#,Order Date," + 
        //"Line,Item#,Item Description,Qty,UOM,Price,Ext Price,Carrier," +
        //"Notes,Purchase Order
        var newLine = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}",
            customer, billToName, shipToName, patient, orderNum, orderDate, line, itemNum, itemDesc,
            qty, uom, price, ext, carrier, notes, purchaseOrder);

        csv.AppendLine(newLine);
    }

    csv.AppendLine();
    csv.AppendLine("Subtotal,Shipping & Handling,Tax,Total");
    csv.AppendLine(string.Format("{0},{1},{2},{3}", subtotal, shipping, tax, total));

    var filename = "MSD-Order-" + orderNum + ".csv";            

    var bytes = Encoding.UTF8.GetBytes(csv.ToString());
    return this.File(bytes, "text/csv");
}

And here is the ajax method:

function download(customerOrderId) {
    $.ajax({
        url: insite.core.actionPrefix + '/Checkout/Download/?customerOrderId=' + customerOrderId,
        type: 'Post',
        contentType: "application/json; charset=utf-8",
        async: false,
        cache: false,
        success: function (data) {
            alert("downloaded");
        },
        error: function (ex) {
            console.log(ex);
        }
    });    
}

In the success of the ajax call, I checked the value of "data" and it has the information, but I'm not sure how to make it download. What do I do once I receive the data?

Can't you just download it via a href like this?

public FileContentResult Download(Guid customerOrderId)
{
    // your code

    var response = new FileContentResult(bytes, "text/csv");
    response.FileDownloadName = filename;
    return response;
}

The link:

<a href="Checkout/Download/?customerOrderId=someId">Download</a>

You can store the file on server and send the URL with response. Then on ajax success function window.location=data.URL

Venerik has a valid answer as well, but keeping in line with your current implementation, I'd suggest the following.

You can return the string of the URL after saving the file to your server. Then do the window location redirection upon your success. I removed the variable assignments since nothing is being done with them other than sending to a method.

Here we write the file and return the string. You'll need to adjust the return to match your site information, etc.

public ActionResult Download(Guid customerOrderId)
{
    var order = this.UnitOfWork.GetRepository<CustomerOrder>().Get(customerOrderId);

    var csv = new StringBuilder();

    csv.AppendLine("Customer,Bill To Name,Ship To Name,Patient,Order#,Order Date," +
        "Line,Item#,Item Description,Qty,UOM,Price,Ext Price,Carrier," +
        "Notes,Purchase Order");

    foreach (var cartLine in order.OrderLines)
    {
        //Customer,Bill To Name,Ship To Name,Patient,Order#,Order Date," + 
        //"Line,Item#,Item Description,Qty,UOM,Price,Ext Price,Carrier," +
        //"Notes,Purchase Order

        csv.AppendLine(string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}",
            order.CustomerNumber, order.BTDisplayName, order.ShipTo.CustomerName, "", order.OrderNumber, order.OrderDate, cartLine.Line, cartLine.Product.ProductCode, cartLine.Description,
            cartLine.QtyOrdered, cartLine.UnitOfMeasure, cartLine.ActualPriceDisplay, cartLine.ExtendedActualPriceDisplay, order.ShippingDisplay, order.Notes, order.CustomerPO));
    }

    csv.AppendLine();
    csv.AppendLine("Subtotal,Shipping & Handling,Tax,Total");
    csv.AppendLine(string.Format("{0},{1},{2},{3}", order.OrderSubTotalDisplay, order.ShippingAndHandling, order.TotalSalesTaxDisplay, order.OrderGrandTotalDisplay));

    var filename = "MSD-Order-" + orderNum + ".csv";  

    using (StreamWriter sw = File.CreateText(Server.MapPath("~/files/" + filename)) 
    {
        sw.Write(csv.ToString());
    } 

    // adjust your url accordingly to match the directory to which you saved
    // '/files/' corresponds to where you did the File.CreateText
    // returning Content in an ActionResult defaults to text
    return Content("http://foo.com/files/" + filename);
}

And in your AJAX method update your success function to redirect the page which will prompt the download:

function download(customerOrderId) {
    $.ajax({
        url: insite.core.actionPrefix + '/Checkout/Download/?customerOrderId=' + customerOrderId,
        type: 'Post',
        contentType: "application/json; charset=utf-8",
        async: false,
        cache: false,
        success: function (data) {
            window.location.href = data;
        },
        error: function (ex) {
            console.log(ex);
        }
    });    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM