Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 16 additions & 44 deletions docs/Binding_Redirects/Autogenerating-Binding-Redirects.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,30 @@
# Autogenerating Binding Redirects

The template will, on compile, generate a copy of the current `web.config` with any required binding redirects added.
This file is written to the `bin` folder with the name `AssemblyName.dll.config` where `AssemblyName` is the name of your assembly.
The template will, on compile, discover any required binding redirects.

You can set the `AssemblyName` by adding
```xml
<AssemblyName>MyAssemblyName</AssemblyName>
```
to your project file as normal.
You may see a build warning `Warning MSB3276 Found conflicts between different versions of the same dependent assembly. Please set the "AutoGenerateBindingRedirects" property to true in the project file. For more information, see http://go.microsoft.com/fwlink/?LinkId=294190.`, and one of three possible actions can be taken with these discovered Binding Redirections

If you get the error `Warning MSB3276 Found conflicts between different versions of the same dependent assembly. Please set the "AutoGenerateBindingRedirects" property to true in the project file. For more information, see http://go.microsoft.com/fwlink/?LinkId=294190. <project name here>`, then you can manually copy the
## None
If you Would like No Action to be taken with these suggestions, set the `GeneratedBindingRedirectionsAction` to `None` in your project file.
```xml
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
...
</assemblyBinding>
</runtime>
<PropertyGroup>
<GeneratedBindingRedirectsAction>None</GeneratedBindingRedirectsAction>
</PropertyGroup>
```
section from the generated `.dll.config` file to your web.config file, replacing the existing `assemblyBinding` node.

Alternatively, since the `.dll.config` file is based on your `web.config` file, you can just overwrite your `web.config` file with the `.dll.config` file.

If you want this to happen automatically, you can add the following to your project file.
## Preview
You can also choose to `Preview` and generate a file `Web.BindingRedirects.config` that contains the suggested Binding Redirects.
```xml
<PropertyGroup>
<OverwriteAppConfigWithBindingRedirects>true</OverwriteAppConfigWithBindingRedirects>
<GeneratedBindingRedirectsAction>Preview</GeneratedBindingRedirectsAction>
</PropertyGroup>
```

This enables the following target in the SDK which will overwrite your web.config from the patched version if there are any changes.

## Overwrite
Alternatively the suggested Binding Redirects can be written directly to the `web.config`.
If you want this to happen automatically, you can add the following to your project file.
```xml
<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>
<PropertyGroup>
<GeneratedBindingRedirectsAction>Overwrite</GeneratedBindingRedirectsAction>
</PropertyGroup>
```
57 changes: 7 additions & 50 deletions docs/Binding_Redirects/How-to-show-Suggested-Binding-Redirects.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,12 @@

The following may be useful if you need to see generated binding redirects.
e.g. if you want to manually add them to your `web.config`
```xml
<UsingTask TaskName="ShowBindingRedirects" TaskFactory="$(TaskFactory)" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<SuggestedBindingRedirects ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Reflection" />
<Using Namespace="System.Xml" />
<Using Namespace="Microsoft.Build.Framework" />
<Code Type="Fragment" Language="cs">
<![CDATA[
StringBuilder sb = new StringBuilder();
foreach(var sbr in SuggestedBindingRedirects) {
var an = new AssemblyName(sbr.ItemSpec);
var mvn = sbr.GetMetadata("MaxVersion");

byte []pt = an.GetPublicKeyToken();

sb.AppendLine("<assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">");
sb.AppendLine("\t<dependentAssembly>");
sb.Append("\t\t<assemblyIdentity name=\"");
sb.Append(an.Name);
sb.Append("\" publicKeyToken=\"");
if (pt is null) {
sb.Append("null");
} else {
for (int i=0;i<pt.GetLength(0);i++)
sb.AppendFormat("{0:x2}", pt[i]);
}
sb.Append("\" culture=\"");
sb.Append(an.CultureName);
sb.AppendLine("\" />");
sb.Append("\t\t<bindingRedirect oldVersion=\"0.0.0.0-");
sb.Append(mvn);
sb.Append("\" newVersion=\"");
sb.Append(mvn);
sb.AppendLine("\" />");
sb.AppendLine("\t</dependentAssembly>");
sb.AppendLine("</assemblyBinding>");
}
Log.LogMessage(MessageImportance.High,sb.ToString());
]]>
</Code>
</Task>
</UsingTask>
Add this into your csproj
```xml
<PropertyGroup>
<GeneratedBindingRedirectsAction>Preview</GeneratedBindingRedirectsAction>
</PropertyGroup>
```

<Target Name="ShowBindingRedirects" AfterTargets="ResolveAssemblyReferences">
<ShowBindingRedirects SuggestedBindingRedirects="@(SuggestedBindingRedirects)" Condition="'@(SuggestedBindingRedirects)'!=''" />
</Target>
```
And then look for a `Web.BindingRedirects.config` file in your project's Solution Explorer.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!--
====================================================================================================

