views:

1450

answers:

4

I have some library code which is used from my application and is also used by a .NET custom action in a Visual Studio installer project. The library code in turn uses the Enterprise Library logging block to do its logging. How can I get configuration information to the Enterprise Library in the context of my custom action running inside msiexec? Is it possible to bootstrap the config mechanism in code before I make any calls to the EntLib?

Update: I've produced a hack that seems like it will work but relies on setting a non-public static field using reflection. It's a shame that EntLib is so tightly coupled to the .NET ConfigurationManager.

var factory = new LogWriterFactory( new FakeConfigSource( "foo.config" ) );
var field = typeof ( Logger ).GetField( "factory", BindingFlags.Static | BindingFlags.NonPublic );
field.SetValue( null, factory );
Logger.Write( "Test" );

Update 2: Although that hack works in a testbed, when run in the context of msiexec, the assembly loader does not find the assemblies referenced in the config file. Fuslogvw indicates that AppBase is the windows system32 directory, which makes some sense. What I don't understand is why the custom action assembly's manifest dependencies (which are in the [TargetDir] directory alongside the custom action assembly) are found, but dynamically-loaded assemblies called out in the config file are not. Can't see any way around this.

A: 

Not sure if this helps, but you can write to the msi log from within a custom action. (Sample VBScript below:)

Const msiMessageTypeInfo = &H04000000
Const msiMessageTypeFatalExit = &H00000000
Const msiMessageTypeError = &H01000000
Const msiMessageTypeWarning = &H02000000
Const msiMessageTypeUser = &H03000000 

Dim rec : Set rec = Session.Installer.CreateRecord(1)
rec.StringData(1) = "Your log message."

Session.Message msiMessageTypeInfo, rec

More info from MSDN: http://msdn.microsoft.com/en-us/library/aa371672.aspx

w4g3n3r
Yeah, thanks but not really what I'm after. I am using library code which uses the enterprise library. I don't actually need to log anywhere, it's simply that the deeply-nested code using the entlib is trying to initialize itself from config.
jlew
A: 

I have a similar problem with msiexec not being able to load a custom actions dependencies currently my solution is to copy the dependent assemblies into the system directory. This is an awful solution but it does work.

string installDir = System.IO.Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().Location);
System.IO.File.Copy(
                System.IO.Path.Combine(installDir, "<Insert Assembly Name>.dll"),
                System.IO.Path.Combine(Environment.SystemDirectory, "<Insert Assembly Name>.dll"),
                true);

One other option would be to install the enterprise library assemblies into the GAC. If you do this you will need to edit the msi using something like Orca to make the installer install into the GAC before is runs the custom actions by default custom actions run first.

I am still looking for a really neat solution to this and I'll update this response when i find it.

John Hunter
+1  A: 

There is no way to use the standard app.config way because that app.config is the msiexec.config you would need to edit prior to executing your MSI. My recommendation would be to have your own configuration loading method which reads from a custom XML or values in the MSI.

Robert MacLean
Does not appear possible with the enterprise library.
jlew
+1  A: 

I believe the issue is that your custom action assembly is being loaded in the LoadFrom context, so its manifest dependencies are resolved relative to its codebase.

You may be able to resolve this issue by creating a new AppDomain. This will give you the opportunity to reset your base directory, load a new App.config file, and so forth. Use AppDomain.CreateDomain(String, Evidence, AppDomainSetup) to create the new AppDomain, populating the AppDomainSetup properties for ApplicationBase, ConfigurationFile, and so on.

Jeffrey Hantin