locked
Exception handling in async calls

    Question

  • I am trying to download a file from web using background transfer. But when I give an invalid link , the code throws exception like "An invalid parameter was passed to a function that considers invalid parameters fatal.". But the catch() section in code is not invoked in this situation. Below is the code. How can we catch and handle he exception in this case so that the app does not crash?

    Concurrency::cancellation_token_source* CancellationToken;

    CancellationToken = new cancellation_token_source(); String^ DownloadLink = "http://msite/trial/1.exe";// just an example link. Windows::Storage::StorageFolder^ folder = ApplicationData::Current->LocalFolder; String^ file_name = "MyDownloadedFile.exe";// The file will be downloaded in this name. task<StorageFile^>(folder->CreateFileAsync(file_name, CreationCollisionOption::ReplaceExisting)) . then([this,DownloadLink](StorageFile^ file) { BackgroundDownloader^ bd = ref new BackgroundDownloader( ); if( bd ) { DownloadOperation^ loader_op = bd->CreateDownload( ref new Uri(DownloadLink ), file ); if( loader_op ) { IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async; async = loader_op->StartAsync(); if( async ) { task<DownloadOperation^>(async, CancellationToken->get_token()). then([this] (DownloadOperation^ download) { try { ResponseInformation^ response = download->GetResponseInformation(); if( 200 == response->StatusCode ) { } else { } } catch( ... ) { } }); } else { } } } else { } });


    Wednesday, October 17, 2012 11:42 AM

