C# 如何在运行时更新配置文件中的 assemblyBinding 部分?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/325788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:16:48  来源:igfitidea点击:

how to update assemblyBinding section in config file at runtime?

c#.netconfiguration

提问by Julien Hoarau

I'm trying to change assembly binding (from one version to another) dynamically.

我正在尝试动态更改程序集绑定(从一个版本到另一个版本)。

I've tried this code but it doesn't work:

我试过这段代码,但它不起作用:

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

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

      ConfigurationManager.RefreshSection("assemblyBinding");

with bindingConf.xmlcontaining the assemblyBinding section configuration.

bindingConf.xml含有assemblyBinding部配置。

So can a change this section at runtime? how to do it? What alternatives do I have?

那么可以在运行时更改此部分吗?怎么做?我有哪些选择?

采纳答案by Eric Rosenberger

The best way I've found to dynamically bind to a different version of an assembly is to hook the AppDomain.AssemblyResolveevent. This event is fired whenever the runtime is unable to locate the exact assembly that the application was linked against, and it allows you to provide another assembly, that you load yourself, in its place (as long as it is compatible).

我发现动态绑定到不同版本的程序集的最佳方法是挂钩AppDomain.AssemblyResolve事件。每当运行时无法找到应用程序链接到的确切程序集时,就会触发此事件,并且它允许您提供另一个程序集,您自己加载,代替它(只要它兼容)。

For example, you can put in a static constructor on your application's main class that hooks the event like this:

例如,您可以在应用程序的主类上放置一个静态构造函数,它可以像这样挂钩事件:

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

This method avoids the need to deal with the assembly bindings in configuration files and is a bit more flexible in terms of what you can do with it.

这种方法不需要处理配置文件中的程序集绑定,并且在您可以使用它做什么方面更加灵活。

回答by Julien Hoarau

RuntimeSection of the config file update at runtime using this code:

使用以下代码在运行时更新配置文件的 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");
  }
}

with Framework35Rebinding containing:

与 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>

and an app.config containing (before the execution of the program):

和一个 app.config 包含(在程序执行之前):

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

Nevertheless it doesn't work for that I wanna do because assemblyBinding is only read at startup of the application whereas the RefreshSection("runtime")

尽管如此,它对我想做的事情不起作用,因为 assemblyBinding 仅在应用程序启动时读取,而 RefreshSection("runtime")

回答by Josh Mouch

I love Eric's answer. It's a lifesaver when trying to use the new buggy NuGet PackageReference model with a Web app. The problem is that you can have msbuild automatically generate the bindings, however, they generate the bindings to Assembly.dll.config, and not to web.config. So this workaround is great.

我喜欢埃里克的回答。当尝试将新的有缺陷的 NuGet PackageReference 模型与 Web 应用程序一起使用时,它是一个救星。问题是您可以让 msbuild 自动生成绑定,但是,它们生成到 Assembly.dll.config 的绑定,而不是 web.config。所以这个解决方法很棒。

I've modified Eric's code a bit to make it more generic and work with an ASP.Net Core app:

我稍微修改了 Eric 的代码,使其更通用并与 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;
            };