Why doesn't AutogenerateBindingRedirects work for a Web.config in Visual Studio 2017
Asked Answered
S

4

18

I have a reference to a .Net Standard 2.0 library that requires Microsoft.AspNet.WebApi.Client 5.2.4. This has a lot of dependencies that need to be redirected to use newer versions.

To avoid package/dependency explosion I've updated the first PropertyGroup in the csproj file:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>

I'm expecting AutoGenerateBindingRedirects to prevent me from needing to change the Web.config to match the versions added.

Why do I still need to add binding redirects to my Web.config to resolve assembly conflicts?

Striped answered 25/2, 2018 at 3:45 Comment(0)
S
29

It appears that AutoGenerateBindingRedirects will not work for web projects per https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/how-to-enable-and-disable-automatic-binding-redirection.

Inspecting the output from the build shows that binding redirects are generated just not in the Web.config. Instead, they are in $(AssemblyName).dll.config. This file has the original configuration from Web.config as well as the binding redirects.

To put it all together you can have MSBuild copy the resulting config back to the Web.config. To do this you would add the following to the csproj:

<Target Name="AfterBuild">
  <Copy SourceFiles="$(TargetDir)\$(AssemblyName).dll.config" DestinationFiles="Web.config" />
</Target>
Striped answered 25/2, 2018 at 3:45 Comment(4)
Note that there is also some visual studio integration that can update needed binding redirects in Web.config github.com/dotnet/standard/issues/613#issuecomment-354393350Thanasi
Daniel, you mentioned that the redirects will in fact be added to the output .dll.config, just not to the source web.config. Is it possible to disable this auto-generation of redirects to the output .dll.config? Because I tried setting the .csproj settings to false for AutoGenerateBindingRedirects and GenerateBindingRedirectsOutputType, but this did not stop them from being auto-generated.Detest
I had to define it as <Target Name="CopyGeneratedBindingRedirects" AfterTargets="AfterBuild"> to get it to work. Perhaps because there were already some other AfterBuild Targets.Smack
Note that this solution replaces one's existing web.config file with just the binding redirects - this may not be what you require. See @Александр Пушкин's solution above for a solution which merges XML files - noting that his answer has two approaches (IIS Express only, and IIS Express/IIS). I've confirmed that his approach works well.Cherub
P
7

For iis express: In Web.config replace section assemblyBinding with

  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <linkedConfiguration href="file:{AssemblyName}.dll.config"/>
  </assemblyBinding>

For iis and iis express:

add to project Scripts\CopyRuntimeSection.ps1

param ($from, $to)
$projectPath = Resolve-Path "$($PSScriptRoot)\..\"

$fromFilePath = "$projectPath\$from";
$toFilePath = "$projectPath\$to";

$fromFileXml = [xml](Get-Content -Path $fromFilePath -Raw)
$toFileXml = [xml](Get-Content -Path $toFilePath -Raw)

$toFileXml.configuration.runtime.InnerXml = $fromFileXml.configuration.runtime.InnerXml
$toFileXml.Save($toFilePath)

add to csproj

  <Target Name="CopyRuntimeSection" AfterTargets="Build">
    <Exec Command="PowerShell -File Scripts\CopyRuntimeSection.ps1 -from $(OutDir)\$(AssemblyName).dll.config -to Web.config" />
  </Target>
Popedom answered 10/1, 2020 at 10:10 Comment(0)
S
2

Expanding on the other answer from this question, here's a solution that supports incremental builds and uses absolute paths for greater flexibility:

Add this somewhere in your solution (I named it UpdateBindingRedirect.ps1):

param ($from, $to)

$fromFileXml = [xml](Get-Content -Path $from -Raw)
$toFileXml = [xml](Get-Content -Path $to -Raw)

if ( $toFileXml.configuration.runtime.InnerXml -Ne $fromFileXml.configuration.runtime.InnerXml ) {
    $toFileXml.configuration.runtime.InnerXml = $fromFileXml.configuration.runtime.InnerXml
    $toFileXml.Save($to)
}

Add this to your csproj:

  <Target Name="UpdateBindingRedirects" AfterTargets="Build" Inputs="$(OutDir)$(AssemblyName).dll.config" Outputs="$(ProjectDir)Web.config">
    <Message Text="Update binding redirects from $(ProjectDir)$(OutDir)$(AssemblyName).dll.config" />
    <Exec Command="PowerShell -NoLogo -NoProfile -File ..\UpdateBindingRedirects.ps1 -from $(ProjectDir)$(OutDir)$(AssemblyName).dll.config -to $(ProjectDir)Web.config" />
  </Target>
Syrinx answered 6/1, 2021 at 15:44 Comment(0)
C
-1

There is a recipe from

https://github.com/CZEMacLeod/MSBuild.SDK.SystemWeb

that you can repurpose to update binding redirects on Web.config automatically.

Warning: not tested

  1. Add a property
<PropertyGroup>
 <OverwriteAppConfigWithBindingRedirects>true</OverwriteAppConfigWithBindingRedirects>
</PropertyGroup>
  1. Use the build target UpdateConfigWithBindingRedirects as defined here https://github.com/CZEMacLeod/MSBuild.SDK.SystemWeb/blob/main/src/MSBuild.SDK.SystemWeb/Sdk/Sdk.targets
  <Target Name="UpdateConfigWithBindingRedirects" AfterTargets="AfterBuild" Condition="'$(OverwriteAppConfigWithBindingRedirects)'=='true'">
    <ItemGroup>
      <_DllConfig Remove="@(_DllConfig)" />
      <_AppConfig Remove="@(_AppConfig)" />
      <_ConfigFile Remove="@(_ConfigFileHash)" />
      <_DllConfig Include="$(OutDir)$(AssemblyName).dll.config" />
      <_AppConfig Include="web.config" />
    </ItemGroup>
    <GetFileHash Files="@(_DllConfig)">
      <Output TaskParameter="Hash" PropertyName="_DllConfigHash" />
      <Output TaskParameter="Items" ItemName="_DllConfigFileHash" />
    </GetFileHash>
    <GetFileHash Files="@(_AppConfig)">
      <Output TaskParameter="Hash" PropertyName="_AppConfigHash" />
      <Output TaskParameter="Items" ItemName="_AppConfigFileHash" />
    </GetFileHash>
    <ItemGroup>
      <_ConfigFileHash Include="@(_DllConfigFileHash)" />
      <_ConfigFileHash Include="@(_AppConfigFileHash)" />
    </ItemGroup>
    <Message Text="%(_ConfigFileHash.Identity): %(_ConfigFileHash.FileHash)" />
    <Warning Text="Replacing web.config due to changes during compile - This should clear warning MSB3276 on next compile" File="web.config" Condition="'$(_DllConfigHash)'!='$(_AppConfigHash)'" />
    <Copy SourceFiles="$(OutDir)$(AssemblyName).dll.config" DestinationFiles="web.config" Condition="'$(_DllConfigHash)'!='$(_AppConfigHash)'" />
  </Target>
Courteous answered 25/2, 2018 at 3:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.