5

I am currently looking for a way to force a download of a file which is returned through a WebAPI controller.

I was using http://www.shawnmclean.com/blog/2012/04/force-download-of-file-from-asp-net-webapi/ as a reference.

On my client I am using an ajax GET call to send up an ID of an object and try to download the file

    exportList: (foo, callback) =>
        path = '/api/export/id'
        path = path.replace("id", foo.id)
        $.ajax(
            url: path,
            dataType: 'text',
            success: (data) =>
                callback(data)
            error: (data) =>
                callback(false)
        )

On the server-side, I have the above URI routed to the method below

    [AcceptVerbs("GET")]
    public HttpResponseMessage ExportList(int id)
    {
        string file = fooService.ExportList(id);

        if (file == null)
        {
            return Request.CreateResponse(HttpStatusCode.NoContent);
        }
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StringContent(file);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = "List.csv";

        return result;
    }

The fooService.ExportList method simply creates a csv string.

When watching the request come back to the client, the response does have the csv string in it, but the client is not prompted or forced to download it.

Is this the correct way to go about this?

2 Answers 2

3

I think your using javascript because of the dynamic id? If you can post directly with a form then use such solution. If javascript really is needed then use this piece of code to simulate a form action:

$.download = function (url, data, method) {
    if (url && data) {
        //data can be string of parameters or array/object
        data = typeof data == 'string' ? data : jQuery.param(data).replace("\+", " ");
        data = data.replace(/\+/g, " ");
        var inputs = '';
        jQuery.each(data.split('&'), function () {
            var pair = this.split('=');
            inputs += '<input type="hidden" name="' + pair[0] + '" value="' + pair[1] + '" />';
        });
        //send request
        jQuery('<form action="' + url + '" method="' + (method || 'post') + '">' + inputs + '</form>')
        .appendTo('body').submit().remove();
    };
};

The code to call the download (in stead of the ajax call):

path = '/api/export/id'
path = path.replace("id", foo.id)
$.download(path);
Sign up to request clarification or add additional context in comments.

2 Comments

this looks like a nice solution, but when used as described, both the data and method parameters will be empty, and so it does not get past the If statement. Could you possibly expand on the $.download method a little? I can get it to work by calling as $.download(path, " ", "GET")
your right you should call the download with data. If no data available then you could pass {} as a parameter i guess. I hope this will help you (If not just ask)!
3

don't use ajax to request a download. do a full GET request. if you want, open the download in the new window.

<a href="..." target="_blank">download file</a>

4 Comments

I am using dynamic IDs, so I can not really hard-code an href.
@Thewads What is stopping you from setting the href dynamically if you can make an AJAX call dynamically?
@Dismissile I could update the hrefs, but this would be create more overheads than other solutions
"overhead". i doubt that. whatever you find to be the easiest to maintain and least likely to introduce side effects would be a good solution.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.