10

I am trying to change the bindingRedirect element at install time by using the XmlDocument class and modifying the value directly. Here is what my app.config looks like:

<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">            
            ...
        </sectionGroup>      
    </configSections>
    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
          <assemblyIdentity name="MyDll" publicKeyToken="31bfe856bd364e35"/>
          <bindingRedirect oldVersion="0.7" newVersion="1.0"/>
        </dependentAssembly>
     </assemblyBinding>
    </runtime>    
...
</configuration>

I then try to use the following code to change 1.0 to 2.0

private void SetRuntimeBinding(string path, string value)
{
    XmlDocument xml = new XmlDocument();

    xml.Load(Path.Combine(path, "MyApp.exe.config"));
    XmlNode root = xml.DocumentElement;

    if (root == null)
    {
        return;
    }

    XmlNode node = root.SelectSingleNode("/configuration/runtime/assemblyBinding/dependentAssembly/bindingRedirect/@newVersion");

    if (node == null)
    {
        throw (new Exception("not found"));
    }

    node.Value = value;

    xml.Save(Path.Combine(path, "MyApp.exe.config"));
}

However, it throws the 'not found' exception. If I back the path up to /configuration/runtime it works. However once I add assemblyBinding, it does not find the node. Possibly this has something to do with the xmlns? Any idea how I can modify this? ConfigurationManager also does not have access to this section.

Cœur
  • 37,241
  • 25
  • 195
  • 267
esac
  • 24,099
  • 38
  • 122
  • 179

3 Answers3

10

I found what I needed. The XmlNamespaceManager is required as the assemblyBinding node contains the xmlns attribute. I modified the code to use this and it works:

    private void SetRuntimeBinding(string path, string value)
    {
        XmlDocument doc = new XmlDocument();

        try
        {
            doc.Load(Path.Combine(path, "MyApp.exe.config"));
        }
        catch (FileNotFoundException)
        {
            return;
        }

        XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
        manager.AddNamespace("bindings", "urn:schemas-microsoft-com:asm.v1");

        XmlNode root = doc.DocumentElement;

        XmlNode node = root.SelectSingleNode("//bindings:bindingRedirect", manager);

        if (node == null)
        {
            throw (new Exception("Invalid Configuration File"));
        }

        node = node.SelectSingleNode("@newVersion");

        if (node == null)
        {
            throw (new Exception("Invalid Configuration File"));
        }

        node.Value = value;

        doc.Save(Path.Combine(path, "MyApp.exe.config"));
    }
esac
  • 24,099
  • 38
  • 122
  • 179
  • 1
    Just a note, I throw exceptions as this is part of an Setup Project and that is how the installer is notified of any errors. It would be better to have the method return true or false if the modification was made. – esac May 01 '09 at 00:11
8

Sounds like you've got your configuration file tweak working now, but I thought you might still be interested in how to adjust binding redirects at run time. The key is to use the AppDomain.AssemblyResolve event, and the details are in this answer. I prefer it over using the configuration file, because my version number comparison can be a bit more sophisticated and I don't have to tweak the configuration file during every build.

Community
  • 1
  • 1
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • 3
    This works, if the assembly load initially fails. However if your app manages to successfully load the _wrong_ assembly, the AssemblyResolve never fires. So the only option in that case is to modify the app.config. – Phil Sep 03 '14 at 21:27
  • Wish I could retract my vote. This actually doesn't work if the binding is set, as of .NET 4.6.1. Still get assembly binding failures. – marknuzz May 20 '16 at 04:09
-1

I think the right Xpath syntax is:

/configuration/runtime/assemblyBinding/dependentAssembly/bindingRedirect@newVersion

(you have a slash too many).

Or if this doesn't work you could select the bindingRedirect element (using SelectSingleNode):

/configuration/runtime/assemblyBinding/dependentAssembly/bindingRedirect

Then modify the attribute newVersion of this element.

Joe
  • 122,218
  • 32
  • 205
  • 338
  • Already been down this path, it complains of invalid token with bindingRedirect@newVersion. Second case, it complains that it could not find the path specified. – esac Apr 30 '09 at 22:31