2012-04-04 7 views
0

Ich habe einen WCF-Dienst, der eine Methode verfügbar macht. Wenn ein Client diese Methode aufruft, geschieht folgendes:Problem mit CompileAssemblyFromSource, wenn von einer WCF-Anwendung aufgerufen

  1. Verfahren hat einige Verarbeitung
  2. es eine Baugruppe zu laden versucht, wenn seine bereits dort
  3. wenn die obige dll nicht da ist, es C# erzeugt Code kompiliert es CSharpCodeProvider der CompileAssemblyFromSource api
  4. mit es lädt dann die gerade generierte Assembly

nun das Problem. Beim ersten Aufruf der aufgerufenen Methode wird die Assembly an Punkt 3) generiert. Wenn versucht wird, die Assemblyreferenz über CompilerResults.CompiledAssembly zurückzugeben, wird die Ausnahme "Datei nicht gefunden" ausgelöst. Ich kann jedoch deutlich sehen, dass die Assembly am angegebenen Speicherort erstellt wurde und ich sie mit anderen Anwendungen öffnen kann.

Wenn ich die Methode erneut über einen Client aufruft, kann sie die Assembly laden (sie wurde erfolgreich als Ergebnis des vorherigen Aufrufs generiert) und geht weiter, um die verbleibenden Aufgaben zu erledigen. Nur wenn die Assembly nicht da ist und sie erzeugt und weiter geht, um sie sofort zu laden, bekomme ich diese Ausnahme. Irgendwelche Ideen? Ich habe versucht, mit der web.config herumzuspielen und den Identitätswechsel auf true/false zu ändern. Ich habe einen separaten App-Pool, um diese Webanwendung zu starten, und ich habe versucht, die Identität des App-Pools von lokalen Service zu lokalen System zu ändern, gab sogar meine Windows-Anmeldedaten, die Admin-Rechte, aber kein Glück hat.

Jede Hilfe würde sehr geschätzt werden.

Antwort

0

Dank user1796307 für Ihre Eingabe. Ich hatte dieses Problem gelöst, aber vergessen, es zu aktualisieren. Teilen Sie es zum Wohl aller. Es war die .NET Fusion im Spiel. Es speichert den Ladepfad der Assembly und versucht nicht einmal, eine Assembly zu laden, wenn ein vorheriger Ladeversuch vom selben Speicherort fehlgeschlagen ist. Mit anderen Worten:

if (Assembly.Load("C:\xyz.dll") == null) 
{ 
    Compile("C:\xyz.dll"); // Now the dll exists 
    Assembly.Load("C:\xyz.dll"); // this will still fail 
} 


The solution is to change it as: 

    if (!File.Exists("C:\xyz.dll") 
{ 
    Compile("C:\xyz.dll"); // Now the dll exists 
    Assembly.Load("C:\xyz.dll"); // this will now work 

} 
1

Sind Sie sicher, dass die Baugruppe erzeugt wird? Ich habe das gleiche Problem, außer dass ich die erzeugte .dll nicht finden kann. Ich habe zuerst vermutet, dass es nicht in den Ordner schreiben konnte, also ruft es jetzt CreateDirectory auf und löscht eine Textdatei, um zu demonstrieren, dass der Ordner beschreibbar ist.

Wie auch immer, das gleiche Problem, kein Erfolg. Ist es wirklich so, dass niemand anderes dieses Problem hatte?

ich Debug-Remote-werde der Server & sehen, ob ich über Microsofts PDBs ...

Schritt kann - EDIT -

Keine Notwendigkeit, die durch Microsofts Code. Ich habe mir die Errors-Sammlung der CompilerResults angeschaut und dort war 1 Punkt: "Metadaten-Datei 'c: \ Windows \ System32 \ aaclient.dll' konnte nicht geöffnet werden - 'Es wurde versucht, ein Programm mit zu laden ein falsches Format ‚“

Wenn ich Directory.GetCurrentDirectory(), um die anderen DLLs zu holen, es ist das Windows-Verzeichnis System32 usign ...

-. EDIT -

dies gelöst durch Hinzufügen Referenzen aus dem Ordner der ausführenden Baugruppe:

CompilerParameters compilerParameters = new CompilerParameters 
    { 
     OutputAssembly = Path.Combine(GeneratedAssembliesFolder, string.Format("{0}.Generated.dll", typeName)) 
    }; 
string executingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
string[] dllFiles = Directory.GetFiles(executingDirectory, "*.dll"); 
compilerParameters.ReferencedAssemblies.AddRange(dllFiles.Select(f => Path.Combine(executingDirectory, f)).ToArray()); 
IEnumerable<string> exeFiles =Directory.GetFiles(executingDirectory, "*.exe").Where(f => !f.Contains(".vshost.")); 
compilerParameters.ReferencedAssemblies.AddRange(exeFiles.Select(f => Path.Combine(executingDirectory, f)).ToArray()); 

Für eine größere Robustheit sollte man hinzufügen, dass die Binärdateien gültige Assemblys mit verwaltetem Code sind. Dieser Code könnte auch mit einer Linq .Union zwischen den beiden GetFiles-Aufrufe gekürzt werden.

Um einen geeigneten Ordner zu finden zu schreiben:

private static string generatedAssembliesFolder; 

private static string GeneratedAssembliesFolder 
{ 
    get 
    { 
     if (generatedAssembliesFolder == null) 
     { 
      string[] candidateFolders = new[] 
       { 
        Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Process), 
        Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Process), 
        Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.User), 
        Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.User), 
        Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Machine), 
        Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Machine), 
        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) 
       }; 
      foreach (string candidateFolder in candidateFolders) 
      { 
       try 
       { 
        if (!Directory.Exists(candidateFolder)) Directory.CreateDirectory(candidateFolder); 
        string testFileName = Path.Combine(candidateFolder, Path.GetRandomFileName()); 
        File.WriteAllBytes(testFileName, new byte[0]); 
        File.Delete(testFileName); 
       } 
       catch (Exception ex) 
       { 
        continue; 
       } 
       generatedAssembliesFolder = candidateFolder; 

       break; 
      } 
     } 
     return generatedAssembliesFolder; 
    } 
}