Why I'm getting System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.' when downloading images ?

sharon glipman 441 Reputation points
2021-10-10T16:29:14.26+00:00
int counter = 0;  
            protected override async void OnLoad(EventArgs e)  
            {  
                var filenames = new List<string>();  
                var wc = new WebClient();  
                var progressPerUrl = 100 / (float)urls.Count;  
                for (var i = 0; i < urls.Count; i++)  
                {  
                    var url = urls[i];  
                    wc.Headers.Add("User-Agent", "User-Agent: CoolTool/0.0 (https://example.org/cool-tool/; cool-tool@example.org) generic-library/0.0");  
                    var filename = $"out-{i}.jpg";  
                    filenames.Add(filename);  
                    wc.DownloadProgressChanged += (ee, sender) => {  
                        var urlProgressStart = progressPerUrl * i;  
                        progressBarText1.Value = (int)(urlProgressStart + progressPerUrl * sender.ProgressPercentage / 100f);  
      
                    };  
                    await wc.DownloadFileTaskAsync(url, filename);  
                }  
                var saveTasks = new List<Task>();  
                foreach (var filename in filenames)  
                {  
                    saveTasks.Add(Task.Run(() => {  
                        var newFilename = @"d:\satImages\satImage" + counter + ".gif";  
                        Image.FromFile(filename).Save(newFilename, ImageFormat.Gif);  
                    }));  
      
                    counter++;  
                }  
                await Task.WhenAll(saveTasks);  
            }  

For some reason without any break point I'm getting the exception error :

System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'

But if I put a break point on the line :

saveTasks.Add(Task.Run(() => {  

And click continue each time when it finish(10 images) it's moving to the last line :

await Task.WhenAll(saveTasks);  

And everything is fine.

But without a break point it's throwing the exception :

ExternalException: A generic error occurred in GDI+.

This exception was originally thrown at this call stack:
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageCodecInfo, System.Drawing.Imaging.EncoderParameters)
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageFormat)
Extract.Form1.OnLoad.AnonymousMethod__1() in Form1.cs
System.Threading.Tasks.Task.InnerInvoke()
System.Threading.Tasks.Task.Execute()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Extract.Form1.OnLoad(System.EventArgs) in Form1.cs
System.Runtime.CompilerServices.AsyncMethodBuilderCore.ThrowAsync.AnonymousMethod__6_0(object)

The full details :

System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Extract.Program.Main() in D:\Csharp Projects\Extract\Program.cs:line 19

This exception was originally thrown at this call stack:
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageCodecInfo, System.Drawing.Imaging.EncoderParameters)
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageFormat)
Extract.Form1.OnLoad.AnonymousMethod__1() in Form1.cs
System.Threading.Tasks.Task.InnerInvoke()
System.Threading.Tasks.Task.Execute()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Extract.Form1.OnLoad(System.EventArgs) in Form1.cs
System.Runtime.CompilerServices.AsyncMethodBuilderCore.ThrowAsync.AnonymousMethod__6_0(object)

Inner Exception 1:
ExternalException: A generic error occurred in GDI+.

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,827 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,233 questions
0 comments No comments
{count} votes

Accepted answer
  1. P a u l 10,406 Reputation points
    2021-10-10T16:49:49.047+00:00

    The error itself is likely caused by that program attempting to write to the same file location for every filename. The reason for this is that the code that's ran inside of Task.Run isn't necessarily ran immediately. All that code does is schedule some work to be done with the ThreadPool:
    https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=net-5.0

    So the loop has already iterated to the end (having incremented 10 times) by the time that the inner function has even run. The result is that every instance attempts to write to satImage11.gif. The fix is to make a copy of that global counter value to a variable that won't change, then use that inside the Task.Run callback instead, and it'll keep it's original value.

       foreach (var filename in filenames) {  
       	var counterCopy = counter;  
         
       	saveTasks.Add(Task.Run(() => {  
       		var newFilename = @"c:\bla\satImage" + counterCopy + ".gif";  
       		Image.FromFile(filename).Save(newFilename, ImageFormat.Gif);  
       	}));  
         
       	counter++;  
       }  
    
    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful