Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass JavaScript/JSON array to MVC 'GET' Method

I'm trying to pass an array/IEnumerable of Guids to a MVC 'GET' method that looks like this:

[HttpGet]
public ActionResult ZipResults(IEnumerable<Guid> ids)
{
    using(var zip = new Zip())
    {
        foreach(var id in ids)
        {
            var stream = GetDataStream(id);
            zip.AddEntry("filename.txt", stream);
        }
    }

    var outputStream = new MemoryStream();
    zip.Save(outputStream);

    return FileStreamResult(outputStream, "application/octet-stream"){
        FileDownloadName = "Results.zip" };
}

And my javascript looks like this:

$('the-button').click(function(){

    // 1. Get the guids from a table and add to javascript array (works fine)
    // 2. Grey-out screen and show processing indicator (works fine)

    // 3. This is how I'm calling the "ZipResults" action:
    $.ajax({
        url: '@Url.Action("ZipResults", "TheController")',
        type: 'GET',
        data: $.toJSON({ ids: _ids }),
        dataType: 'json',
        contentType: 'application/json;charset=utf-8',
        traditional: true,
        success: function(){
            // Undo the grey-out, and remove processing indicator
        },
        error: function(){
        }
    });
});

My expectation is that this will popup the download dialog on the browser. As it is, the javascript array being passed to the controller is null (on the server-side, it works correctly client-side). Also, this works fine with a 'POST', however, a 'POST' method used this way will not force the download dialog...

Open for suggestions :)

like image 425
Didaxis Avatar asked Feb 02 '12 14:02

Didaxis


2 Answers

You should avoid sending JSON requests with GET. Try like this:

var _ids = [ 
    'e2845bd4-9b3c-4342-bdd5-caa992450cb9', 
    '566ddb9d-4337-4ed7-b1b3-51ff227ca96c',
    '25bc7095-a12b-4b30-aabe-1ee0ac199594'
];

$.ajax({
    url: '@Url.Action("ZipResults", "TheController")',
    type: 'GET',
    data: { ids: _ids },
    dataType: 'json',
    traditional: true,
    success: function() {
        // Undo the grey-out, and remove processing indicator
    },
    error: function() {

    }
});

This being said, I see that you are invoking some controller action which returns a file stream to download. You shouldn't be using AJAX at all to do this. The reason for that is that in your success callback you will get the contents of the ZIP file but there's not much you could do with it. You cannot save it to the client computer, you cannot prompt the user to choose a save location, you are pretty much busted.

So no AJAX calls if you want to download a file. You could use a simple anchor:

@Html.ActionLink("download zip", "ZipResults", "TheController", null, new { id = "download" })

and then:

$(function() {
    $('#download').click(function() {
        var _ids = [ 
            'e2845bd4-9b3c-4342-bdd5-caa992450cb9', 
            '566ddb9d-4337-4ed7-b1b3-51ff227ca96c',
            '25bc7095-a12b-4b30-aabe-1ee0ac199594'
        ];

        var url = this.href;
        for (var i = 0; i < _ids.length; i++) {
            if (url.indexOf('?') > 0) {
                url += '&ids=' + encodeURIComponent(_ids[i]);
            } else {
                url += '?ids=' + encodeURIComponent(_ids[i]);
            }
        }

        window.location.href = url;

        return false;
    });
});
like image 164
Darin Dimitrov Avatar answered Oct 15 '22 04:10

Darin Dimitrov


The problem is that a GET doesn't get a request body. I suspect that if you look at the client issued request, you would find that it is trying to shove an enumerable onto the query string....

Post -> Redirect seems like the best course of action here.

like image 44
Tetsujin no Oni Avatar answered Oct 15 '22 03:10

Tetsujin no Oni