【问题标题】:Can I use / access the app.config from .net code, when called via COM当通过 COM 调用时,我可以从 .net 代码使用/访问 app.config
【发布时间】:2011-01-18 07:35:40
【问题描述】:

我有一组现有的 .net 库,我希望从 Excel VBA 中调用它们(该部分工作正常)。这些库依赖于 app.config 中的设置。我知道我可以在 excel.exe.config 文件中输入这些设置(与 excel.exe 位于同一目录中),但这对我来说似乎不是一个非常易于管理的解决方案,因为我可以看到如果不止一个应用程序想要这样做。

我的问题很简单:COM 公开的 dll 是否有任何方式引用它们各自的配置文件?

示例 app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="test" value="Hello world!" />
  </appSettings>
</configuration>

示例c#:

namespace ExcelVbaFacingCode
{
    public class SimpleAppSettingReader
    {
        public string GetValue(string key)
        {
            return ConfigurationManager.AppSettings[key];
        }
    }
}

VBA 示例:

Public Sub Test()
    Dim Test As New SimpleAppSettingReader
    Dim sampleValue As String
    sampleValue = Test.GetValue("test")
    MsgBox "Value: '" + sampleValue + "'", vbOKOnly
End Sub

【问题讨论】:

    标签: .net vba com app-config


    【解决方案1】:

    每当调用ConfigurationManager.AppSettings 时,它会自动打开正在执行的程序集的配置文件。在您的情况下,Excel 是执行应用程序,因此您无法打开 .Net DLL 的配置文件。

    这样做是有原因的。可以从多种类型的应用程序调用单个 DLL,每种应用程序可能有不同的要求(例如,可能还有不同的数据库)。因此,应用程序指定了设置,而不是引用的程序集。

    我认为您已经建议的是最好的方法。我知道您似乎正在复制您的配置文件,这意味着您需要担心代码何时更改,但这是最好的做法。

    【讨论】:

    • +1 我一直抱着不适用于 COM dll 的希望!不幸的是,我工作的公司是 Excel“应用程序”的忠实粉丝,所以我真的不想陷入我不得不开始担心与其他应用程序的设置冲突的情况。我怀疑我将不得不在应用程序中引入一些新的设置管理层:(
    • 如果他们对 excel 应用程序如此感兴趣,您应该查看 VSTO。它允许您进行更多控制(以及 .net 框架)。它比 VBA 好得多,但添加/转换非常简单。
    • 完全同意 VSTO,但是我继承了 VBA 宏,并希望从我们现有的一些 .net 代码中受益而无需重写。 VSTO绝对是长期战略!不用担心,在赏金到期之前会标记最佳答案:)
    • 使用 VSTO,您不必丢失现有代码。您可以轻松地从 VBA 调用 VSTO 函数,反之亦然。阅读本页:msdn.microsoft.com/en-us/magazine/cc163373.aspx#S4
    • 看起来您只能从 Office 2007+ 中的 VBA 调用 VSTO 代码 :(
    【解决方案2】:

    我在使用 web.config....时遇到了类似的问题。我找到了一个有趣的解决方案。您可以封装配置读取功能,例如。像这样:

    public class MyClass {
    
    public static Func<string, string> GetConfigValue = s => ConfigurationManager.AppSettings[s];
    
    //...
    
    }
    

    然后正常使用

    string connectionString = MyClass.GetConfigValue("myConfigValue");
    

    但在特殊情况下,首先“覆盖”这样的函数:

    MyClass.GetConfigValue = s =>  s == "myConfigValue" ? "Hi", "string.Empty";
    

    更多信息:

    http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/

    【讨论】:

    • +1 表示这个想法 - 与我在对 Gabriel McAdams 的回答的评论回复中提到的非常相似
    【解决方案3】:

    您确实可以指定 .NET 配置 API 将使用的配置文件,但您必须在创建 AppDomain 之前执行此操作(这并不像听起来那么容易。)这就是 ASP.NET 的工作原理例子。它将 AppDomain 设置为使用位于虚拟目录中的“web.config”文件,而不是需要 w3p.exe.config 或其他文件。

    您也可以这样做,但您需要创建一个辅助 AppDomain。由于许多与多个加载项和程序集引用有关的原因,这本身就是一个好主意。但是您可以在AppDomain's setup 中添加的内容之一是“app.config”文件的名称/路径。

    要创建新的 AppDomain,您可以使用“shim”,它是一些样板 C++ 代码,用于配置和启动 AppDomain,此后的其余代码都可以是托管代码。

    MSDN 上有一篇文章是 Andrew Whitechapel 写的,叫做Isolating Office Extensions with the COM Shim Wizard。我不会撒谎,这不是一个微不足道的概念,但也不算太糟糕。有一个向导可以为您创建 C++ 项目,它将 .NET 插件加载到新的 AppDomain 中。 AppDomain 的配置必须在加载之前完成,因此您需要将以下内容放入向导创建的代码中。

    // CLRLoader.cpp
    HRESULT CCLRLoader::CreateLocalAppDomain()
    {
    
        ... snip ...
    
        // Configure the AppDomain to use a specific configuration file
        pDomainSetup->put_ConfigurationFile(CComBSTR(szConfigFile));
    
        ... snip ...
    
    }
    

    还值得注意的是,如果/当您转换为 VSTO 项目时,VSTO 运行时会为您完成所有这些 AppDomain 配置。每个 VSTO 插件都在自己的 AppDomain 中运行,并带有自己的私有 app.config 文件。

    【讨论】:

    • 从表面上看,这正是我所追求的。将审查实施以确认。也感谢 VSTO 的提示
    • 还没有充分的机会来审查它以检查它是否有效,但从周围阅读它听起来就像它会做我想要的。在此基础上将其标记为答案。谢谢乔希!
    • 没问题。请随时与我联系,因为当我第一次参与 shiming 时,我是通过 C++ 对 COM 完全陌生,但经过一番磕磕绊绊,结果证明它确实提高了我的加载项的稳定性。
    • 看起来 COM shim 向导 v2.3.1.0 支持开箱即用的配置文件 (msdn.microsoft.com/en-us/library/bb508939.aspx)。事情进展顺利:)
    【解决方案4】:

    试试:

    ConfigurationManager.OpenExeConfiguration("foo.config");
    

    【讨论】:

    • OpenExeConfiguration 需要传递给它的 exe 路径,而不是配置文件的路径。但即使我使用它,它也只会给我一个配置对象,而不是将它加载到我当前的配置中。因此,我需要重写对 ConfigurationManager.AppSettings 的所有现有调用才能使其正常工作 - 这不是这些共享二进制文件的选项。
    【解决方案5】:

    据我了解,您希望配置对安装 dll 的机器是全局的。机器全局配置选项有一个 machine.config 文件。我自己从未使用过它,所以我没有任何更详细的信息,但它可能值得研究。 http://msdn.microsoft.com/en-us/library/ms229697(VS.71).aspx。在 Google 上搜索“machine.config”会得到更多看起来信息丰富的结果。

    另一种方法是在dll文件的安装目录下放一个自定义的xml文件。要获取文件的路径,请使用 System.Reflection.Assembly.GetExecutingAssembly.Location(或者可能是 CodeBase 而不是 Location)。不幸的是,您必须在 xml 文件之上构建自己的配置管理,但是感谢 Linq to XML,我认为 XML 比以往任何时候都更轻松。

    【讨论】:

    • 不幸的是,使用 machine.config 比使用 Excel.config 提供的粒度更小!谢谢你的想法
    • 您在寻找什么级别的粒度?也许我误解了这个问题 - 我以为你想要机器范围的配置,但不必将它与 Excel 放在一起。设置应该是机器范围的吗?或者当 COM 对象被调用时,您是否需要针对不同情况进行不同的设置?
    • 不。设置应该是应用程序(即宏)特定的
    • 你的意思是每个dll只有一个设置文件是不够的,而是你希望每个宏文件都有一个设置文件?
    • 抱歉,错过了您建议 xml 配置文件的部分。在我对其他答案的回复中评论了这种方法。
    【解决方案6】:

    还有另一种从我使用了几年的 COM 组件加载 .config 文件的方法。

    它是这样工作的:

    • 打开 dcomcnfg.exe
    • 创建一个新的 COM+ 应用程序
    • 在“激活”选项卡的“应用程序根目录”中输入您的 com 对象所在的文件夹
    • 将您的 com 对象添加到应用程序中
    • 在文件夹中放置一个名为“Application.manifest”的文件。该文件必须包含:

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" />

    • 将您的配置文件放在同一个文件夹中。配置文件的名称必须是“Application.config”,即不是“myapp.config”

    您可以在 application.config 中使用所有常规标签(例如 runtime、system.diagnostics 等)


    我使用 vbscript 创建 COM+ 应用程序:

    Dim allapps, newapp
    Set allapps = objCatalog.GetCollection("Applications")
    
    Set newapp = allapps.Add()
    newapp.Value("Name") = MyComAppName
    newapp.Value("ApplicationAccessChecksEnabled") = False 
    newapp.Value("Activation") = 1 '  own process
    newapp.Value("ApplicationDirectory") = WScript.CreateObject("WScript.Shell").CurrentDirectory
    allapps.SaveChanges
    WScript.Echo "Created application " & ComAppName
    
    objCatalog.ImportComponent ComAppName, MyComName
    WScript.Echo "Installed component " & MyComName
    

    【讨论】:

      猜你喜欢
      • 2018-07-11
      • 2011-08-03
      • 2010-09-18
      • 2011-03-08
      • 2012-06-09
      • 2013-03-20
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      相关资源
      最近更新 更多