如何解决此System.IO.FileNotFoundException错误
如何解决此System.IO.FileNotFoundException错误
- 该错误只在生产环境中发生(在调试中没有发生)。
- 该错误只在Windows登录后的第一次应用程序运行时发生。
- 当我们点击BtnUseDesktop并触发BtnUseDesktop_Click事件时,该错误发生(如下所示)。
- 事件查看器堆栈从The.Application.Name.Main()方法开始...
- 但我们的代码中没有这个方法(它是一个WPF应用程序)。
事件查看器
应用程序:The.Application.Name.exe 框架版本:v4.0.30319 描述:由于未处理的异常,进程终止。 异常信息:System.IO.FileNotFoundException 堆栈: at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen( System.Object, System.Delegate, System.Object, Int32, System.Delegate) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl( System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr) at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef) at System.Windows.Threading.Dispatcher.PushFrameImpl( System.Windows.Threading.DispatcherFrame) at System.Windows.Threading.Dispatcher.PushFrame( System.Windows.Threading.DispatcherFrame) at System.Windows.Threading.Dispatcher.Run() at System.Windows.Application.RunDispatcher(System.Object) at System.Windows.Application.RunInternal(System.Windows.Window) at System.Windows.Application.Run(System.Windows.Window) at The.Application.Name.Main()
BtnUseDesktop_Click
private void BtnUseDesktop_Click(object sender, RoutedEventArgs e) { AvSwitcher switcher = new AvSwitcher(); this.RunAsyncTask(() => switcher.SwitchToDesktop(this.windowSyncSvc.ActiveLyncWindowHandle)); }
Click事件调用的AvSwitcher
public class AvSwitcher { private DeviceLocationSvc deviceLocationSvc; private UIAutomationSvc uiAutomationSvc; private WindowMovingSvc windowMovingSvc; private ManualResetEvent manualResetEvent; private Modality audioVideo; public static bool IsSwitching { get; set; } public AvSwitcher() { this.deviceLocationSvc = new DeviceLocationSvc(); this.uiAutomationSvc = new UIAutomationSvc(); this.windowMovingSvc = new WindowMovingSvc(); } public void SwitchToDesktop(IntPtr activeLyncConvWindowHandle) { this.BeginHold(DeviceLocation.Desktop, activeLyncConvWindowHandle); } public void SwitchToWall(IntPtr activeLyncConvWindowHandle) { this.BeginHold(DeviceLocation.Wall, activeLyncConvWindowHandle); } private Conversation GetLyncConversation() { Conversation conv = null; if (LyncClient.GetClient() != null) { conv = LyncClient.GetClient().ConversationManager.Conversations.FirstOrDefault(); } return conv; } private void BeginHold(DeviceLocation targetLocation, IntPtr activeLyncConvWindowHandle) { AvSwitcher.IsSwitching = true; // make sure the class doesn't dispose of itself this.manualResetEvent = new ManualResetEvent(false); Conversation conv = this.GetLyncConversation(); if (conv != null) { this.audioVideo = conv.Modalities[ModalityTypes.AudioVideo]; ModalityState modalityState = this.audioVideo.State; if (modalityState == ModalityState.Connected) { this.HoldCallAndThenDoTheSwitching(targetLocation, activeLyncConvWindowHandle); } else { this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle); } } } private void HoldCallAndThenDoTheSwitching( DeviceLocation targetLocation, IntPtr activeLyncConvWindowHandle) { try { this.audioVideo.BeginHold( this.BeginHold_callback, new AsyncStateValues() { TargetLocation = targetLocation, ActiveLyncConvWindowHandle = activeLyncConvWindowHandle }); this.manualResetEvent.WaitOne(); } catch (UnauthorizedAccessException) { // the call is already on hold this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle); } } private void BeginHold_callback(IAsyncResult ar) { if (ar.IsCompleted) { DeviceLocation targetLocation = ((AsyncStateValues)ar.AsyncState).TargetLocation; IntPtr activeLyncConvWindowHandle = ((AsyncStateValues)ar.AsyncState).ActiveLyncConvWindowHandle; this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle); } Thread.Sleep(2000); // is this necessary this.audioVideo.BeginRetrieve(this.BeginRetrieve_callback, null); } private void DoTheSwitching(DeviceLocation targetLocation, IntPtr activeLyncConvWindowHandle) { DeviceLocationSvc.TargetDevices targetDevices = this.deviceLocationSvc.GetTargetDevices(targetLocation); this.SwitchScreenUsingWinApi(targetDevices.Screen, activeLyncConvWindowHandle); this.SwitchVideoUsingLyncApi(targetDevices.VideoDevice); this.SwitchAudioUsingUIAutomation( targetDevices.MicName, targetDevices.SpeakersName, activeLyncConvWindowHandle); AvSwitcher.IsSwitching = false; } private void SwitchScreenUsingWinApi(Screen targetScreen, IntPtr activeLyncConvWindowHandle) { if (activeLyncConvWindowHandle != IntPtr.Zero) { WindowPosition wp = this.windowMovingSvc.GetTargetWindowPositionFromScreen(targetScreen); this.windowMovingSvc.MoveTheWindowToTargetPosition(activeLyncConvWindowHandle, wp); } } private void SwitchVideoUsingLyncApi(VideoDevice targetVideoDevice) { if (targetVideoDevice != null) { LyncClient.GetClient().DeviceManager.ActiveVideoDevice = targetVideoDevice; } } private void SwitchAudioUsingUIAutomation( string targetMicName, string targetSpeakersName, IntPtr activeLyncConvWindowHandle) { if (targetMicName != null && targetSpeakersName != null) { AutomationElement lyncConvWindow = AutomationElement.FromHandle(activeLyncConvWindowHandle); AutomationElement lyncOptionsWindow = this.uiAutomationSvc.OpenTheLyncOptionsWindowFromTheConvWindow(lyncConvWindow); this.uiAutomationSvc.SelectTheTargetMic(lyncOptionsWindow, targetMicName); this.uiAutomationSvc.SelectTheTargetSpeakers(lyncOptionsWindow, targetSpeakersName); this.uiAutomationSvc.InvokeOkayButton(lyncOptionsWindow); } } private void BeginRetrieve_callback(IAsyncResult ar) { this.audioVideo.EndRetrieve(ar); this.manualResetEvent.Set(); // allow the program to exit } private class AsyncStateValues { internal DeviceLocation TargetLocation { get; set; } internal IntPtr ActiveLyncConvWindowHandle { get; set; } } }
在解决System.IO.FileNotFoundException的问题上,我曾经被误导过不止一次。花费了几个小时进行谷歌搜索、更新nuget包、版本检查,然后坐在一个完全更新的解决方案旁边,我重新意识到了产生这个错误的一个完全有效、更简单的原因。
如果在一个多线程的环境中(例如UI Dispatcher.Invoke),当线程管理器dll(文件)无法返回时,就会抛出System.IO.FileNotFoundException。所以,如果你的主UI线程A调用系统线程管理器dll B,而B调用你的线程代码C,但C由于一些不相关的原因(例如我遇到的空引用)而抛出异常,那么C就无法返回,B也无法返回,而A只会因为B丢失而责怪B抛出了FileNotFoundException。
在走上dll版本的路径之前...更仔细地检查一下你的线程代码是否抛出异常。
如何解决System.IO.FileNotFoundException问题
System.IO.FileNotFoundException意味着程序找不到指定的文件。因此,您需要检查代码在生产环境中要查找的文件。为了查看程序在生产环境中要查找的文件(查看异常的FileName属性),可以尝试以下技术:
1.写入调试日志(debug log);
2.使用Visual Studio Attach to Process;
3.使用Visual Studio Remote Debugging。
然后,查看计算机上的文件系统,看看文件是否存在。很可能的情况是文件不存在。
我将这个答案标记为正确答案,因为它引导我使用了"attach to process"。然后我编辑了答案,将"attach to process"作为生产调试选项。
“写入调试日志”是什么意思以及要写什么?
这意味着您需要存储一些记录,记录发生了什么以及调试时有用的相关信息。您可以自己开发日志记录解决方案,但强烈建议查看现有的日志库,如Serilog、NLog等。
这是否意味着无法从事件查看器提供的数据中找出缺失的文件?
这取决于事件查看器中的内容。我肯定不会依赖它的内容。将日志记录掌握在自己手中,这样您可以完全控制记录了哪些信息。