2

In my ASP.NET MVC project, I generated a excel file using ClosedXML.

It works well in non-ajax call. Here is my controller action method

 // Prepare the response
 Response.Clear();
 Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
 Response.AddHeader("content-disposition", "attachment;filename=\"" + reportHeader + ".xlsx\"");

 // Flush the workbook to the Response.OutputStream
 using (MemoryStream memoryStream = new MemoryStream())
 {
     MyWorkBook.SaveAs(memoryStream);
     memoryStream.WriteTo(Response.OutputStream);
     memoryStream.Close();
 }
 Response.End();

Now I am trying to do it via an ajax request. But the file is not sent from mvc controller.

$.ajax({
                url: url,
                type: "POST",
                data: fd,
                processData: false,  
                contentType: false,  
                beforeSend: function () {
                },
                success: function (response) {

                },
                error: function (request, status, error) {
                },
                complete: function () {
                }
            });

How can i accomplish it? Thank you in advance.

3
  • You just don't need an AJAX call to do this. Commented Jan 10, 2015 at 8:40
  • @king.code I want to do it in ajax response. Commented Jan 10, 2015 at 8:45
  • 1
    Have a look at this then. It's PHP but that's the way I guess. Commented Jan 10, 2015 at 8:50

2 Answers 2

7

Why not? ramiramilu was right about using window.location and iframe. I did the same thing but for ASP.NET MVC3.

I would suggest to use controller which returns FileContentResult

FYI about FileContentResult MSDN

And finally how I did it (Controller):

    [HttpPost]
    public HttpStatusCodeResult CreateExcel()
    {
        XLWorkbook wb = new XLWorkbook(XLEventTracking.Disabled); //create Excel

        //Generate information for excel file
        // ...

        if (wb != null)
        {
            Session["ExcelResult"] = wb;
            return new HttpStatusCodeResult(HttpStatusCode.OK);
        }

        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

    }

    [HttpGet]
    public FileContentResult ExcelResult(string reportHeader) //it's your data passed to controller
    {

        byte[] fileBytes = GetExcel((XLWorkbook)Session["ExcelResult"]);
        return File(fileBytes, MediaTypeNames.Application.Octet, reportHeader + ".xlsx");
    }

In model (you can remove static if you wish, and call it with instance)

public static byte[] GetExcel(XLWorkbook wb)
{
    using (var ms = new MemoryStream())
    {
        wb.SaveAs(ms);
        return ms.ToArray();
    }
}

AJAX:

$.ajax({
            url: "@Url.Action("CreateExcel")",
            async: true,
            type: "POST",
            traditional: true,
            cache: false,
            statusCode: {
                400: function () {
                    alert("Sorry! We cannot process you request");
                },
                200: function () {
                    $("#fileHolder")
                    .attr('src', 
                    '@Url.Action("ExcelResult")?reportHeader=' + 
                    reportHeader);
                }
            }
        });

BTW, I removed all exception handlers to simplify the code, but I assume You can do it yourself.

Sign up to request clarification or add additional context in comments.

5 Comments

Can you please tell me what is "fileHolder" used for?
Id for iframe. Purpose using same window.
statusCode part solved my problem because it was not hitting the success. thanks.
do i need to add any reference to get XlWorkbook in MVC5?
Sure. You can go to link in the question about closedXML
3

You cannot DIRECTLY download a file using AJAX, but you can download a file using window.location in conjunction with AJAX to make the file downloaded. What I mean is that if you use AJAX GET/POST all the file content will be in memory of the browser but cannot be saved to disk (because of JavaScript limitations).

Instead you can use window.location to point to a URL which in turn will fetch the file and prompt the save/open prompt. Or else you can use a hidden iFrame and set the src attribute of iFrame with the URL from which will download the file.

4 Comments

Read comment on OP from @king.code. AJAX requests are possible and he references an example. This solved the problem for me and yes, it is possible to download a file with AJAX if you find the need to do so.
@jaredbaszler, if you look at the king.code post, even they used window.location. Can you clearly explain the reason behind down vote?
Because you clearly state "you cannot download a file using AJAX" as your first sentence above. Which as you later state in your own post is not true. At first glance I was going to look for another alternative because of the way you presented your argument. Thankfully I read the response from @king.code above and found what I was looking for. Technically you are right about not downloading via AJAX but I wanted to utilize other features of AJAX with using window.location. The way you present your argument made me think that wasn't possible.
Agreed with your point, in that case a EDIT would make the essence of answer more appropriate, than projecting the entire answer as wrong one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.