locked
Problem with making download file from webMethod. RRS feed

  • Question

  • User-79977429 posted

    Hi

    in my asp.net app i have a webMethod which get a dataTable parameter as json, here is my code :

    public static void OpenAttachment(object objData)
            {
                string strData = objData.ToString();
                DataTable dtData = Newtonsoft.Json.JsonConvert.DeserializeObject<DataTable>(strData);
                if (dtData != null)
                {
                    byte[] pdfByteArray = Encoding.UTF8.GetBytes(dtData.Rows[0]["DocContent"].ToString());
                    string strFileName = string.Format("{0}{1}", dtData.Rows[0]["Title"], dtData.Rows[0]["Suffix"]);
    
                    HttpContext.Current.Response.Clear();
                    MemoryStream ms = new MemoryStream(pdfByteArray);
                    HttpContext.Current.Response.ContentType = "application/pdf";
                    HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", strFileName));
                    HttpContext.Current.Response.Buffer = true;
                    ms.WriteTo(HttpContext.Current.Response.OutputStream);
                    HttpContext.Current.Response.Flush();
                    HttpContext.Current.Response.SuppressContent = true;
                    HttpContext.Current.ApplicationInstance.CompleteRequest();                
                }
            }

    My problem is that after the last line, i'm getting this error inside ajax query :

    error : SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

    Here is my ajax query :

    function OpenAttachment(jsonData){
                $.ajax({
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    url: "MedicalHistory.aspx/OpenAttachment",
                    data: JSON.stringify({ objData: jsonData }),
                    dataType: "json",
                    success: function (response) {
                        alert(response);
                    },
                    error: function (request, status, error) {
                        alert('error : ' + error);
                    }
                });
            }

    Can anybody help me where is my problem & how to accomplish this task ?

    thanks in advance

    Thursday, September 26, 2019 10:53 PM

