【问题标题】:How to distinguish between different "types" of System.UnauthorizedAccessException in UWP application?如何区分 UWP 应用程序中 System.UnauthorizedAccessException 的不同“类型”?
【发布时间】:2017-01-31 16:50:58
【问题描述】:

此代码 sn-p 尝试读取 UWP 应用允许的位置之外的文件:

StorageFile sf2 = await StorageFile.GetFileFromPathAsync(Path.Combine("C:\\Temp", "spam.dat"));

抛出 System.UnauthorizedAccessException,它被 Visual Studio 2015 调试器拦截并显示在一个漂亮的弹出窗口中:

全文如下:

“System.UnauthorizedAccessException”类型的异常发生在 mscorlib.ni.dll 中,但未在用户代码中处理

WinRT 信息:无法访问指定的文件或文件夹 (C:\Temp\spam.dat)。该项目不在应用程序有权访问的位置(包括应用程序数据文件夹、可通过功能访问的文件夹以及 StorageApplicationPermissions 列表中的持久项目)。确认该文件未标记系统或隐藏文件属性。

“System.UnauthorizedAccessException”类型的异常发生在 mscorlib.ni.dll 中,但未在用户代码中处理

现在另一个代码sn-p(这个代码试图读取一个已经打开写的文件):

StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(ApplicationData.Current.LocalFolder.Path);
StorageFile file = await folder.CreateFileAsync("spam.dat", CreationCollisionOption.ReplaceExisting);
Stream fs = await file.OpenStreamForWriteAsync();
StorageFile sf2 = await StorageFile.GetFileFromPathAsync(Path.Combine(ApplicationData.Current.LocalFolder.Path, "spam.dat"));
await sf2.OpenStreamForReadAsync();

调试器中的异常屏幕看起来完全不同:

附加信息:访问被拒绝。 (来自 HRESULT 的异常:0x80070005 (E_ACCESSDENIED))

我不明白调试器对这些异常有何不同。在我的代码中,我需要了解获得 UnauthorizedAccessException 的原因 - 如果是因为文件被锁定以供读取,因为它被另一个作家占用(我可以稍后再试)或者由于其他原因,比如它在 LocalFolder 之外(而且不值得重试)。我实际上正在开发一个库,将由 UWP 应用程序的开发人员使用,所以我不知道我将获得哪个文件/文件路径,并且不能对权限、目录结构等做出任何假设。我只是在输入时获得路径而且,万一出了什么事,只能用异常处理来了解原因。

因此,Visual Studio 调试器以某种方式看到了差异,但我不知道如何以编程方式执行此操作。 InnerException 在两种情况下都为 null,HResult 也相同(0x80070005)。

【问题讨论】:

  • 其他开发人员将如何使用您的库?它会做什么?对您来说最好的办法可能是不处理异常,以便您的代码的使用者可以决定他们希望如何处理这种情况。
  • 该库有望处理多个线程甚至应用程序实例可以同时读取/写入相同共享文件的情况。行为已经设置,我无法更改它。该库已经在其他 .NET 平台上采用了这种方式,我只是在制作一个 UWP 端口。
  • 我很好奇为什么 Visual Studio 调试器显示这些异常的方式如此不同。它们之间有什么不同?

标签: c# exception visual-studio-2015 uwp


【解决方案1】:

如果您将 .NET 库移植到 UWP,大概它根本不依赖 StorageFile(在实现或公共接口中),所以我将继续使用具有明显错误的 .NET 类型(未经授权访问与 IO):

try
{
  var f = File.OpenRead(@"d:\temp\foo.txt");
}
catch (UnauthorizedAccessException ex)
{
  Debug.WriteLine(ex.Message);
}

try
{
  var localPath = ApplicationData.Current.LocalFolder.Path;
  var filename = Path.Combine(localPath, "foo.txt");
  var f1 = File.OpenWrite(filename);
  var f2 = File.OpenRead(filename);
}
catch (IOException ex)
{
  Debug.WriteLine(ex.Message);
}

如果我运行您的示例代码,则使用 StorageFile 的写入/读取示例不会出现任何异常(尽管我正在运行 Windows 10 Creator's Update 的 Insider Builds)。如果我尝试两次打开同一个文件进行写入,我可能会遇到异常,但它被投影为IOException

try
{
  var f = await StorageFile.GetFileFromPathAsync(@"d:\temp\foo.txt");
}
catch (UnauthorizedAccessException ex)
{
  Debug.WriteLine(ex.Message);
}

try
{
  var localFolder = ApplicationData.Current.LocalFolder;
  var f1 = await localFolder.CreateFileAsync("foo.txt", CreationCollisionOption.ReplaceExisting);
  var f2 = await localFolder.GetFileAsync("foo.txt");
  var s1 = await f1.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders);
  var s2 = await f2.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders);
}
catch (IOException ex)
{
  Debug.WriteLine(ex.Message);
}

【讨论】:

  • 这很有趣。尽管它没有直接回答我的问题,但它表明文件访问冲突不仅会导致 UnauthorizedAccessException,而且还会导致 IOException。在这种情况下,原始的非 UWP 库确实处理了 IOException,并且在进行迁移时,我发现这种情况没有发生(在我的情况下,发生了 UnauthorizedAccessException)。但是您的案例再次显示 IOException。似乎我都发生在不同的情况下。
  • 我直接复制了你的示例代码,并没有因为共享违规而出现任何错误。不过,这可能取决于您正在运行的 Windows 的特定版本(我认为我们最近可能已经放宽了规则)。您可以尝试检查HResult 属性,看看它是否不同?
  • 来自原帖:InnerException 在两种情况下都为空,HResult 也相同(0x80070005)。
  • 我也尝试在同一台机器上使用普通的 .NET 应用程序:FileStream fs1 = new FileStream("log.txt", FileMode.OpenOrCreate); FileStream fs2 = new FileStream("log.txt", FileMode.Open); Getting IOException (not UnauthorizedAccessException) The process cannot access the file '...\log.txt' because it is being used by another process. UnauthorizedAccessException 只发生在 UWP 对我来说..
  • 你有什么版本的 Windows?
【解决方案2】:

亚历克斯,

对于第二个,您正在使用 IO 流而不处理前一个流,您尝试在同一文件上创建另一个流。因此,它可以防止您说未经授权的访问。我已经介绍了刷新流并处理流然后代码对我有用。下面是修改后的代码:

StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(ApplicationData.Current.LocalFolder.Path);
        StorageFile file = await folder.CreateFileAsync("spam.dat", CreationCollisionOption.ReplaceExisting);
        Stream fs = await file.OpenStreamForWriteAsync();
        fs.Flush();
        fs.Dispose();
        StorageFile sf2 = await StorageFile.GetFileFromPathAsync(Path.Combine(ApplicationData.Current.LocalFolder.Path, "spam.dat"));
        var x = await sf2.OpenStreamForReadAsync();

【讨论】:

  • 您没有完全理解这一点。我的代码是专门为产生这个异常而设计的。我说的是异常处理,为了演示它,我需要让这个异常发生。
  • 哦,对不起,是的,您已经提到过。这是我的错。我以为你在第二种代码中也遇到了这样的异常..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 2011-09-26
相关资源
最近更新 更多