2

我有一个自定义的 .Net dll 组件,它将通过 COM 互操作从 MS Access 调用。

因为 MSACCESS.EXE 是调用进程,默认情况下它将尝试在安装 MS Access 的位置定位程序集 .config 文件和任何引用的 ddls。

由于部署问题,我们希望所有自定义代码从单独的位置运行,而不是从 MS Office 文件夹结构中运行。

我已经能够使用以下方法强制程序集从自定义位置加载其配置信息:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", customPath);

typeof(ConfigurationManager)
            .GetField("s_initState", BindingFlags.NonPublic |
                                        BindingFlags.Static)
            .SetValue(null, 0);

typeof(ConfigurationManager)
            .GetField("s_configSystem", BindingFlags.NonPublic |
                                        BindingFlags.Static)
            .SetValue(null, null);

typeof(ConfigurationManager)
            .Assembly.GetTypes()
            .Where(x => x.FullName ==
                        "System.Configuration.ClientConfigPaths")
            .First()
            .GetField("s_current", BindingFlags.NonPublic |
                                    BindingFlags.Static)
            .SetValue(null, null);

这似乎工作正常,除日志记录外,此时一切似乎都正常。无论如何,log4net.dll 文件不会从 MSACCESS.EXE 所在目录以外的任何位置加载。

我尝试将以下内容添加到我的 app.config 文件中(log4net.dll 与我的 .Net 组件位于同一目录中),但它似乎被忽略了。

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <probing privatePath="c:\mycomponent" />
  </assemblyBinding>
</runtime> 

我使用 SysInternals procmon 来确认从 Access 调用组件时是否找到了 dll,并且它已成功定位,但随后它恢复为尝试从 MS Access 目录加载它并失败。

无论如何强制log4net.dll从我想要的位置加载?

这是 log4net 内部调试日志的输出:

log4net:ERROR Failed to parse config file. Is the <configSections> specified as: <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net, Version=1.2.11.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a" />
System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for log4net: Could not load file or assembly 'log4net' or one of its dependencies. The system cannot find the file specified. (C:\mycomponent\alt.config line 4) ---> System.IO.FileNotFoundException: Could not load file or assembly 'log4net' or one of its dependencies. The system cannot find the file specified.
   at System.Configuration.TypeUtil.GetTypeWithReflectionPermission(IInternalConfigHost host, String typeString, Boolean throwOnError)
   at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.Init(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord)
   at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.InitWithRestrictedPermissions(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord)
   at System.Configuration.RuntimeConfigurationRecord.CreateSectionFactory(FactoryRecord factoryRecord)
   at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)
   --- End of inner exception stack trace ---
   at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)
   at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
   at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
   at System.Configuration.ConfigurationManager.GetSection(String sectionName)
   at System.Configuration.ConfigurationSettings.GetConfig(String sectionName)
4

1 回答 1

1

我以前用过这样的东西。不过,一些注意事项:

  • 这是非常通用的,所以可以根据需要随意修改它
  • 如果存在冲突的版本(即主应用程序使用 log4net 2.0 而您的应用程序使用 log4net 3.0),您可能会弄乱 AppDomain

代码:

class AssemblyResolver
  {
    static AssemblyResolver()
    {
      AppDomain.CurrentDomain.AssemblyResolve +=
        (sender, args) =>
          {
            var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
            var instanceName = referencedAssemblies.ToList().First(x => x.FullName == args.Name).Name;
            var loadFile = Assembly.LoadFile(System.IO.Path.GetDirectoryName(Assembly.GetAssembly(typeof(AssemblyResolver)).Location) + @"\" + instanceName + ".dll");
            return loadFile;
          }; 
    }

    public AssemblyResolver()
    {

    }

  }

然后,要使用它,只需加载AssemblyResolver. 它的静态构造函数将处理维护

实例化代码时要做的第一件事:

new AssemblyResolver()
于 2013-07-23T18:10:52.703 回答