进程无法访问该文件,因为它正被Directory.Move()上的另一个进程使用

时间:2012-01-16 11:32:13

标签: c# .net wcf process ioexception

我们有一个具有以下架构的客户端应用程序:管理器进程管理几个工作进程(读取器和编写器),并定期查询服务器以获取版本更新。如果版本更新可用,则管理器将其下载到客户端计算机,关闭工作线程,启动更新程序进程以处理更新并退出。 updater在启动时接收管理器PID和更新文件位置;然后等待管理员退出,备份管理员和工作人员的所有文件,重新创建他们的目录并将新版本文件传播到新目录。

当按照描述进行此过程时,第一次调用Directory.Move(string, string)(用于备份管理器目录)会抛出IOException。奇怪的是,如果我让管理器在没有启动更新程序的情况下关闭然后自己启动更新程序可执行文件,则不会抛出异常。

管理工作线程的管理员代码:

public void Run()
{
   _config = GetConfiguration();
   Process reader, writer;

   //Start reader and writer with appropriate arguments

   //Keep reader and writer alive

   reader.Kill();
   writer.Kill();

   reader.WaitForExit();
   writer.WaitForExit();

   reader.Dispose();
   writer.Dispose();
}

查询数据库的管理员代码:

EndpointAddress endpoint;
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.MaxReceivedMessageSize = 2000000000;
ChannelFactory<IService> chanFactory = new ChannelFactory<IService>(httpBinding);
IService service;

try
{
   endpoint = new EndpointAddress(ConfigurationManager.AppSettings["Service URL"]);

   service = chanFactory.CreateChannel(endpoint);

   UpdateInstructions instructions = service.GetUpdateInstructions(_config.SiteID,     Assembly.GetExecutingAssembly().GetName().Version.ToString(), _config.Version);

   HandleUpdateInstructions(instructions); //Downloads files and starts the updater process
}
catch (Exception ex)
{
   //Report exception
}
finally
{
    if (chanFactory.State != CommunicationState.Faulted)
    chanFactory.Close();
}

启动更新程序进程的管理员代码:

private void StartUpdater(string updateFilePath, string configFilePath)
{
   ProcessStartInfo updaterStartInfo = new ProcessStartInfo(_config.UpdaterExePath, string.Format("{0} \"{1}\" \"{2}\"", Process.GetCurrentProcess().Id, updateFilePath, configFilePath));
   Process updater = Process.Start(updaterStartInfo);
   updater.Dispose();
}

等待经理关闭的更新代码:

bool isManagerUp = true;

while (isManagerUp)
{
  try
  {
     Process managerProcess = Process.GetProcessById(bDoxForceManagerPID);

     managerProcess.WaitForExit();

     managerProcess.Dispose();

     isManagerUp = false;
  }
  catch
  {
     isManagerUp = false;
  }
}

更新模块的更新程序代码:

//updateDirectory is the directory of the new files to be inserted, moduleDirectory is the working directory of the module that will be updated, in this case the manager
private void UpdateModule(DirectoryInfo updateDirectory, DirectoryInfo moduleDirectory)           
{
   string backupDirectory = MakeBackupDirectoryFullPath(moduleDirectory.Parent.FullName);

   Directory.Move(moduleDirectory.FullName, backupDirectory); // IOException as described above.
   Directory.CreateDirectory(moduleDirectory.FullName);

   foreach (FileInfo updateFile in updateDirectory.EnumerateFiles())
   {
       string newFilePath = moduleDirectory.FullName + "\\" + updateFile.Name;

       File.Copy(updateFile.FullName, newFilePath);
   }

   Directory.Delete(updateDirectory.FullName, true);
}

2 个答案:

答案 0 :(得分:3)

感谢Adam Caviness回答我们能够弄清楚。

我们的流程是控制台应用程序,他们创建了一个.vshost文件,这些文件在流程终止后继续工作。 尝试使用正在运行的.vshost文件移动目录会导致问题。

将流程转换为Windows服务并未创建.vshost文件并解决了此问题。

答案 1 :(得分:2)

我建议您使用MS(正式的SysInternals)Process Monitor来跟踪这个问题,从而首先排除任何反病毒/反恶意软件/启发式方法(如果你不像我们开发人员那样去攻击突击队)。这一点的线索让我指出你在这个方向是你可以自己启动更新程序,并且不会抛出异常。就在今年,我已经遇到了这个问题,不得不添加AV目录排除。