2013-07-23 1 views
1

У меня есть компонент .Net dll, который вызывается из MS Access через COM Interop.Загрузить log4net.dll из альтернативного местоположения

Поскольку MSACCESS.EXE является вызывающим процессом, он по умолчанию будет пытаться найти файлы .config сборок и любые ссылочные ddls в том месте, где установлен MS Access.

Из-за проблем с развертыванием мы хотим, чтобы весь пользовательский код запускался из отдельного места, а не из структуры папок 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, и он удачно расположен, но затем он возвращается к попытке загрузить его из каталога 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) 
+0

я собираюсь оставить это для вас, но я хотел бы предложить изменить название для загрузки log4net конфигурации из различных местоположение или что-то такое, что является проблемой –

+0

Загрузка конфигурации log4net НЕ является проблемой. Это сама dll не может быть найдена. Внутренний вывод отладки запутан, но если вы внимательно прочитаете его, вы увидите, что это файл dll, который не может быть найден. – Remoh

+0

Извините, я неправильно понял –

ответ

1

я использовал что-то подобное раньше. Некоторые замечания, хотя:.

  • Это довольно общее, так что не стесняйтесь изменять его по мере необходимости
  • Вы можете потенциально испортить AppDomain, если есть противоречивые версии (то есть основное приложение использует log4net 2.0 и приложение использует log4net 3,0)

код:

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() 
+0

Спасибо, но я не думаю, что понимаю, как это будет использоваться от основного компонента для загрузки сборки. У вас есть пример, показывающий, как он называется? – Remoh

+0

@Remoh Я только что обновил свой ответ. Он довольно прост в использовании. Если вам нужны комментарии о том, что делает этот метод, дайте мне знать –

+0

Thanks Justin.Это помогает загрузить сборку. Но я узнал из-за некоторой дополнительной отладки, что и мой оригинальный подход (с использованием установки времени сборки в файле конфигурации) также работает. Похоже, что log4net.dll находится в коллекции загруженных сборок, но затем как-то «теряется», когда другая ссылочная dll создает объект журнала и пытается регистрировать некоторую информацию. – Remoh

 Смежные вопросы

  • Нет связанных вопросов^_^