GenerateBindingRedirects Behaviors

Traditionally (Microsoft.Common.CurrentVersion.targets) only Performs BindingRedirect calculations when
Project type is deemed to "need" redirects -> when OutputType == 'exe' or OutputType == 'winexe' (Microsoft.Common.CurrentVersion.targets)
AND
Not an "old" project, aka either
An SDK project type that incorporates Microsoft.NET.Sdk (Microsoft.NET.Sdk.BeforeCommon.targets)
OR
A newer Full Framework project TargetFrameworkIdentifier == '.NETFramework' and '$(TargetFrameworkVersion.TrimStart(vV))' >= '4.7.2' (Microsoft.Common.CurrentVersion.targets)
Additionally it chooses the filename of the config file to be updated as what exe projects want...
$(IntermediateOutputPath)$(TargetFileName).config -> the config file named after the assembly and in the IntermediateOutputPath

https://github.com/CZEMacLeod/MSBuild.SDK.SystemWeb/issues/34
This SDK Project Type will override these settings so that we can facilitate developers working with BindingRedirects in the web.config
Enable the Build Process to calculate Binding Redirects
GenerateBindingRedirectsOutputType(true - even though this project is not an .exe or .winexe)
AutoGenerateBindingRedirects (true - set explictly even though should be set by Microsoft.NET.Sdk.BeforeCommon.targets)
Take an action
OverwriteAppConfigWithBindingRedirects -> this is the SystemWeb Sdk Legacy property
GeneratedBindingRedirectsAction (Overwrite) -> this will conditionally change wich config file is written to
====================================================================================================
-->

<Project>

<PropertyGroup Label="Change the default BindingRedirects behavior for projects of this SDK type">
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<AutoGenerateBindingRedirects Condition=" '$(AutoGenerateBindingRedirects)' == '' ">true</AutoGenerateBindingRedirects>
</PropertyGroup>

<PropertyGroup Label="Set the desire default behavior of what to do with SuggestedBindingRedirects if not yet set"
Condition=" '$(GeneratedBindingRedirectsAction)' == ''">
<GeneratedBindingRedirectsAction>None</GeneratedBindingRedirectsAction>
<GeneratedBindingRedirectsAction Condition=" '$(OverwriteAppConfigWithBindingRedirects)' != 'true' ">Preview</GeneratedBindingRedirectsAction>
<GeneratedBindingRedirectsAction Condition=" '$(OverwriteAppConfigWithBindingRedirects)' == 'true' ">Overwrite</GeneratedBindingRedirectsAction>
</PropertyGroup>


<!--
====================================================================================================

SystemWebProject_ChooseConfigFileForGenerateBindingRedirects

