2016-10-20 3 views
1

MEFを使用してアセンブリを読み込むWinFormsプログラムを作成しています。これらのアセンブリは、実行可能ファイルと同じフォルダにありません。 ファイルメンテナンスを行う必要があるため、実際のWinFormをロードする前にProgram.csファイルにいくつかのコードを実装していますので、プログラムによって(アセンブリであっても)ファイルがロードされません。ファイルを操作してブロックする

が、私は2つの操作を実行しています: - 他の1つの に一つの場所からフォルダを移動する - アーカイブからファイルがある場合は、フォルダからdllファイルをアーカイブから解凍ファイルや上書き移動(1よりも新しいが移動しました)

問題は、フォルダを移動した後で、ファイルがロックされ、上書きできないことです。私はまた、移動が終了したときにそれらを破棄することによって、ファイルを1つずつ移動しようとしました。

ファイルがブロックされていると私は

おかげ

private static void InitializePluginsFolder() 
    { 
     if (!Directory.Exists(Paths.PluginsPath)) 
     { 
      Directory.CreateDirectory(Paths.PluginsPath); 
     } 

     // Find archive that contains plugins to deploy 
     var assembly = Assembly.GetExecutingAssembly(); 
     if (assembly.Location == null) 
     { 
      throw new NullReferenceException("Executing assembly is null!"); 
     } 

     var currentDirectory = new FileInfo(assembly.Location).DirectoryName; 
     if (currentDirectory == null) 
     { 
      throw new NullReferenceException("Current folder is null!"); 
     } 

     // Check if previous installation contains a "Plugins" folder 
     var currentPluginsPath = Path.Combine(currentDirectory, "Plugins"); 
     if (Directory.Exists(currentPluginsPath)) 
     { 
      foreach (FileInfo fi in new DirectoryInfo(currentPluginsPath).GetFiles()) 
      { 
       using (FileStream sourceStream = new FileStream(fi.FullName, FileMode.Open)) 
       { 
        using (FileStream destStream = new FileStream(Path.Combine(Paths.PluginsPath, fi.Name), FileMode.Create)) 
        { 
         destStream.Lock(0, sourceStream.Length); 
         sourceStream.CopyTo(destStream); 
        } 
       } 
      } 

      Directory.Delete(currentPluginsPath, true); 
     } 

     // Then updates plugins with latest version of plugins (zipped) 
     var pluginsZipFilePath = Path.Combine(currentDirectory, "Plugins.zip"); 

     // Extract content of plugins archive to a temporary folder 
     var tempPath = string.Format("{0}_Temp", Paths.PluginsPath); 

     if (Directory.Exists(tempPath)) 
     { 
      Directory.Delete(tempPath, true); 
     } 

     ZipFile.ExtractToDirectory(pluginsZipFilePath, tempPath); 

     // Moves all plugins to appropriate folder if version is greater 
     // to the version in place 
     foreach (var fi in new DirectoryInfo(tempPath).GetFiles()) 
     { 
      if (fi.Extension.ToLower() != ".dll") 
      { 
       continue; 
      } 

      var targetFile = Path.Combine(Paths.PluginsPath, fi.Name); 
      if (File.Exists(targetFile)) 
      { 
       if (fi.GetAssemblyVersion() > new FileInfo(targetFile).GetAssemblyVersion()) 
       { 
        // If version to deploy is newer than current version 
        // Delete current version and copy the new one 

        // FAILS HERE 

        File.Copy(fi.FullName, targetFile, true); 
       } 
      } 
      else 
      { 
       File.Move(fi.FullName, targetFile); 
      } 
     } 

     // Delete temporary folder 
     Directory.Delete(tempPath, true); 
    } 
+2

コードを共有してください。 –

+0

悲しいことに私たちは本当にそれから推測することはできません。 – BugFinder

+0

申し訳ありませんコードをたくさん入れたくありませんでしたが、確かに役立つと思います。このメソッドは、Mainメソッドで呼び出された最初のメソッドです –

答えて

3

は、コードのこの部分で使用GetAssemblyVersion()メソッドの実装を確認してください:

if (File.Exists(targetFile)) 
{ 
    if (fi.GetAssemblyVersion() > new FileInfo(targetFile).GetAssemblyVersion()) 
    { 
    // If version to deploy is newer than current version 
    // Delete current version and copy the new one 

    // FAILS HERE 

    File.Copy(fi.FullName, targetFile, true); 
    } 
} 

