0

I have a C# method that works if you call it from another C# method, but not from javascript. How do I make it work from my ajax call?

I need to get a file based on an ID that is passed in, so I have an ajax post with the statusID. That ID is pulling the proper file in my C# method, it is just not giving the file save dialog.

However, if I call this from my C# page load method with a static statusID for testing purposes, it works just fine.

Here is the C# method:

    public void Get_Attachment_By_StatusID(int statusID)
    {
        SqlDataReader _reader = null;
        string _connString = "Data Source=133.31.32.33;Initial Catalog=Reports;Integrated Security=True";

        string sql = "SELECT a.StatusID ,a.DocumentName ,a.MIMETypeID ,a.Binary ,a.CreatedDate ,a.CreatedBy " +
            ",b.MIMEType FROM Attachments a Inner join  MIME_Types b on  a.MIMETypeID = b.ID " +
            "WHERE [StatusID] = {0} ";

        sql = string.Format(sql, statusID);

        try
        {
            _connection = new SqlConnection(_connString);
            _connection.Open();

            using (SqlCommand cmd = new SqlCommand(sql, _connection))
            {
                cmd.CommandType = System.Data.CommandType.Text;
                _reader = cmd.ExecuteReader();

                if (_reader.HasRows)
                {
                    while (_reader.Read())
                    {
                        System.Web.HttpContext.Current.Response.ClearContent();
                        System.Web.HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
                        System.Web.HttpContext.Current.Response.ContentType = _reader["MIMEType"].ToString();
                        System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + _reader["DocumentName"].ToString() + ";");
                        byte[] b = (byte[])_reader["Binary"];
                        System.Web.HttpContext.Current.Response.BinaryWrite(b);
                        System.Web.HttpContext.Current.Response.Flush();
                        System.Web.HttpContext.Current.Response.Close();
                    }

                }

                _reader.Close();
                _connection.Close();
            }
        }
        catch (Exception ex)
        {
            //Log exception to error Logging app
            string err = ex.ToString();

        }
        finally
        {
            if (_connection != null)
                _connection.Close();
            if (_reader != null)
                _reader.Close();
        }
    }

Here is how I am calling it from my page, in javascript:

function GetFile(statusID) {
    var url = '/Home/Get_Attachment_By_StatusID';

    $.ajax({
        url: url,
        type: 'post',
        cache: false,
        data: JSON.stringify({ "statusID": statusID }),
        contentType: 'application/json',
        success: function (data) {

        }
    });
}

Nothing happens. In Chrome, I don't see anything in the javascript console, and in IE, my console spits this out: "XML5619: Incorrect document syntax."

Again, if I go into the controller, and call the method in my page load method, it presents the save file dialog and saves the file just fine. So I must be doing something wrong with my javascript/jquery/ajax...

I am new to MVC4 and know I'm missing something here. What am I missing?

tereško
  • 58,060
  • 25
  • 98
  • 150
codesforcoffee
  • 179
  • 5
  • 11
  • 1
    Why are you sending JSON to the URL? Does it not with "normal" POST query strings? Try to use `data: {statusID: statusID}` (and lose the `contentType`). – gen_Eric Jul 22 '13 at 17:57
  • I would change your Action to accept a GET request instead of a `POST` and simply change the code on your client side to do `window.location=path/to/action_to_download_file/;` – Icarus Jul 22 '13 at 18:01
  • @Rocket Hazmat, The statusID gets there just fine, and the byte array is filled with the correct file. – codesforcoffee Jul 22 '13 at 18:02

2 Answers2

2

Use window.open('CONTROLLER_URL/STATUS_ID'); instead of an AJAX request.

<a target="_blank" href="javascript:window.open('/Home/Get_Attachment_By_StatusID/12345');">Test</a>
Louis Ricci
  • 20,804
  • 5
  • 48
  • 62
  • +1 but I would remove the `href="javascript:..."` and place it outside as to keep Javascript code separate from the markup. – Icarus Jul 22 '13 at 18:04
  • @LastCoder Can you please give me a sample of what to change in my c# method to make this one work? Right now it complains that statusID is null. How do I make it use what is tacked on to the URL after /Home/Get_Attachment_By_StatusID/? – codesforcoffee Jul 22 '13 at 18:17
  • @LastCoder Actually I got it, Icarus elaborated on it for me! Thanks! – codesforcoffee Jul 22 '13 at 19:20
1

Here's one suggestion, largely based on answer from LastCoder:

Decorate your action with the [HttpGet] attribute and change the parameter name to id:

[HttpGet]
public void Get_Attachment_By_StatusID(int id) ...

Now in your client-side code, simply do this:

function GetFile(statusID) {
    var url = '/Home/Get_Attachment_By_StatusID/'+statusID;
    window.location=url;
}
Icarus
  • 63,293
  • 14
  • 100
  • 115
  • -Thanks for trying to answer my question to LastCoder, but I did what you said and still get an id parameter is null, in my Get_Attachment_By_StatusID method. – codesforcoffee Jul 22 '13 at 18:31
  • Did you decorate it with a `[HttpGet]` attribute? and change the parameter name to `id`? If so, please post your updated code. – Icarus Jul 22 '13 at 18:36
  • I did but it didn't work until I went into my Routing options and added id as an optional parameter for my MVC project. In RouteConfig -> RegisterRoutes, I have this now and it works! routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Home", id = UrlParameter.Optional } – codesforcoffee Jul 22 '13 at 19:21