This target should executes between
ResolveAssmblyReferences (where the "@(SuggestedBindingRedirects)" itemgroup is populated... based on the logic that resolves assemblies being referenced
and
GenerateBindingRedirects (where the suggestedBindingRedirects are written to disk into a config file at $(_GenerateBindingRedirectsIntermediateAppConfig)

Then we can choose where the suggestedBindingRedirects are written, if at all (Default Value is Overwrite unless set by project)
'$(GeneratedBindingRedirectsAction)' == 'Preview' -> Creates new Web.BindingRedirects.config file showing proposed changes
'$(GeneratedBindingRedirectsAction)' == 'Overwrite' -> Updates the $(AppConfig) aka web.config in the project root
'$(GeneratedBindingRedirectsAction)' == Something Unknown -> Prints message giving options of what the developer can choose from

In general we want to emit a "warning" whenever we either do, or don't do something to help developers find the property that drives this behavior
====================================================================================================
-->
<Target Name="SystemWebProject_ChooseConfigFileForGenerateBindingRedirects"
BeforeTargets="GenerateBindingRedirects"
Condition="'$(AutoGenerateBindingRedirects)' == 'true' and '$(GenerateBindingRedirectsOutputType)' == 'true' and @(SuggestedBindingRedirects->Count()) > 0 ">

<PropertyGroup Label="Set the location of the file to which the suggestedBindingRedirects should be written during the GenerateBindingRedirects Target">
<_GenerateBindingRedirectsIntermediateAppConfig Condition="'$(GeneratedBindingRedirectsAction)' == 'Preview' " >Web.BindingRedirects.config</_GenerateBindingRedirectsIntermediateAppConfig>
<_GenerateBindingRedirectsIntermediateAppConfig Condition="'$(GeneratedBindingRedirectsAction)' == 'Overwrite' " >$(AppConfig)</_GenerateBindingRedirectsIntermediateAppConfig>
</PropertyGroup>

<Warning Condition="'$(GeneratedBindingRedirectsAction)' != 'Preview' and '$(GeneratedBindingRedirectsAction)' != 'Overwrite'"
Text="Generated Binding Redirects have been applied only to the $(TargetFileName).config. You should incorporate them into the web.config. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Preview&lt;/GeneratedBindingRedirectsAction&gt; to create a file containing the proposals. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Overwrite&lt;/GeneratedBindingRedirectsAction&gt; to automatically update web.config with proposals." />

<Warning Condition="'$(GeneratedBindingRedirectsAction)' == 'Preview'"
Text="Generated Binding Redirects have been applied only to the Web.BindingRedirects.config. You should incorporate them into the web.config. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Overwrite&lt;/GeneratedBindingRedirectsAction&gt; to automatically update web.config with proposals." />

<Warning Condition="'$(GeneratedBindingRedirectsAction)' == 'Overwrite'"
Text="Generated Binding Redirects have been applied automatically to the web.config. This warning will disappear on the next build." />

</Target>



</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<ItemGroup Condition="'$(EnableWebFormsDefaultItems)'=='true'">
<Content Include="Web.config" />
<_WebConfigConfigurations Include="$(Configurations)" />
<None Include="@(_WebConfigConfigurations->'Web.%(Identity).config')">
<None Include="@(_WebConfigConfigurations->'Web.%(Identity).config');Web.BindingRedirects.config">
<DependentUpon>Web.config</DependentUpon>
</None>
<Content Include="Web.*.config" Exclude="@(_WebConfigConfigurations->'Web.%(Identity).config')">
<Content Include="Web.*.config" Exclude="@(None)">
<DependentUpon>Web.config</DependentUpon>
</Content>
</ItemGroup>
Expand Down
6 changes: 0 additions & 6 deletions src/MSBuild.SDK.SystemWeb/Sdk/Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
<PublishProfileImported>true</PublishProfileImported>
<AppConfig>web.config</AppConfig>

<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<ItemGroup>
<ProjectCapability Include="DotNetCoreWeb" />
Expand All @@ -18,10 +16,6 @@
<ProjectCapability Include="LegacyRazorEditor" />
</ItemGroup>

<PropertyGroup>
<OverwriteAppConfigWithBindingRedirects Condition="'$(OverwriteAppConfigWithBindingRedirects)'==''">false</OverwriteAppConfigWithBindingRedirects>
</PropertyGroup>

<Import Project="MSBuild.SDK.SystemWeb.DefaultPackages.props" />
<!-- Default item includes -->
<Import Project="MSBuild.SDK.SystemWeb.DefaultItems.props" />
Expand Down
29 changes: 4 additions & 25 deletions src/MSBuild.SDK.SystemWeb/Sdk/Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,13 @@
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>

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

<!-- Default item excludes -->
<Import Project="MSBuild.SDK.SystemWeb.DefaultItems.targets" />

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

<!-- Inject BindingRedirects targets after Microsoft.NET.Sdk is injected -->
<Import Project="MSBuild.SDK.SystemWeb.BindingRedirects.targets" />

<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" />
</Project>