System.UnauthorizedAccessException - 访问路径被拒绝

11

这是一个稍微棘手的问题,所以请耐心等待...

我有一个简单的小方法:

Public Overloads Shared Function DoStuff(ByVal path As String) As Boolean
        If Not IO.File.Exists(ipath) Then Throw New ArgumentException

        Dim result As Boolean
        Using fs As FileStream = New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)
            ' do stuff here, details are not important
            fs.Close()
        End Using

        Return result
    End Function

我很欣赏这种方法不显示流如何使用,但细节是无关紧要的,因为我将在下面解释。
这个方法被紧密地放置在一个类库中;一个我们在各种其他项目中引用的助手。显然,对于大多数情况,只要路径有效、可访问等等,那段代码看起来应该没问题。
现在出现了问题。我有一个 WCF 服务库,它引用并使用上述助手程序集中的方法。WCF 服务库托管在一个 Windows 服务中,而该 Windows 服务又驻留在我们的一台服务器上。WCF 服务有一个操作,接收一个 UNC 路径用于文件,在正常流程中,调用上面助手类中的方法。
我发送的路径是网络上的共享文件的路径。"Using fs As..." 这一行失败,并抛出以下异常:
System.UnauthorizedAccessException: 访问路径 "我的文件路径在此列出" 被拒绝。 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) 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) at MyHelperAssemblyName.DoStuff(String filePath) in 异常的其余部分是指向方法、程序集、WCF 服务等的堆栈跟踪"
现在,我列出了一些为诊断问题所尝试的事情(包括愚蠢明显的步骤)的清单:
  • 将Stack Trace中列出的路径复制并粘贴到Windows Explorer中(本地计算机和服务器上都要这样做),以确保文件存在且可访问-->能够访问该文件

  • 确保Windows服务帐户对文件具有足够的读取权限-->有效权限将服务帐户列为具有完全控制权

  • 更改Windows服务帐户以使用我的个人管理员帐户(临时措施),并显然重新启动服务以使更改生效-->相同的代码行失败

  • 复制包含文件的目录到我的本地计算机,并针对我的本地计算机运行服务(我们想确保托管文件的NAS不是原因)-->相同的代码行失败

  • 创建一个快速控制台应用程序,将辅助程序集方法中的代码复制并粘贴到应用程序中,注入相同的文件路径,在本地计算机上运行,然后在服务器上运行(通过在服务器上远程连接使用我之前提到的相同管理员帐户,并运行它)-->应用程序运行代码没有任何问题

  • 创建控制台应用程序,并使用bulk standard方式在控制台应用程序中托管WCF服务库。在本地运行应用程序,然后使用WcfStorm针对我指定为控制台应用程序基地址的本地地址调用相同的方法和路径,正常服务无法运行-->来自WcfStorm的结果确认代码没有问题

  • 仔细检查WCF服务库的代码,以确保没有任何奇怪的条件逻辑会影响我的测试-->帮助方法几乎是在服务操作实现开始时立即调用的(在参数验证之后)。操作不可能在运行辅助方法之前返回连贯的结果,因此当我之前收到连贯的结果并假设已运行“奇怪”的文件访问代码时,它实际上已经运行了

  • 重新部署服务,使用Windows服务主机、WCF服务库和辅助程序集的干净重建(希望确保屏幕上的代码实际上是在服务器上运行的代码)-->没有变化

  • EDIT 2011-06-24 16:32GMT - 使用我之前创建的控制台应用程序托管WCF服务,相应地调整baseAddress并在服务器上部署。使用与上述相同的管理员帐户运行应用程序。在新的基地址上使用WcfStorm测试新应用程序-->代码按预期工作并返回良好结果(我认为此时将其缩小到是Windows服务的故障?)

  • EDIT 2011-06-27 10:21GMT - 创建一个简单的Windows服务,引用辅助类。安装在服务器上,服务的帐户设置为与Live Server相同。-->新服务能够运行代码并访问文件

  • EDIT 2011-06-27 10:23GMT - 愤怒于服务已经起作用,我打开了WcfStorm,它一直在周末运行。结果仍然显示从星期