All replies

  • User-719153870 posted

    Hi hamed_1983,

    hamed_1983

    error : SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

    This seems a data related issue. Maybe your jsonData is with incorrect format or data?

    I built a demo based on your code and set jsonData a sample json data and the demo worked well, please take a look:

    <script>
            function OpenAttachment() {
                var jsonData = "[{'DocContent':'1788','Title':'19','Suffix':'aa'}]";
                $.ajax({
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    url: "JsonAjaxDemo.aspx/OpenAttachment",
                    data: JSON.stringify({ objData: jsonData }),
                    dataType: "json",
                    success: function (response) {
                        alert(response);
                    },
                    error: function (request, status, error) {
                        alert('error : ' + error);
                    }
                });
            }
        </script>

    You might need to provide a sample of your current jsonData in your OpenAttachment function, i guess it has some problems.

    Also, why not passing a string directly to the webmethod instead of converting jsonData to a json object and then convert the json object back to string?

    Hope it help.

    Best Regard,

    Yang Shen

    Friday, September 27, 2019 2:30 AM
  • User-79977429 posted

    Hi Yang Shen

    thanks for reply.

    The 'DocContent' field is byte[] array which store my pdf files in database. However this works in my windows application correctly (I tested the file which works inside my application), but i don't know why this not working in this project.

    As you told, I think the problem is related to sending dataTable (serializing to json) from my local webService or receiving and deserializing to dataTable!

    Please look at previous step of OpenAttachment function (Getting attachment) :

    function GetAttachmentByReceptionRowID(receptionRowID) {
                $.ajax({
                    type: "POST",
                    crossDomain: true,
                    contentType: "application/json; charset=utf-8",
                    url: "http://localhost:5473/MyESB.asmx/GetAttachmentByReceptionRowID",
                    data: '{receptionRowID:"' + receptionRowID + '"}',
                    dataType: "json",
                    async: false,
                    success: function (response) {
                        //alert('Ok!');
                        OpenAttachment(response.d);
                    },
                    error: function (request, status, error) {
                        alert('error' + request.error);
                    }
                });
            }

    And here is my webMethod :

    [WebMethod]
            public string GetAttachmentByReceptionRowID(string receptionRowID)
            {
                string strResult = string.Empty;
    
                Dictionary<string, object> dicParameters = new Dictionary<string, object>();
                dicParameters.Add("@receptionRowID", Guid.Parse(receptionRowID));
    
                DataTable dtResult = HelperClass.GetDataByProcedure("sp_ESB_GetAttachmentByReceptionRowID", dicParameters, System.Configuration.ConfigurationManager.ConnectionStrings["IranHealthESBConnectionString"].ConnectionString);
                Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings();           
                strResult = Newtonsoft.Json.JsonConvert.SerializeObject(dtResult);
    
                return strResult;
            }

    Can u plz help me where is the problem?

    Thanks in advance

    Friday, September 27, 2019 5:10 AM
  • User-719153870 posted

    Hi hamed_1983,

    I understand you want to provide more information and ajax and webmethod code you provided is reallyhelpful.

    But there's another much easier way that you can see the data in yout jsonData parameter. This series of operations you can apply in lots of situations, it's called debug in the dev tool.

    Please follow below steps:

    1. browse your current page in your browser, we will take chrome for example, press F12 to open the dev tool;
    2. click the "Sources" section above the tool and click your current page at left to see your front code;
    3. put several break points on the left of your code like you did in the VS;
    4. double click or drag to select parameters you want to view, like jsonData in OpenAttachment function and response.d in GetAttachmentByReceptionRowID function, right click and choose "add selected text to watches";
    5. At last, you can see all the parameters value in the right "Watch" section right;
    6. Fire your GetAttachmentByReceptionRowID function to debug the code;

    After all those steps, you will be able to check if the jsonData is in the right format or even if it's correct in value.

    This will be a more intuitive information you can share with us.

    Hope this could help.

    Best Regard,

    Yang Shen

    Friday, September 27, 2019 8:36 AM
  • User753101303 posted

    Hi,

    dataType asks for a json  response but you are sending back an application/pdf content. Also I'm not sure using Ajax have some real purpose here. Using the content-disposition attachment the browser knows this is a download rather to replace the current page shown in the browser so using Ajax is most often not needed for a download (or which benefit do you expect ?)

    Friday, September 27, 2019 8:47 AM
  • User-79977429 posted

    Thanks for reply

    As i found, i have 2 problems :

    1. Getting attachment from ESB (as JSON string)
    2. Opening received attachment in step 1

    The first one solved by changing my GetAttachmentByReceptionRowID (in ESB project) to send just byte[] instead of complete dataTable as follow :

    [WebMethod]
            public string GetAttachmentByReceptionRowID(string receptionRowID)
            {
                string strResult = string.Empty;
    
                Dictionary<string, object> dicParameters = new Dictionary<string, object>();
                dicParameters.Add("@receptionRowID", Guid.Parse(receptionRowID));
    
                DataTable dtData = HelperClass.GetDataByProcedure("sp_ESB_GetAttachmentByReceptionRowID", dicParameters, System.Configuration.ConfigurationManager.ConnectionStrings["IranHealthESBConnectionString"].ConnectionString);
                string strDocContent = Encoding.Default.GetString((byte[])dtData.Rows[0]["DocContent"]);
                strResult = Newtonsoft.Json.JsonConvert.SerializeObject(strDocContent);
    
                return strResult;
            }

    Also, in my web project, i;ve changed OpenAttachment method as follow :

    [WebMethod]
            public static void OpenAttachment(object objData)
            {
                if (objData == null)
                    return;
    
                string strDocContent = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(objData.ToString());
                byte[] pdfByteArray = Encoding.Default.GetBytes(strDocContent);
                string strFileName = string.Format("{0}{1}", DateTime.Now.Ticks, ".pdf");
                string strFullPath = HttpContext.Current.Server.MapPath(string.Format("~/Uploads/{0}", strFileName));
    
                if (SaveFile(strFullPath, pdfByteArray))
                {
    		// nothing!
                }
    	}

    As u see in above code, i've create a file as pdf and works correctly (I also open created pdf file correctly).

    Now i want to make download for user!! here is step 2!! If i change above code as follow, facing the same error :

    [WebMethod]
            public static void OpenAttachment(object objData)
            {
                if (objData == null)
                    return;
    
                string strDocContent = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(objData.ToString());
                byte[] pdfByteArray = Encoding.Default.GetBytes(strDocContent);
                string strFileName = string.Format("{0}{1}", DateTime.Now.Ticks, ".pdf");
                string strFullPath = HttpContext.Current.Server.MapPath(string.Format("~/Uploads/{0}", strFileName));
    
                if (SaveFile(strFullPath, pdfByteArray))
                {
                    HttpContext.Current.Response.Clear();
                    MemoryStream ms = new MemoryStream(pdfByteArray);
                    HttpContext.Current.Response.ContentType = "application/pdf";
                    HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", strFileName));
                    HttpContext.Current.Response.Buffer = true;
                    ms.WriteTo(HttpContext.Current.Response.OutputStream);
                    HttpContext.Current.Response.Flush();
                    HttpContext.Current.Response.SuppressContent = true;
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                }
    	}

    Where is the problem and how to solve it ?

    Thanks in advance

    Friday, September 27, 2019 9:59 AM
  • User753101303 posted

    Still unclear. You now splitted downloading the file in two steps which doesn't seemed a problem?

    If you want to trigger a download file dialog you can just request the needed resource just using a "a" link. The browser uses the content disposition to trigger the download dialog and knows the current page should be left intact. It can be as simpler as that.

    Else we would need first your requirements to understand why Ajax is really needed. In this case it would be something such as :
    https://codepen.io/chrisdpratt/pen/RKxJNo

    Ajax is about handling programmatically the response and so you still have to use this kind of trick to have finally the browser handling the download dialog (and so the easiest apoproach is to just let the browser handle the whole download).

    Friday, September 27, 2019 11:50 AM
  • User-79977429 posted

    Thanks PatriceSc

    I've split my goal into 2 steps just for clarification.

    In my web project user click on a button which occures these steps :

    1. An ajax query call webService from ESB url to get pdf file as json.
    2. The received json data deserialize & save in server as pdf file (Of course, there is a another ajax query call webService to accomplish this task).
    3. Make download request to the created pdf file.

    I've changed my OpenAttachment webMethod as follow :

    [WebMethod]
            public static void OpenAttachment(object objData)
            {
                if (objData == null)
                    return;
    
                string strDocContent = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(objData.ToString());
                byte[] pdfByteArray = Encoding.Default.GetBytes(strDocContent);
                string strFileName = string.Format("{0}{1}", DateTime.Now.Ticks, ".pdf");
                string strPhisycalFullPath = HttpContext.Current.Server.MapPath(string.Format("~/Uploads/{0}", strFileName));
    
                if (SaveFile(strPhisycalFullPath, pdfByteArray))
                {
                    try
                    {
                        HttpContext.Current.Response.ContentType = "application/pdf";
                        HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", strFileName));
                        HttpContext.Current.Response.TransmitFile(strPhisycalFullPath);
                        HttpContext.Current.Response.End();
                    }
                    catch (Exception ex)
                    {
                        return;
                    }
    	    }
             }

    But i'm facing the Thread was being aborted exception! As u see in above code, i've handled all exceptions inside try/catch block (which describes here) but still i'm facing the same error!!

    Can anybody help me how to accomplish this task?

    Thanks in advance.

    Friday, September 27, 2019 10:27 PM
  • User475983607 posted

    Return the PDF's URL to the AJAX method.  The URL can be the actual file or a web method that returns a file stream.  In the success handler set windows.location to the URL which will cause the browser to download the file.  Another option is using an iFrame and setting the iFrame's scr attribute to the PDF URL.  The later will also download a file.

    https://stackoverflow.com/questions/4545311/download-a-file-by-jquery-ajax

    Friday, September 27, 2019 10:44 PM
  • User-79977429 posted

    Thanks mgebhard

    It works via this javascript function inside success event :

    function downloadFile(url) {
                var a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.download = 'LabResult.pdf';
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(url);
            }

    But i'm facing a new problem! how to detect when download completed to delete requested file in server. because i've do download operation in javscript (at clientSide), i can not understand when the file downloading complete to delete file from server.

    Is there any way to accomplish this task in my webMethod (or another idea to accomplish my task)?

    thanks in advance

    Saturday, September 28, 2019 4:19 PM
  • User-719153870 posted

    Hi hamed_1983,

    function downloadFile(url) {
                var a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.download = 'LabResult.pdf';
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(url);
            }

    how to detect when download completed to delete requested file in server

    If you are saying that you want to detect a hyperlink.click() download file event, as far as i know, it's not possible.

    Because, after the click event triggered, the download operation is offered to the browser. In this case, you will need to detect the browser download event, maybe you can find some browser extension for this case, even though, the extension will be spesific for one browser which is not the ideal situation.

    If you are willing to change the download event, you can refer to Detecting the File Download Dialog In the Browser for more information.

    Best Regard,

    Yang Shen

    Monday, September 30, 2019 2:57 AM
  • User-79977429 posted

    Thanks Yang Shen

    Is there any way to accomplish this task in server side ?

    Monday, September 30, 2019 9:24 AM
  • User-719153870 posted

    Hi hamed_1983,

    I'm sorry that i might be wrong.

    Here i found many solutions about detect download complete in Asp.Net.

    For your code situation, you might want to see this jquery.filedownload solution, also please refer to this demo.

    This is really similar to your situation.

    Hope it could help, sorry again.

    Best Regard,

    Yang Shen

    Monday, September 30, 2019 9:52 AM
  • User753101303 posted

    I'm not sure why you are going now through a file while your first version was just retrieving data from your db (and now you need a way to clean up this file)... Please avoid to needlessly change your approach while others are trying to help.

    The starting point when serving files in a database with Web Forms is most often to use https://yomotherboard.com/download-file-using-ashx-handler/ and just have a link pointing to this ASHX location (with an id parameter to know which file should be sent back).

    Sometimes it's best to start with something simple that works and then move your code forward depending on what you need rather than to use right away a more complex approach which is perhaps not needed at all.

    Monday, September 30, 2019 11:40 AM