C# .NET 4.5文件。可以复制,但文件不存在

C# .NET 4.5文件。可以复制,但文件不存在,c#,.net,system.io.file,C#,.net,System.io.file,这些天,我们的生产环境中出现了奇怪的行为。 我有以下资料: 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 s

这些天,我们的生产环境中出现了奇怪的行为。 我有以下资料:

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错误文件.Copy都会引发异常,所以这件事让我抓狂。 请注意,在该文件夹中写入文件的其他代码部分工作正常。另外,请注意,所有文件名都是唯一的(为简洁起见,未包含业务代码,请确保这一点),在这种情况下,我认为会引发异常,或者至少会覆盖文件

有人面临过同样的问题吗?可能的原因?有解决办法吗

编辑2016-07-01 15:12(GMT+0200)

好了,伙计们,显然文件根本没有被删除。。。显然根本没有任何原因,在复制它们之后,它们在与客户端连接的用户的读写模式下保持打开状态。 我在调试模式下尝试在我的计算机上运行reader应用程序,并尝试打开我知道最近复制的一个文件时发现了这个问题。 我得到了一个例外声明文件是由其他人打开的,这对我来说似乎很奇怪。 在远程服务器(存储文件的服务器)中打开“计算机管理”,然后转到“共享文件夹”>“打开文件”,我发现复制文件的web应用程序正在模拟执行该任务的模拟用户以读写模式打开了该文件。 还有一大堆其他文件,它们处于相同的状态,还有许多其他文件是以读取模式打开的。 我还在Shared Folders>Sessions中发现了一个天文数字般长的模拟用户会话列表,所有这些会话都有很长的空闲时间。 由于模拟只用于复制文件,然后被处理,我不应该期望这样,对吗

我认为在文件复制过程中,我们模拟用户的方式可能存在问题,链接到目标文件夹中的大量文件。 我查一下

结束编辑

谢谢

我认为克劳迪奥·瓦莱里奥找到了解决办法。 我的问题是用于模拟对目标文件夹具有写入权限的用户的代码。 (为我辩护,所有这些项目都是从以前的软件公司继承下来的,而且规模相当大,所以关注每一件事情并不是那么容易)

模拟过程包装在实现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
}
我的怀疑是,关闭模拟用户的处理程序可能会以某种方式破坏windows处理模拟用户通过网络共享打开的文件的方式,就像我的情况一样,让共享文件以读写模式打开,从而阻止任何其他进程/用户打开它们

我修改了模拟器类,如下所示:

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方法中处理了它

自从我将此更新投入生产以来,我对这段代码没有任何其他问题,在目标服务器上也没有任何其他以读写模式打开的共享文件。 也许不是最佳解决方案(我在“计算机管理”>“共享文件夹”>“会话”中仍有一大堆会话,但目前看来,这似乎不会对系统造成危害

如果有人对这种情况有其他的评论、建议或深入研究,请阅读

谢谢


Claudio

可能有人/某事在被复制后正在删除该文件?嗨,Matteo,谢谢你的评论。遗憾的是,没有任何代码行可以从该特定文件夹中删除,除了我和我的同事之外,没有人可以通过Windows资源管理器访问(没有FTP访问)。在某些情况下,您的
目标路径可能与您想象的不一样。也许您也应该将其记录下来。嗨,Charles,目标路径始终是一个特定的现有文件夹(100%确定)结合一个唯一的文件名。此外,该代码每次都在一小群图像文件上运行,在一个单独的群中,一个或两个文件被正确复制并存在。显然,源文件也存在(否则,根据文档,我应该得到一个FileNotFoundException)。