try {
var sourcePath = ... // my source path
var destinationPath = ... // guess what? You're right, my destination path
File.Copy(sourcePath, destinationPath);
Log.Debug(string.Format("Image {0} copied successfully", imagename));
}
catch(Exception e) {
// exception handling
}
源路径和目标路径都位于网络共享上,是具有大量文件(> 500k)的其他(虚拟)计算机上的文件夹。 从过去2天开始,上面的代码运行,记录最后一行(表示已复制图像的那一行),但是如果我签入目标文件夹,则假定的目标文件不存在。
我认为对于任何I / O错误File.Copy会引发异常,所以这件事让我很生气。 请注意,在该文件夹中写入文件的其他代码部分正常工作。另请注意,所有文件名都是唯一的(为简洁起见,不包括业务代码确保这一点),我认为在这种情况下会抛出异常或文件至少会被覆盖。
有没有人遇到同样的问题?可能的原因?任何解决方案?
编辑2016-07-01 15:12(GMT + 0200)
好吧,伙计们,显然文件根本就没有被删除......只是显然没有任何理由,在复制后他们在客户端连接用户的读/写模式下保持打开状态。 我发现这尝试在我的计算机上运行读取器应用程序,在调试模式下,并尝试打开我知道最近复制的文件之一。 我得到一个例外,说明该文件是由其他人打开的,这对我来说似乎很奇怪。 在远程服务器(存储文件的那个)中打开计算机管理,然后转到共享文件夹>打开文件,我发现该文件在模拟用户的读取和写入模式下保持打开状态,复制文件的Web应用程序模拟执行该作业。 还有一大堆其他文件在相同的条件下,还有许多其他文件在读取模式下打开。 我也在共享文件夹中找到了>会话,模拟用户的一个天文长的会话列表,所有这些都有很长的空闲时间。 由于模仿仅用于复制文件,然后被处置,我不应该期望,对吧?
我认为在文件复制期间模仿用户的方式可能存在问题,链接到目标文件夹中的大量文件。 我会检查一下。
结束编辑
谢谢,
Claudio Valerio
答案 0 :(得分:0)
我认为找到了解决方案。 我的问题是用于模拟目标文件夹上具有写权限的用户的代码。 (在我的辩护中,所有这个项目都是从以前的软件公司继承而来的,它非常庞大,因此密切关注一切并不容易)
模拟过程包含在实现IDisposable
的类中public class Impersonator :
IDisposable
{
public Impersonator()
{
string userName = // get username from config
string password = // get password from config
string domainName = // get domain from config
ImpersonateValidUser(userName, domainName, password);
}
public void Dispose()
{
UndoImpersonation();
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private void ImpersonateValidUser(
string userName,
string domain,
string password)
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
private void UndoImpersonation()
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
private WindowsImpersonationContext impersonationContext = null;
}
这个类以这种方式使用:
using(new Impersonator())
{
// do stuff with files in here
}
我的怀疑是关闭模拟用户的处理程序,不知何故,它可能会破坏窗口处理模拟用户通过网络共享打开文件的方式,就像在我的情况下一样,将共享文件保留为read +写入模式,阻止任何其他进程/用户打开它们。
我修改了Impersonator类,如下所示:
public class Impersonator :
IDisposable
{
public Impersonator()
{
string userName = // get username from config
string password = // get password from config
string domainName = // get domain from config
ImpersonateValidUser(userName, domainName, password);
}
public void Dispose()
{
UndoImpersonation();
impersonationContext.Dispose();
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private void ImpersonateValidUser(
string userName,
string domain,
string password)
{
WindowsIdentity tempWindowsIdentity = null;
token = IntPtr.Zero;
tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
}
}
private void UndoImpersonation()
{
try
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
private WindowsImpersonationContext impersonationContext = null;
private IntPtr token;
private IntPtr tokenDuplicate;
}
基本上我在UndoImpersonation方法中关闭了处理程序。我还怀疑是否没有明确处理impersonationContext,我把它放在了Impersonator类的Dispose方法中。
由于我将此更新投入生产,因此我对此代码没有任何其他问题,也没有任何其他共享文件在目标服务器上以读取/写入模式保持打开状态。 也许不是最佳解决方案(我仍然在计算机管理>共享文件夹>会话中有一大堆会话,但这似乎暂时不会损害系统。
如果有人对这种情况有一些额外的评论,建议或深度研究,请随时阅读。
谢谢,
克劳迪奥