Mehr

CodeDom.Compiler schlägt im Arcmap-Add-In fehl, funktioniert jedoch über die Konsolen-App

CodeDom.Compiler schlägt im Arcmap-Add-In fehl, funktioniert jedoch über die Konsolen-App


Die Testmethode im folgenden Code ist in einer Konsolentest-App erfolgreich, schlägt jedoch fehl, wenn ich sie aus einem Arcmap-Add-In aufrufe und eine ReflectionTypeLoadException mit einer Loader-Ausnahme auslöst, die besagt:

Datei oder Assembly 'KompilerLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' oder eine ihrer Abhängigkeiten konnte nicht geladen werden. Die angegebene Datei wurde vom System nicht gefunden.

KompilerLib ist ein Windows-Klassenbibliotheksprojekt (3.5) und dies ist die einzige Datei im Projekt (eine Schnittstelle und eine Klasse).

Muss ich etwas Besonderes tun, wenn ich CodeDom.Compiler in einem Add-In verwende?

Verwenden des Systems; mit System.Collections.Generic; Verwenden von System.Text; Verwenden von System.CodeDom.Compiler; Verwenden von System.Diagnostics; Verwenden von System.IO; namespace KompilerLib { öffentliche Schnittstelle IKalkulation { string Test(); } public class Kompiler { private const string TYPENAME = "Kalk.Kalkulation"; public IKalkulation Kompile(Zeichenfolgensprache, Liste Referenzen, String-Quelle) { CodeDomProvider provider = CodeDomProvider.CreateProvider(language); var-Parameter = neue CompilerParameters(); Parameter.GenerateInMemory = true; Parameter.GenerateExecutable = false; foreach (String-Referenz in Referenzen) { parameters.ReferencedAssemblies.Add(Referenz); } var Ergebnisse = provider.CompileAssemblyFromSource(Parameter, Quelle); if (results.Errors == null || results.Errors.Count == 0) { Debug.Print(results.CompiledAssembly.ReflectionOnly.ToString()); foreach (Geben Sie t in results.CompiledAssembly.GetTypes() ein) Debug.Print(t.Name); var type = results.CompiledAssembly.GetType(TYPENAME); if (type == null) throw new Exception("type not found: " + TYPENAME); Objekt o = Activator.CreateInstance(Typ); if (o == null) throw new Exception("unable to createinstance"); var kalkulation = o als IKalkulation; if (kalkulation == null) throw new Exception("kann nicht in IKalkulation umgewandelt werden"); Rückrechnung; } else { StringBuilder sb = new StringBuilder(); foreach (CompilerError err in results.Errors) sb.AppendLine(err.ErrorText); werfen Sie eine neue Ausnahme (sb.ToString()); } } öffentliche statische Zeichenfolge Test () { var kompiler = new Kompiler (); var list = neue Liste(); list.Add("System.dll"); string path = kompiler.GetType().Assembly.Location; if (!File.Exists(path)) throw new Exception("Datei nicht gefunden" + Pfad); list.Add(Pfad); Zeichenfolgenquelle = GetSource(); var kalk = kompiler.Kompile("CSharp", Liste, Quelle); kalk.Test() zurückgeben; } private statische Zeichenfolge GetSource() { StringBuilder sb = new StringBuilder(); sb.AppendLine("mit KompilerLib; "); sb.AppendLine("Namensraum Kalk"); sb.AppendLine("{"); sb.AppendLine(" public class Kalkulation : IKalkulation "); sb.AppendLine(" { "); sb.AppendLine(" öffentlicher String Test() "); sb.AppendLine(" { "); sb.AppendLine(" return "Hallo Welt"; "); sb.AppendLine(" } "); sb.AppendLine(" } "); sb.AppendLine("} "); sb.ToString() zurückgeben; } } }

Aktualisieren

Hier ist der Fix mit AssemblyResolve, dank blah238. Ich bin immer noch neugierig, warum dies ein Problem in arcmap.exe ist, aber nicht in meiner Konsolentester-exe. Es scheint auch, dass die am einfachsten aufzulösende Assembly diejenige sein sollte, in der der Compiler ausgeführt wird.

public IKalkulation Kompile(Zeichenfolgensprache, Liste Referenzen, String-Quelle) { CodeDomProvider provider = CodeDomProvider.CreateProvider(language); var-Parameter = neue CompilerParameters(); Parameter.GenerateInMemory = true; Parameter.GenerateExecutable = false; foreach (String-Referenz in Referenzen) { parameters.ReferencedAssemblies.Add(Referenz); } // das scheint sicher ein Hack zu sein… AppDomain.CurrentDomain.AssemblyResolve += (s,args) => { if (args.Name == this.GetType().Assembly.FullName) return this.GetType().Assembly ; sonst null zurückgeben; }; var Ergebnisse = provider.CompileAssemblyFromSource(Parameter, Quelle); if (results.Errors == null || results.Errors.Count == 0) { var type = results.CompiledAssembly.GetType(TYPENAME); if (type == null) throw new Exception("type not found: " + TYPENAME); Objekt o = Activator.CreateInstance(Typ); if (o == null) throw new Exception("unable to createinstance"); var kalkulation = o als IKalkulation; if (kalkulation == null) throw new Exception("kann nicht in IKalkulation umgewandelt werden"); Rückrechnung; } else { StringBuilder sb = new StringBuilder(); foreach (CompilerError err in results.Errors) sb.AppendLine(err.ErrorText); werfen Sie eine neue Ausnahme (sb.ToString()); } }

Bei der Verwendung von benutzerdefiniertem .NET sind ähnliche Probleme aufgetretenKonfigurationsabschnitt's und bei Verwendung der binären (De-)Serialisierung. Dieses Problem wird in den Kommentaren zu dieser Frage erörtert: ArcMap-Add-In mit app.settings erkennt Änderungen an app.config nicht?

Das Problem scheint zu sein, dass einige Assemblys, auf die von Add-Ins verwiesen wird, nicht korrekt aufgelöst werden können, da die Add-In-Anwendungsdomäne nicht von der Hauptanwendungsdomäne getrennt ist und die .NET-Laufzeit daher im Assembly-Prüfpfad der Hauptanwendung sucht und findet sie nicht. Die Lösung ist zu verwenden Assembly.LoadFrom und handhabe die AppDomain.AssemblyResolve Veranstaltung.

Dies war der Fix, der für mich mit dem Brauch funktionierteKonfigurationsabschnittAusgabe. Ich hoffe, es funktioniert in deinem Fall auch!


Schau das Video: Work with a grid in ArcGIS Pro