如何在 .NET 自定义操作中使用企业库日志记录

发布于 2024-07-10 23:14:44 字数 745 浏览 6 评论 0原文

我有一些在我的应用程序中使用的库代码,也由 Visual Studio 安装程序项目中的 .NET 自定义操作使用。 库代码又使用企业库日志记录块来进行日志记录。 如何在 msiexec 内运行的自定义操作上下文中获取企业库的配置信息? 在对 EntLib 进行任何调用之前,是否可以在代码中引导配置机制?

更新:我已经制作了一个黑客,看起来它可以工作,但依赖于使用反射设置非公共静态字段。 遗憾的是 EntLib 与 .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" );

更新 2:虽然该 hack 在测试台中有效,但当在 msiexec 上下文中运行时,程序集加载器找不到配置文件中引用的程序集。 Fuslogvw表明AppBase是windows system32目录,这是有一定道理的。 我不明白的是为什么找到了自定义操作程序集的清单依赖项(位于自定义操作程序集旁边的 [TargetDir] 目录中),但没有找到配置文件中调用的动态加载程序集。 看不到任何解决办法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夏见 2024-07-17 23:14:44

无法使用标准的 app.config 方式,因为 app.config 是您在执行 MSI 之前需要编辑的 msiexec.config。 我的建议是使用您自己的配置加载方法,该方法从自定义 XML 或 MSI 中的值读取。

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.

戏蝶舞 2024-07-17 23:14:44

我相信问题是您的自定义操作程序集正在 LoadFrom context,因此其清单依赖项是相对于其代码库解析的。

您可以通过创建新的 AppDomain 来解决此问题。 这将使您有机会重置基本目录、加载新的 App.config 文件等等。 使用 AppDomain.CreateDomain(String, Evidence, AppDomainSetup) 创建新的 AppDomain,填充 ApplicationBase、ConfigurationFile 的 AppDomainSetup 属性,等等。

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.

梦在夏天 2024-07-17 23:14:44

不确定这是否有帮助,但您可以从自定义操作中写入 msi 日志。 (下面是 VBScript 示例:)

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

来自 MSDN 的更多信息:http://msdn.microsoft .com/en-us/library/aa371672.aspx

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

攒眉千度 2024-07-17 23:14:44

我遇到了类似的问题,msiexec 无法加载自定义操作依赖项,目前我的解决方案是将依赖程序集复制到系统目录中。 这是一个糟糕的解决方案,但它确实有效。

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);

另一种选择是将企业库程序集安装到 GAC 中。 如果您这样做,您将需要使用 Orca 让安装程序在运行自定义操作之前安装到 GAC 中,默认情况下首先运行自定义操作。

我仍在寻找一个非常巧妙的解决方案,当我找到它时我会更新此回复。

I had 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.

芯好空 2024-07-17 23:14:44

这可能会帮助那些仍在处理 VS 安装程序的人:可以通过自定义操作使用动态加载的程序集,您只需要帮助运行时找到程序集即可。

执行此操作的方法是处理 AppDomain.AssemblyResolve 事件。 我在安装程序类的 Install 方法上执行了此操作,如下所示:

internal class MyInstaller : Installer
{
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);

        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // Resolve assemblies here, e.g.:
            return
                args.Name == "My.Assembly"
                ? Assembly.LoadFrom(this.Context.Parameters["TARGETDIR"] + "\\My.Assembly.dll")
                : null;
        };

        // Continue install...
    }
}

我建议阅读 关于实现处理程序的 MS 文档页面

This might help people still dealing with VS installers: it is possible to use dynamically-loaded assemblies from a custom action, you simply need to help the runtime locate the assemblies.

The way you do this is by handling the AppDomain.AssemblyResolve event. I did this on the Install method of my installer class, like this:

internal class MyInstaller : Installer
{
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);

        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // Resolve assemblies here, e.g.:
            return
                args.Name == "My.Assembly"
                ? Assembly.LoadFrom(this.Context.Parameters["TARGETDIR"] + "\\My.Assembly.dll")
                : null;
        };

        // Continue install...
    }
}

I would recommend reading the MS Docs page on implementing the handler as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文