2016-05-24 5 views
0

Assemblée A déclare un attribut d'assemblage personnalisé qui est appliqué dans l'assemblage B.Être attribut personnalisé des données de fichier d'assemblage et déverrouiller afterwise

class MyAssemblyAttribute : Attribute { /* ... */ } 

Je dois obtenir que les données d'attributs de l'Assemblée B de méthode Assemblée A sans maintien de l'ensemble B chargé.

Pseudo code dans l'assemblage A:

var domain = AppDomain.Create(); 
MyAssemblyAttribute attr = null; 
string path = "B.dll"; 
domain.DoCallback(() => { 
     attr = Assembly.Load(path) 
      .GetCustomAttributes() 
      .OfType<MyAssemblyAttribute>() 
      .First(); 
     }); 

AppDomain.Unload(domain); 
File.Delete(path); 
File.WriteAllBytes(path, ...); 
return expectedAttr.Equals(attr); 

Comment puis-je faire?

Je peux recompiler les deux assemblages. Je ne peux pas utiliser des choses tierces comme Mono.Cecil ou IKVM.

+0

Avez-vous essayé 'AppDomainSetup.ShadowCopyFiles = "true"'? –

+0

@RubensFarias n'a pas aidé, mais je peux simplement supprimer l'assembly avant de le charger à l'état brut dans AppDomain – Vlad

+0

Vous ne pouvez pas décharger un assembly, vous devrez décharger l'intégralité de 'AppDomain' comme je l'ai fait ici il y a longtemps: www.codeproject.com/Articles/24349/Generic-WCF-Host –

Répondre

1

Enfin, je fait ce travail:

var domain = AppDomain.CreateDomain(
    "CompiledAssemblyCheck", 
    null, 
    new AppDomainSetup() 
    { 
     LoaderOptimization = LoaderOptimization.MultiDomainHost, 
     PrivateBinPath = Path.GetDirectoryName(Path.GetFullPath(otherAssembly)), 
     ShadowCopyFiles = "true" 
    }); 
try 
{ 

    var data = File.ReadAllBytes(otherAssembly); 

    string myPath = new Uri(executingAssembly.GetName().CodeBase).LocalPath; 
    var proxy = (AssemblyAnyLoadProxy)domain.CreateInstanceFromAndUnwrap(myPath, typeof(AssemblyAnyLoadProxy).FullName); 

    proxy.LoadFrom(myPath); 

    int outputAssemblyId = proxy.Load(data); 

    bool same = proxy.CompareAttribute(outputAssemblyId, typeof(MyAssemblyAttribute).FullName, expectedArgs); 
} 
finally 
{ 
    AppDomain.Unload(domain); 
} 



    [Serializable] 
    class AssemblyAnyLoadProxy : MarshalByRefObject 
    { 
     List<Assembly> _assemblies=new List<Assembly>(); 

     public int Load(byte[] raw) 
     { 
      Assembly asm = Assembly.ReflectionOnlyLoad(raw); 
      return Add(asm); 
     } 

     public int LoadFrom(string assemblyFile) 
     { 
      Assembly asm = Assembly.ReflectionOnlyLoadFrom(assemblyFile); 
      return Add(asm); 
     } 

     int Add(Assembly asm) 
     { 

      _assemblies.Add(asm); 
      return _assemblies.Count - 1; 
     } 

     public bool CompareAttribute(int assembly, string fullName, object[] args) 
     { 
      var attrs = CustomAttributeData.GetCustomAttributes(_assemblies[assembly]); 
      CustomAttributeData attr = attrs.FirstOrDefault(x => x.Constructor.DeclaringType.FullName == fullName); 
      return attr?.ConstructorArguments.Select(x => x.Value).SequenceEqual(args) ?? false; 
     } 
    }