locked
How to write javascript from HttpHandler's HttpContext RRS feed

  • Question

  • User-209105085 posted

    I have a asynchronous http handler that downloads the file. When user clicks on the download link it invokes the httphandler, and the broswer's download window pops up. Depending on the browser version, the window may be different. but the current page's content remains as it is and download starts.

    If any exception occur on the server is there any way to inform the user without clearing the page? Becuase in Catch block if i do context.Response.Write("Something Bad Happened") it will clear the content of the existing page.

    so i thought of sending alert so the current browser content will remain as it is

    below is my code

    public class DownloadFileHandler : IHttpAsyncHandler
        {
            public bool IsReusable { get { return false; } }
    
            public DownloadFileHandler()
            {
            }
    
            public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
            {
                AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
                asynch.StartAsyncWork();
                return asynch;
            }
    
            public void EndProcessRequest(IAsyncResult result)
            {
            }
    
            public void ProcessRequest(HttpContext context)
            {
                throw new InvalidOperationException();
            }
        }
    
    class AsynchOperation : IAsyncResult
        {
    
            private bool _completed;
            private Object _state;
            private AsyncCallback _callback;
            private HttpContext _context;
    
            bool IAsyncResult.IsCompleted
            {
                get
                {
                    return _completed;
                }
            }
    
            WaitHandle IAsyncResult.AsyncWaitHandle
            {
                get
                {
                    return null;
                }
            }
    
            Object IAsyncResult.AsyncState
            {
                get
                {
                    return _state;
                }
            }
    
            bool IAsyncResult.CompletedSynchronously
            {
                get
                {
                    return false;
                }
            }
    
            public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
            {
                _callback = callback;
                _context = context;
                _state = state;
                _completed = false;
            }
    
            public void StartAsyncWork()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
            }
    
            private void StartAsyncTask(Object workItemState)
            {
                try
                {
    //Instantiate the Stream here
    context.Response.ContentType = "application/x-zip-compressed"; context.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename); int read = 0; //prevent infinite loop if user disconnects while (context.Response.IsClientConnected && (read = _stream.Read(buffer, 0, buffer.Length)) > 0) { context.Response.OutputStream.Write(buffer, 0, read); context.Response.Flush(); } } catch (Exception ex) { if (_context.Response.IsClientConnected && _context.Response != null) { //??? How to send Javascript alert here and
    //??? what would be the content type and What
    //??? What about the header(Conetent-Disposition which is already added in the response) _context.Response.Write("How to send javascript alert here??"); _context.Response.Flush(); } } finally { // Close the response if (_context != null && _context.Response != null) { _context.Response.Close(); } } _completed = true; _callback(this); } }

    Questions:

    1>When exception occur, i guess i need to change the content type if i want to write javascript back to user. What would be the contenttype? ( Please see inline comments in the code)

    2>Is there any other way to inform user that something bad hapend without clearing the content?

    Wednesday, February 12, 2014 4:27 PM

Answers

  • User-760709272 posted

    I wouldn't bother rethrowing it.  If the exception occurs before you have written anything to the output stream then in that case you can write out a normal html page instead.  The issue is only trying to output html *after* data has been sent.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 13, 2014 4:27 AM

All replies

  • User-760709272 posted

    You are sending a response which is triggered by a request.  When you start the download you are telling the client it is receiving a zip file and you start to push the data.  Once the headers are written, you can't then undo that and tell the browser "actually it's not a zip file you're getting any more so abort what you were doing, it's now a 200 OK Html page that I'm sending"  The download is separate from the browser anyway, I can start downloading a file then close my browser but leave the download running, so where is your html going to show?  This is the stateless nature of the internet.  If there is a problem with the download the user will know because the download manager will tell them.

    Wednesday, February 12, 2014 4:41 PM
  • User-209105085 posted

    Thanks

    then in above scenario how one should handle it? Should i rethrow the exception or eat the exception? how download manger would know?

    try
    {
     Download()
    }
    catch(Exception ex)
    {
      //Log ex here
    
    // rethrow exception here throw }
    try
    {
     Download()
    }
    catch(Exception ex)
    {
      //Log ex here
     
      // Dont rethrow, eat the exception here
    }



    Wednesday, February 12, 2014 5:18 PM
  • User-760709272 posted

    Just ignore exceptions, the connection will be aborted and the user will be told the download failed.

    Wednesday, February 12, 2014 5:20 PM
  • User-209105085 posted

    But i have to log the exception so we can diagnose why download failed. 

    That means in catch block after logging just rethrow the exception as below ?????

    try
    {
      Download()
    }
    catch(Exception ex)
    {
      //Log ex here
    throw; } finally { if (_context != null && _context.Response != null) { _context.Response.Close(); } }

    Wednesday, February 12, 2014 5:23 PM
  • User-760709272 posted

    You can log the exception ok, you just can't really do anything to inform the client.

    Wednesday, February 12, 2014 6:23 PM
  • User-209105085 posted

    Thanks, I do understand that i cant infom client. But after logging is done,  should rethrow the exception or just leave it to terminate the call? Also note that exception may occur before even download starts, and in that case there wont be any popup on client side.

    Wednesday, February 12, 2014 10:16 PM
  • User-760709272 posted

    I wouldn't bother rethrowing it.  If the exception occurs before you have written anything to the output stream then in that case you can write out a normal html page instead.  The issue is only trying to output html *after* data has been sent.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 13, 2014 4:27 AM
  • User1622957740 posted

    When you're making a link or form submission request from the browser to the server you are requesting a new page and the server will always response with new HTTP content, regardless of whether the request works or not. The result is whatever the server returns and the original output is cleared and new content is set to the result or - if it's a server error a server or ASP.NET error display which in effect becomes the HTTP response.

    If you want to request data from within the page, capture the output and take action from the current page you need to use AJAX calls to do that. You can a something like jQuery to make a call to the server and capture the output:

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript">   </script>
        <script>
            $("button").click(function() {
                $.ajax({ url: "myhandler.hnd" })
                    .done(function(resultText) {
                        // update existing page content from server response
                        $("#result").text(resultText);
                        alert('done');
                    })
                    .fail(function(xhr, status) {
                        alert('server call failed ' + status);
                    })
                    .always(function() {
                        alert('always');
                    });
            });
        </script>

    If you just want to wait for the call to complete and then navigate you can take over the .done() handler and navigate from there with window.location='newpage.html' or whatever...

    +++ Rick ---

    Tuesday, February 25, 2014 6:15 AM