Как обновить раздел AssemblyBinding в файле конфигурации во время выполнения? - PullRequest
9 голосов
/ 28 ноября 2008

Я пытаюсь динамически изменить привязку сборки (из одной версии в другую).

Я пробовал этот код, но он не работает:

      Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
      ConfigurationSection assemblyBindingSection = config.Sections["assemblyBinding"];

      assemblyBindingSection.SectionInformation.ConfigSource = "bindingConf.xml";
      config.Save(ConfigurationSaveMode.Modified);

      ConfigurationManager.RefreshSection("assemblyBinding");

с bindingConf.xml, содержащим конфигурацию секции AssemblyBinding.

Так можно ли изменить этот раздел во время выполнения? как это сделать? Какие у меня есть альтернативы?

Ответы [ 3 ]

19 голосов
/ 28 ноября 2008

Лучший способ, которым я нашел динамическое связывание с другой версией сборки, - перехватить событие AppDomain.AssemblyResolve. Это событие вызывается всякий раз, когда среда выполнения не может найти точную сборку, с которой было связано приложение, и позволяет вам предоставить вместо нее другую сборку, которую вы загружаете самостоятельно (если она совместима).

Например, вы можете вставить статический конструктор в основной класс вашего приложения, который перехватывает событие следующим образом:

using System.Reflection;

static Program()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
    {
        AssemblyName requestedName = new AssemblyName(e.Name);

        if (requestedName.Name == "AssemblyNameToRedirect")
        {
            // Put code here to load whatever version of the assembly you actually have

            return Assembly.LoadFrom("RedirectedAssembly.DLL");
        }
        else
        {
            return null;
        }
    };
}

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

3 голосов
/ 01 декабря 2008

RuntimeSection обновления файла конфигурации во время выполнения, используя этот код:

private void ModifyRuntimeAppConfig()
{
  XmlDocument modifiedRuntimeSection = GetResource("Framework35Rebinding");

  if(modifiedRuntimeSection != null)
  {
    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    ConfigurationSection assemblyBindingSection = config.Sections["runtime"];

    assemblyBindingSection.SectionInformation.SetRawXml(modifiedRuntimeSection.InnerXml);
    config.Save(ConfigurationSaveMode.Modified);
    ConfigurationManager.RefreshSection("runtime");
  }
}

с Framework35Rebinding, содержащим:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
      <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="3.5.0.0"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="Microsoft.CompactFramework.Build.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
      <bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="9.0.0.0"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

и файл app.config, содержащий (до выполнения программы):

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v2.0.50727"/>
  </startup>
  <runtime>
  </runtime>
</configuration>

Тем не менее, это не сработает, я хочу это сделать, потому что AssemblyBinding читается только при запуске приложения, тогда как RefreshSection("runtime")

1 голос
/ 19 марта 2019

Мне нравится ответ Эрика. Это спасает, когда вы пытаетесь использовать новую ошибочную модель NuGet PackageReference с веб-приложением. Проблема в том, что msbuild может автоматически генерировать привязки, однако они генерируют привязки к Assembly.dll.config, а не к web.config. Так что этот обходной путь хорош.

Я немного изменил код Эрика, чтобы сделать его более универсальным и работать с приложением ASP.Net Core:

AppDomain.CurrentDomain.AssemblyResolve += delegate (object sender2, ResolveEventArgs e2)
            {
                var requestedNameAssembly = new AssemblyName(e2.Name);
                var requestedName = requestedNameAssembly.Name;
                if (requestedName.EndsWith(".resources")) return null;
                var binFolder = System.Web.Hosting.HostingEnvironment.MapPath("~/bin");
                var fullPath = Path.Combine(binFolder, requestedName) + ".dll";
                if (File.Exists(fullPath))
                {
                    return Assembly.LoadFrom(fullPath);
                }

                return null;
            };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...