1
此外,作为一个小插曲,我有99.99999%的把握,我目前遇到问题的文件昨晚还能正常工作。服务昨晚实际上在不同的文件(在提供的路径循环中更远的位置)上失败了,出现了相同的错误。例如,我有一个字符串列表 { "PathA", "PathB", "PathC" }。昨晚,PathA成功了,PathB以上述错误失败了。今天,PathA失败了,我甚至没有到达PathB。我没有直接将这个放在原始帖子中,因为它只会让事情变得更加混乱... - Smudge202
1
我理解这个“网络共享”和本地机器不在同一个域上? - insipid
3
+1 可能是 SO 上最长的问题之一。你一定非常沮丧! - Mrchief
1
@MrChief,我所有的问题都变得这么长——这是沮丧和我无法简洁表达的结合体 =) - Smudge202
1
WCF服务的安全上下文是什么? - Amit Bagga
显示剩余3条评论
4个回答

4
尝试使用进程监视器。它将显示哪个用户正在访问文件以及返回的具体Windows错误代码。然后,您应该能够看到为什么某些文件可以工作而另一些文件不行。

1
下次遇到文件出现问题时,我会尝试这样做。谢谢 @Mike。 - Smudge202

1

你的WCF服务是否使用模拟身份?

这可能解释了为什么新的Windows服务可以执行操作,但WCF服务不能。新服务直接针对NAS进行身份验证。如果在旧服务中,WCF正在模拟调用者,则客户端计算机会对用户进行身份验证,其令牌传递给您的WCF服务,后者将安全令牌传递给NAS,然后您就会遇到双跳问题。

您可以像这样使活动安全上下文恢复到服务帐户:

using (WindowsIdentity.Impersontate(IntPtr.Zero))
{
    DoStuff();
}

当然,这并不能解释为什么它可能会间歇性地工作。但是这可以解释为什么在托管它的机器上本地调用WCF服务时它能够工作,但是从远程客户端机器上却不能工作。

1
嗨,Alex,我也考虑了同样的事情。WCF服务没有使用模拟身份,但我确实想知道服务帐户可能会产生什么影响。这就是为什么在我的测试中,我将帐户更改为管理员,但似乎没有任何影响。不过还是谢谢你提供的链接! - Smudge202
如果是双跳问题,成为管理员(域管理员)也无济于事。也许你已经尝试过了,但是如果你从托管该服务的计算机上调用WCF服务,它是否能正常工作? - Alex Peck
1
是的,我的一个测试是在控制台应用程序中托管WCF服务库(通常是MSDN方式)。然后我将该主机放置在同一服务器上并启动它。使用WcfStorm调用新托管的WCF服务,代码运行良好。很奇怪,不是吗? - Smudge202
如果在本地机器上调用时它能够工作,但是在远程机器上不能工作,那么问题几乎肯定与Windows尝试委派安全令牌有关,然后发现无法进行委派,并尝试使用空令牌(匿名登录)访问文件共享。这就是为什么你会收到拒绝访问错误的原因。 - Alex Peck
是的,另外有人也建议了同样的事情,所以它绝对在我的清单上。但如果显示文件被进程锁定,我会更加困惑,因为我能够使用多种方法从几个其他位置和相同位置打开文件。感谢关于双跳和一般网络安全方面的信息! - Smudge202
显示剩余2条评论

1

我曾经遇到过类似的问题,当我的代码访问一个尚未完全写入磁盘的新文件时。所以等待几毫秒对我来说解决了这个问题。你是否可能在完全写入磁盘之前尝试读取该流?


1
很遗憾。我碰巧知道这个文件在这个网络共享上已经存在了4年多。但是,我能够从两个不同的位置打开文件,将文件复制到我的本地PC,并使用测试项目在代码中访问文件,这证实了流可用。感谢您的建议。 - Smudge202

1

我有一些猜测。

你尝试过将 'FileAccess.Read' 和/或 'FileShare.Read' 设置为 'ReadWrite' 吗?

此外,这个警告可能是一个因素吗?来自 http://msdn.microsoft.com/en-us/library/5h0z48dh.aspx

注意

当您使用特定文化设置编译一组字符并使用不同的文化设置检索相同的字符时,这些字符可能无法被解释,并可能导致抛出异常。


1
感谢您的回答。我将其设置为Read,因为该文件仅需要读取。老实说,当设置这些枚举时,我并不太了解底层发生了什么 - 我认为它类似于SQL Server中的锁类型。下次遇到此问题时,我会尝试将Enum设置为ReadWrite,只是出于好奇。关于文化方面,我没有考虑过。我没有在任何地方设置文化,服务器能够运行代码,但无法在服务+WCF环境中运行。 - Smudge202

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接