fi変数はGetAssemblyVersion()は、拡張メソッドのように見える、FileInfoを入力しています。ファイルからアセンブリバージョンを取得する方法を確認する必要があります。このメソッドがアセンブリをロードする場合、アセンブリをアンロードしてファイルを解放する必要があります。

別のAppDomainは、アセンブリをロードし、ジョブを実行した後にアンロードする必要がある場合に役立ちます。ここでGetAssemblyVersionメソッドの実装は次のとおりです。

public static Version GetAssemblyVersion(this FileInfo fi) 
{ 
    AppDomain checkFileDomain = AppDomain.CreateDomain("DomainToCheckFileVersion"); 
    Assembly assembly = checkFileDomain.Load(new AssemblyName {CodeBase = fi.FullName}); 
    Version fileVersion = assembly.GetName().Version; 
    AppDomain.Unload(checkFileDomain); 
    return fileVersion; 
} 

GetAssemblyVersion()の次の実装は、あなたのAppDomainにアセンブリをロードすることなく、アセンブリのバージョンを取得することができます。ヒントのためのThnx @usterdev。それはまた、あなたがアセンブリ参照の解決なしバージョンを取得することができます:

public static Version GetAssemblyVersion(this FileInfo fi) 
{ 
    return AssemblyName.GetAssemblyName(fi.FullName).Version; 
} 
0

は、以下のステートメントは、ファイル

destStream.Lock(0, sourceStream.Length); 

をロックしますが、その後、あなたがロック解除されたhaventはことを避けることができるか、なぜ誰かが私に説明できますファイル。おそらくそれがあなたの問題の原因です。

+0

残念ながら、これは原因ではありません。コピー後にロックを解除するかアンロックを追加しても問題は解決されません。 –

0

あなたのプログラムは、実際に、すでにアセンブリをロードした場合、私はチェックを開始します。

2提案:

1 - あなたのInitializePluginsFolder

static void DumpLoadedAssemblies() 
{ 
    var ads = AppDomain.CurrentDomain.GetAssemblies(); 
    Console.WriteLine(ads.Length); 
    foreach (var ad in ads) 
    { 
     Console.WriteLine(ad.FullName); 
     // maybe this can be helpful as well 
     foreach (var f in ad.GetFiles()) 
      Console.WriteLine(f.Name); 
     Console.WriteLine("*******"); 
    } 
} 

2を呼び出す前に、このようなメソッドを呼び出します - メインの最初の行で、AssemblyLoadイベントに登録し、イベントハンドラに読み込まれたアセンブリをダンプ

public static void Main() 
{ 
    AppDomain.CurrentDomain.AssemblyLoad += OnAssemlyLoad; 
    ... 
} 
static void OnAssemlyLoad(object sender, AssemblyLoadEventArgs args) 
{ 
    Console.WriteLine("Assembly Loaded: " + args.LoadedAssembly.FullName); 
} 
1

あなたはそれからバージョンを得るためにあなたのドメインにAssemblyをロードしていないことを確認する必要があり、それ以外の場合、ファイルはロックされます。AssemblyName.GetAssemblyName()静的メソッド(see MSDN)を使用することにより

は、アセンブリファイルは、ロードされたバージョンが読み込まれ、その後、をアンロードしますが、あなたのドメインに追加されません。ここで

FileInfoの拡張子そう:

public static Version GetAssemblyVersion(this FileInfo fi) 
{ 
    AssemblyName an = AssemblyName.GetAssemblyName(fi.FullName); 
    return an.Version; 
} 
0

をあなたは間違いなくAssemblyName.GetAssemblyNameを使用してアセンブリをロードするには、残念ながら、.NETは、装着アセンブリずにアセンブリメタデータをチェックのない従来の方法を持っていません。これを避けるために次のことができます。ニキータが示唆されているように、分離のAppDomain内

  1. ロードアセンブリは、私が追加することができます。ReflectionOnlyLoad
  2. でそれをロードしたり、リフレクターちょうど完全性のため
  3. がそうであるようにMono.Cecilライブラリを使用してアセンブリのバージョンを取得:実際にアセンブリファイルを2つのステージでロックせずに同じAppDomainにアセンブリをロードすることができます:ファイル内容をバイト[]に読み込み、Assembly.Load(byte [] rawAssembly)を使用して読み込みますが、この方法では重大な "読み込みコンテキスト"の問題があり、負荷アセンブリ:
関連する問題