Answers

  • I modified your code in a little bit and it can resolve the exception. Try using this....

    Paste it inside yourif( async )    { // Here }

    task<DownloadOperation^>(async, CancellationToken->get_token()).then([this] (DownloadOperation^ download) 
    					{ 
    							ResponseInformation^ response = download->GetResponseInformation();
    							if( 200 == response->StatusCode )
    							{
    
    							} 
    							else 
    							{
    							}
    							
    					}).then([this] (task<void> loaderTask)
    					{
    						try
    						{
    							loaderTask.get();
    						}
    						catch(Exception^ ex)
    						{
    							OutputDebugStringW(L"\n Exception: ");
    							OutputDebugStringW(ex->Message->Data());
    							OutputDebugStringW(L"\n");
    						}
    					});



    Here is whole code which works properly

    Concurrency::cancellation_token_source* CancellationToken; 
    	CancellationToken = new cancellation_token_source(); 
    	String^ DownloadLink = "http://msite/trial/1.exe";// just an example link.
    	Windows::Storage::StorageFolder^ folder = ApplicationData::Current->LocalFolder; String^ file_name = "MyDownloadedFile.exe";// The file will be downloaded in this name.
    
    	task<StorageFile^>(folder->CreateFileAsync(file_name, CreationCollisionOption::ReplaceExisting)).then([=](StorageFile^ file) 
    	{ 
    		
    		BackgroundDownloader^ bd = ref new BackgroundDownloader( ); 
    		if( bd ) 
    		{ 
    			DownloadOperation^ loader_op = bd->CreateDownload( ref new Uri(DownloadLink ), file );
    			if( loader_op )
    			{
    				IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async; 
    
    				async = loader_op->StartAsync(); 	
    				
    				if( async )
    				{
    					task<DownloadOperation^>(async, CancellationToken->get_token()).then([this] (DownloadOperation^ download) 
    					{ 
    						try
    						{
    							ResponseInformation^ response = download->GetResponseInformation();
    							if( 200 == response->StatusCode )
    							{
    
    							} 
    							else 
    							{
    							}
    						}
    						catch( ... )
    						{
    						}
    							
    					}).then([this] (task<void> loaderTask)
    					{
    						try{
    							loaderTask.get();
    						}catch(Exception^ ex){
    							OutputDebugStringW(L"\n Exception: ");
    							OutputDebugStringW(ex->Message->Data());
    							OutputDebugStringW(L"\n");
    						}
    					});
    				}
    				else
    				{
    				}
    
    			}
    		}
    		else
    		{
    		}
    		});


    Wednesday, October 17, 2012 4:35 PM
  • Take a look at the Handling errors in a task chain section in Asynchronous programming in C++ for further explanation and documentation of the exception handling Mokarrom demonstrates.

    --Rob

    Thursday, October 18, 2012 5:06 AM
    Owner

All replies

  • The try/catch is inside lambda expression so it only catches the exception of callback. 

    Maybe this is a solution. (I have not tested.)

    task<StorageFile^>( try {

    folder->CreateFileAsync(file_name, CreationCollisionOption::ReplaceExisting) } catch (...) { ; }).then([this,DownloadLink](StorageFile^ file)




    Charlie Chang L


    • Edited by Charlie C Wednesday, October 17, 2012 12:43 PM
    Wednesday, October 17, 2012 12:41 PM
  • Thank you, Charlie for your reply. Really, I am not familiar with a construct like :

    task<StorageFile^>(

    try {folder->CreateFileAsync(file_name,
    CreationCollisionOption::ReplaceExisting)

    } catch (...) {

    ;

    ie. try..catch() here is inside the task<StorageFile^> section. I tried this but this does not compile. I am more familiar with a construct like below:

    task<StorageFile^>(folder->CreateFileAsync(file_name,CreationCollisionOption::ReplaceExisting)).
    
    then([]( task<StorageFile^>f  )
    
    {
    
    try
    
    {
    
     f.get();
    
    }
    
    catch( ... )
    
    {
    
    }
    
    );

    Can u please re-write the original code with your suggestion?

    Also in my case, the exception occurs because it is trying to download from an invalid location.

    So I think the below section should cause the exception.

    IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async;
     async = loader_op->StartAsync(); 


    • Edited by its_me_here Wednesday, October 17, 2012 1:22 PM
    Wednesday, October 17, 2012 1:22 PM
  • In your case you may need to use Tony's solution at http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/de134da2-c8ae-4e60-847d-57642b4123c3 because your URL has not been authorized.

    My solution is a general solution to use StorageFile. However the original try/catch should be defined as a function.

    In your code, you may try to add a try/catch in front of 

    try {
    	BackgroundDownloader^ bd = ref new BackgroundDownloader();
    } ....

    or

    IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async; async =loader_op->StartAsync();

    Your original try is inside then that is a callback code.


    Charlie Chang L


    • Edited by Charlie C Wednesday, October 17, 2012 3:40 PM
    Wednesday, October 17, 2012 3:38 PM
  • I modified your code in a little bit and it can resolve the exception. Try using this....

    Paste it inside yourif( async )    { // Here }

    task<DownloadOperation^>(async, CancellationToken->get_token()).then([this] (DownloadOperation^ download) 
    					{ 
    							ResponseInformation^ response = download->GetResponseInformation();
    							if( 200 == response->StatusCode )
    							{
    
    							} 
    							else 
    							{
    							}
    							
    					}).then([this] (task<void> loaderTask)
    					{
    						try
    						{
    							loaderTask.get();
    						}
    						catch(Exception^ ex)
    						{
    							OutputDebugStringW(L"\n Exception: ");
    							OutputDebugStringW(ex->Message->Data());
    							OutputDebugStringW(L"\n");
    						}
    					});



    Here is whole code which works properly

    Concurrency::cancellation_token_source* CancellationToken; 
    	CancellationToken = new cancellation_token_source(); 
    	String^ DownloadLink = "http://msite/trial/1.exe";// just an example link.
    	Windows::Storage::StorageFolder^ folder = ApplicationData::Current->LocalFolder; String^ file_name = "MyDownloadedFile.exe";// The file will be downloaded in this name.
    
    	task<StorageFile^>(folder->CreateFileAsync(file_name, CreationCollisionOption::ReplaceExisting)).then([=](StorageFile^ file) 
    	{ 
    		
    		BackgroundDownloader^ bd = ref new BackgroundDownloader( ); 
    		if( bd ) 
    		{ 
    			DownloadOperation^ loader_op = bd->CreateDownload( ref new Uri(DownloadLink ), file );
    			if( loader_op )
    			{
    				IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async; 
    
    				async = loader_op->StartAsync(); 	
    				
    				if( async )
    				{
    					task<DownloadOperation^>(async, CancellationToken->get_token()).then([this] (DownloadOperation^ download) 
    					{ 
    						try
    						{
    							ResponseInformation^ response = download->GetResponseInformation();
    							if( 200 == response->StatusCode )
    							{
    
    							} 
    							else 
    							{
    							}
    						}
    						catch( ... )
    						{
    						}
    							
    					}).then([this] (task<void> loaderTask)
    					{
    						try{
    							loaderTask.get();
    						}catch(Exception^ ex){
    							OutputDebugStringW(L"\n Exception: ");
    							OutputDebugStringW(ex->Message->Data());
    							OutputDebugStringW(L"\n");
    						}
    					});
    				}
    				else
    				{
    				}
    
    			}
    		}
    		else
    		{
    		}
    		});


    Wednesday, October 17, 2012 4:35 PM
  • Take a look at the Handling errors in a task chain section in Asynchronous programming in C++ for further explanation and documentation of the exception handling Mokarrom demonstrates.

    --Rob

    Thursday, October 18, 2012 5:06 AM
    Owner
  • I modified the app with the above code..But the app still crashes even with exception caught.
    Thursday, October 18, 2012 12:33 PM
  • As exception is caught, so now follow it.

    You should  disable following option when a pop-up window is thrown in Visual Stdio.

    Break when this exception type is thrown

    Now execution will not terminated and execute your code inside the catch block.


    Thursday, October 18, 2012 12:42 PM
  • Thank you Mokkarrom .That solved my problem. But frankly, why is this option checked on by default? Is this really the way to handle exceptions? Is this intentionally checked on by default? It will work in my development PC and may not work in another. If one is to follow this method, this option will have to be unchecked in all development machines in the team, right?

    Thursday, October 18, 2012 2:36 PM
  • its_me_here

    You are right. Once you will unchecked, it will save to the project configuration. So it will persist later time for this particular project to any other development pc.

    Actually, Visual Studio automatically insert this breakpoint for debugging purpose. Sot it is not related to any other issues. In fact, Windows Store apps are deployed in a device not similar to any other typical apps.

    Thursday, October 18, 2012 3:05 PM
  • Is there any other option to catch this without setting VS options?
    Friday, October 19, 2012 2:32 AM
  • No. If you have VS set to break on the 1st chance exception then VS will break as soon as it is raised, before your exception handler is called. This is required to debug many scenarios, especially when exception handlers are involved. If you don't want the debugger to break when the exception is thrown then you need to change that option in the debugger settings.

    --Rob

    Friday, October 19, 2012 2:34 PM
    Owner
  • Thank you Rob.
    Saturday, October 20, 2012 5:39 PM