Consider the following code:
```c#
using System.Xml;
class Program
{
static void Main()
{
var reader = XmlReader.Create("a", new XmlReaderSettings { Async = true });
reader.Read();
}
}
Assuming the file `a` doesn't exist, this code is expected to throw `FileNotFoundException`. .Net Core 1.x does exactly that. But .Net Core 2.x and .Net Framework 4.x don't, they throw the exception wrapped in `AggreagteException`:
dotnet run -f netcoreapp1.1
Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'C:\code\tmp\coreappa'.
at System.IO.Win32FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.Win32FileSystem.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, FileStream parent)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.Xml.XmlSystemPathResolver.GetEntity(Uri uri, String role, Type typeOfObjectToReturn)
at System.Xml.XmlTextReaderImpl.FinishInitUriString()
at System.Xml.XmlTextReaderImpl.FinishInit()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlAsyncCheckReader.Read()
at Program.Main() in C:\code\tmp\coreapp\Program.cs:line 8
dotnet run -f netcoreapp2.0
Unhandled Exception: System.AggregateException: One or more errors occurred. (Could not find file 'C:\code\tmp\coreappa'.) ---> System.IO.FileNotFoundException: Could not find file 'C:\code\tmp\coreappa'.
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.Xml.XmlDownloadManager.<>c__DisplayClass2_0.b__0()
at System.Threading.Tasks.Task1.InnerInvoke() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult()
at System.Xml.XmlUrlResolver.d__15.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at System.Xml.XmlTextReaderImpl.FinishInitUriString()
at System.Xml.XmlTextReaderImpl.FinishInit()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlAsyncCheckReader.Read()
at Program.Main() in C:\code\tmp\coreapp\Program.cs:line 8
dotnet run -f netcoreapp2.1
Unhandled Exception: System.AggregateException: One or more errors occurred. (Could not find file 'C:\code\tmp\coreappa'.) ---> System.IO.FileNotFoundException: Could not find file 'C:\code\tmp\coreappa'.
at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.Xml.XmlDownloadManager.<>c__DisplayClass2_0.b__0()
at System.Threading.Tasks.Task1.InnerInvoke() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown --- at System.Xml.XmlUrlResolver.<GetEntityAsync>d__15.MoveNext() --- End of inner exception stack trace --- at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at System.Xml.XmlTextReaderImpl.FinishInitUriString() at System.Xml.XmlTextReaderImpl.FinishInit() at System.Xml.XmlTextReaderImpl.Read() at System.Xml.XmlAsyncCheckReader.Read() at Program.Main() in C:\code\tmp\coreapp\Program.cs:line 8 dotnet run -f net45 Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.IO.FileNotFoundException: Could not find file 'C:\code\tmp\coreapp\a'. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync) at System.Xml.XmlDownloadManager.<>c__DisplayClass4_0.<GetStreamAsync>b__0() at System.Threading.Tasks.Task1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Xml.XmlUrlResolver.d__15.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at System.Xml.XmlTextReaderImpl.FinishInitUriString()
at System.Xml.XmlTextReaderImpl.Read()
at Program.Main() in C:\code\tmp\coreapp\Program.cs:line 8
dotnet run -f net47
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.IO.FileNotFoundException: Could not find file 'C:\code\tmp\coreappa'.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
at System.Xml.XmlDownloadManager.<>c__DisplayClass4_0.b__0()
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Xml.XmlUrlResolver.d__15.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at System.Xml.XmlTextReaderImpl.FinishInitUriString()
at System.Xml.XmlTextReaderImpl.Read()
at Program.Main() in C:\code\tmp\coreapp\Program.cs:line 8
```
I think that XmlReader.Read() should not throw AggregateException, even though Async is set in the settings.
The code responsible for this behavior on .Net Core is:
Changing it from .Wait() and .Result to .GetAwaiter().GetResult() should fix the issue.
Changing it from .Wait() and .Result to .GetAwaiter().GetResult() should fix the issue.
Yup
@svick do you want to submit PR?
Corefx should consume an analyzer that flags all uses of Task.Wait. 馃槇
@karelz Yes, I just did: https://github.com/dotnet/corefx/pull/25681.
@jnm2 is it something you would like to create PR for? ;)
Sounds like this diverges from 4.x behavior. Is that acceptable?
Sounds like this diverges from 4.x behavior. Is that acceptable?
The netfx behavior is arguably a bug, if for no other reason than Read shouldn't throw a different exception type based on whether Async == false or true. My suggestion is it be fixed in netfx as well (under quirk if necessary), and assuming we're ok with that change, fix it in core, too.
is it something you would like to create PR for? ;)
Absolutely! But it'd probably actually get done this time 2018 by the time I get to the end of the list of PRs that people have asked me to do, so... not unless I'm already doing other corefx PRs.
Most helpful comment
The netfx behavior is arguably a bug, if for no other reason than Read shouldn't throw a different exception type based on whether Async == false or true. My suggestion is it be fixed in netfx as well (under quirk if necessary), and assuming we're ok with that change, fix it in core, too.