2017-12-13 8 views
0

IVerwendung MEF mit Generika importieren innerhalb Wix Toolset benutzerdefinierte Aktion

namespace SimpleLibrary 
{ 
    public interface IImported<T> 
    { 
     T Value { get; set; } 
    } 
} 

und deren Umsetzung in einem anderen .dll

namespace ImportedLibrary 
{ 
    [Export(typeof(IImported<>))] 
    public class ExportedEntry<T> : IImported<T> 
    { 
     public T Value { get; set; } 
    } 
} 

Dann mache ich den Import in eine andere Klasse

namespace SimpleLibrary 
{ 
    public class MainEntry 
    { 
     [Import] 
     public IImported<string> Imported { get; set; } 

     public MainEntry() 
     { 
      try 
      { 
       var catalog = new DirectoryCatalog(Dir); 
       var container = new CompositionContainer(catalog); 
       container.ComposeParts(this); 

       Imported.Value = "Gomo Sapiens"; 
      } 
      catch (CompositionException ex) 
      { 
       System.Diagnostics.Debugger.Launch(); 
      } 
      catch (Exception ex) 
      { 
       System.Diagnostics.Debugger.Launch(); 
      } 
     } 

     private string Dir 
     { 
      get 
      { 
       var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "SimpleLibrary"); 

       if (!Directory.Exists(dir)) 
       { 
        dir = AppDomain.CurrentDomain.BaseDirectory; 
       } 

       return dir; 
      } 
     } 
    } 
} 
einige generische Schnittstelle

Dann erstelle ich Konsolenanwendung, legte .dll mit Klasse m arked [Export] innerhalb bin\Debug Ordner und

static void Main(string[] args) 
{ 
    MainEntry me = new MainEntry(); 
    Console.WriteLine(me.Imported.Value); 

    Console.ReadLine(); 
} 

Alles funktioniert gut, Konsole zeigt line "Gomo Sapiens" laufen. Allerdings, wenn ich Wix Installer mit einiger benutzerdefinierten Aktion erstellen, die dieselbe MainEntry-Klasse verwendet, und läuft nach InstallFinalize, Import nicht funktioniert:

<Binary Id="ServerActions" SourceFile="path to CA.dll" /> 

<CustomAction Id="RunMainEntry" BinaryKey="ServerActions" DllEntry="RunMainEntry" Execute="immediate" Return="check" /> 

<InstallExecuteSequence> 
    <Custom Action='RunMainEntry' After='InstallFinalize'>NOT Installed AND NOT WIX_UPGRADE_DETECTED</Custom> 
</InstallExecuteSequence> 

und Code für benutzerdefinierte Aktion

public class CustomActions 
{ 
    [CustomAction] 
    public static ActionResult RunMainEntry(Session session) 
    { 
     MainEntry me = new MainEntry(); 
     session.Log(me.Imported.Value); 

     return ActionResult.Success; 
    } 
} 

Benutzerdefinierte Aktion wirft CompositionException. Beachten Sie, dass mein Installationsprogramm anfänglich alle Dateien (.dll und .exe) in Program Files(x86)\SimpleLibrary kopiert und dann benutzerdefinierte Aktion mit MEF Zusammensetzung aufruft. Ich möchte hervorheben, dass im Moment des Aufrufs MainEntry Konstruktor alle .dlls liegen in Program Files Ordner und MEF sieht sie aber nicht finden können, was zu importieren. Und das Problem tritt nur bei Generiktypen auf, einfache Schnittstellen importieren.

.NET Framework Version ist 4.5, . CustomAction.config:

<configuration> 
    <startup useLegacyV2RuntimeActivationPolicy="true">   
     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 
    </startup> 
</configuration> 

versuchte auch MefContrib zu verwenden, Situation ist die gleiche.

Wichtig ist, dass, wenn ich Konsole App manuell von Program Files(x86) nach der Installation ausführen, alles funktioniert wieder gut funktioniert.

Also die Frage ist, wie kann ich MEF von Wix's benutzerdefinierte Aktionen verwenden und wenn ich nicht kann - warum?

Antwort

0

Ich bin ziemlich sicher, dass beim Ausführen einer benutzerdefinierten Aktion das Installationsprogramm die CA.dll-Binärdatei in ein temporäres Verzeichnis entpacken und von dort aus ausführen wird. Wenn Sie etwas zu PATH hinzugefügt haben, wird es nicht in der Umgebung des Installers angezeigt, so dass Sie keine der neuen Dateien entdecken werden.

Sie können überprüfen, mit MSI-Protokollierung ausgeführt wird (/ l * v log.txt) und/oder mit procmon auch Capture gleichzeitig ausgeführt.

Sie müssen wahrscheinlich die abhängigen DLLs in der selbstextrahierenden CA.dll selbst verpacken.

Sie können dies tun, indem Sie in Ihrem benutzerdefinierten Aktionsprojekt <CustomActionContents> definieren und den Wert dieser MSBuild-Eigenschaft auf eine separate Liste der Pfade zu den abhängigen DLLs festlegen. Beim Erstellen werden diese DLLs zusammen mit Ihrer benutzerdefinierten Aktionsdll in die Zertifizierungsstelle verpackt.dll, die in ein temporäres Verzeichnis zur Verwendung zur Laufzeit für die benutzerdefinierte Aktion extrahiert wird.

Ich habe tatsächlich eine andere Antwort mit besseren Details darüber, was CustomActionContents ist und was es tut here. Im Kommentar steht "Leerzeichen", aber ich habe festgestellt, dass es "; -begrenzt" ist. Dadurch erhalten Sie auch den Speicherort der Datei, in der das Ziel und die Eigenschaft von MSBuild definiert sind, wenn Sie diesen Code ebenfalls lesen möchten.

+0

Ich habe Ihre Empfehlung versucht, '.dll' mit' [Export] 'in Referenzen von benutzerdefinierten Aktionen Projekt, kein Glück. Wie Sie in meinem Beispiel sehen können, versuche ich nicht, 'Main Entry' aus der Ausführung des Assembly-Standorts zu erstellen, sondern suche im Ordner' Programme' nach, wo genau '.dll' zum Zeitpunkt der Ausführung existiert . Also Fiasko wurde erwartet – ivanblin

+0

Hmm es sollte funktionieren, da Sie die Dateien manuell an Ort und Stelle setzen können, damit es funktioniert. Ich würde einen Durchlauf durchführen, der Dateidaten mit procmon erfasst und sieht, was es zu laden versucht und wo es sucht. Vielleicht kann das etwas Licht ins Dunkel bringen. –

+0

Ich bin mir nicht sicher, ich verstehe genau, wie procmon funktioniert, aber wenn es nur eine Möglichkeit gibt zu sehen, wo Installer nach '.dll' suchen will, kann ich es im Debug-Modus tun – ivanblin

Verwandte Themen