2015-09-15 8 views
6

を上書きするDirectory.Delete()とDirectory.CreateDirectoryを()を使用して、私はこのコードを使用して、フォルダを上書き/作成したい:私<code>WebApi</code>アクションメソッドでフォルダ

string myDir = "..."; 
if(Directory.Exists(myDir)) 
{ 
    Directory.Delete(myDir, true); 
} 
Directory.CreateDirectory(myDir); 

// 1 - Check the dir 
Debug.WriteLine("Double check if the Dir is created: " + Directory.Exists(myDir)); 

// Some other stuff here... 

// 2 - Check the dir again 
Debug.WriteLine("Check again if the Dir still exists: " + Directory.Exists(myDir)); 

問題

奇妙なことに、ディレクトリを作成した直後に、ディレクトリが存在しないことがあります。

最初にdirを確認するとき(番号1の場合)。 Directory.Exist()true、その他の場合はfalseを返します。 2番目の時間(2番はどこか)にdirをチェックすると同じことが起こります。コードのこの部分の

ノート

  • いずれも、例外をスローしません。
  • ウェブサイトをサーバーに公開するときにのみこれを再現できます。 (Windows server 2008)
  • 同じフォルダにアクセスすると起こります。

質問

  • これは、同時実行の問題の競合状態ですか?
  • WebApiまたはオペレーティングシステムが同時性を処理していませんか?
  • これは、フォルダを上書きする正しい方法ですか?
  • 同じファイルに対して多数のAPIリクエストがある場合、ファイルを手動でロックする必要がありますか?

または一般に:

  • この奇妙な行動の理由は何ですか?

UPDATE:

  • 代わりDirectoryDirectoryInfoRefresh()を使用することで問題を解決していません。 削除再帰オプションがtrueとき

  • のみ発生します。 (ディレクトリは空ではありません)。

+0

ディレクトリはファイル共有ですか(つまり、Webサーバー以外のマシン上のディスクですか)。 – jlew

+0

@jlewいいえ、それはWebサーバーと同じマシン上にあります。 –

答えて

0

私は競合状態に似ています。理由は分かりませんが、十分な詳細を提供していませんでしたが、できることはlock()の文ですべてをラップし、問題がなくなっているかどうかを確認することです。これは実稼動環境に対応したソリューションではないことを確認するだけで、簡単に確認できます。確かに競合状態であれば、フォルダの書き直しの考え方を再考する必要があります。 「GUID」フォルダを作成して終了すると、最新のGUIDを使用して最新のフォルダを指すようにDBを更新しますか?

+0

この行をコードに追加しました。 'Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId)'。すべて同じスレッドで発生するようです。また、同じ問題を抱えていてもロックを試みました。 –

+0

さらに、すでにGUIDフォルダです。このGUIDフォルダを上書きする必要がある場合もあります。 –

7

多くのファイルシステム操作は、一部のファイルシステム(Windowsの場合 - NTFS)で同期しません。 (いくつかの点でDirectory.DeleteDirectoryによって呼び出される)の例RemoveDirectory呼び出しを見てみましょう:

RemoveDirectory機能が密接に削除用のディレクトリをマーク。したがって、ディレクトリへの最後のハンドルが閉じられるまで、ディレクトリは削除されません。

実際、表示されているとおり、すべてのハンドルが閉じられるまでディレクトリは削除されませんが、Directory.DeleteDirectoryは正常終了します。あなたのケースでは、Directory.Existsを実行している間にディレクトリが実際に作成されないような並行性の問題もありそうです。

したがって、必要なものを定期的にチェックし、.NETのファイルシステム呼び出しを同期させないでください。ポーリングを避けるために、FileSystemWatcherを使用することもできます。

編集:私はそれを再現する方法を考えて、そしてここにコードされた:

internal class Program { 
    private static void Main(string[] args) { 
     const string path = "G:\\test_dir"; 
     while (true) {   
      if (Directory.Exists(path)) 
       Directory.Delete(path);  
      Directory.CreateDirectory(path); 
      if (!Directory.Exists(path)) 
       throw new Exception("Confirmed");     
     }    
    }   
} 

あなたはすべてのファイルシステムコールが(.NETで)同期した場合、このコードは問題なく実行する必要があることがわかります。さて、そのコードを実行する前に、指定されたパス(好ましくはSSDを使用しないでください)に空のディレクトリを作成し、Windowsエクスプローラで開きます。今すぐコードを実行します。私にとっては、Confirmed(問題を正確に再現します)またはDirectory.Deleteにディレクトリが存在しないことを伝えます(ほとんど同じケース)。それは私にとって時間の100%です。

ここに私のマシン上で実行する場合は、File.Existsが直接File.Deleteコールの後にtrueを返すすることは確かに可能だということを確認し、別のコードです:私は、

internal class Program { 
    private static void Main(string[] args) { 
     while (true) { 
      const string path = @"G:\test_dir\test.txt"; 
      if (File.Exists(path)) 
       File.Delete(path); 
      if (File.Exists(path)) 
       throw new Exception("Confirmed"); 
      File.Create(path).Dispose(); 
     } 
    }   
} 

exception

これを行うにはG:\ test_dirフォルダを開き、このコードの実行中にtest.txtファイルが常に表示され、消えてしまった。いくつか試行した後、Confirmed例外がスローされました(私はそのファイルを作成または削除していませんでしたが、例外がスローされた後はすでにファイルシステムには存在しません)。だから競争条件は複数のケースで可能で、私の答えは正しいものです。

+0

動作を再現するためにサンプルコードで更新しました。 – Evk

+1

削除が返されたときに唯一の削除が行われないのは、ファイル共有の削除を持つハンドルが開いている場合です。これは非常にまれです。これは、ほとんどコードが使用されない動作を選択します。それ以外の場合、削除は完全に同期します。私もこの振る舞いを再現することはできません。私はこの答えが非常に誤解を招くことに気づきます。 – usr

+1

おそらく、彼の問題はレースに基づいています。 FILE_SHARE_DELETEではありません。私は解決策を提供していないので、なぜこの答えが受け入れられるのか分かりません。 'これは多段階のプロセスであり、ウィンドウはいつ完了するか分からず、その前にFile.Deleteから返されます。 ... - Directory.Existsを実行している間、ディレクトリは実際には作成されません.'両方の文が偽です。 – usr

関連する問題