-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validate binding redirects #7153
Validate binding redirects #7153
Conversation
src/MSBuild/MSBuild.csproj
Outdated
</Task> | ||
</UsingTask> | ||
|
||
<Target Name="ValidateMSBuildPackageDependencyVersions" BeforeTargets="AfterBuild"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only run this target on .NET Framework builds (since that's the only case where the binding redirects apply).
foreach (var assemblyIdentityAttribute in dependentAssemblyXmlElement.Attributes) | ||
{ | ||
if (assemblyIdentityAttribute is XmlAttribute assemblyIdentityAttributeXmlElement && assemblyIdentityAttributeXmlElement.Name.Equals("name", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
name = assemblyIdentityAttributeXmlElement.Value; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can simplify this as
foreach (var assemblyIdentityAttribute in dependentAssemblyXmlElement.Attributes) | |
{ | |
if (assemblyIdentityAttribute is XmlAttribute assemblyIdentityAttributeXmlElement && assemblyIdentityAttributeXmlElement.Name.Equals("name", StringComparison.OrdinalIgnoreCase)) | |
{ | |
name = assemblyIdentityAttributeXmlElement.Value; | |
} | |
} | |
name = dependentAssemblyXmlElement.GetAttribute("name"); |
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(version)) | ||
{ | ||
string path = Path.Combine(AssemblyPath, name + ".dll"); | ||
string assemblyVersion = File.Exists(path) ? Assembly.LoadFile(path).GetName().Version.ToString() : version; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling LoadFile
will load the assemblies into the running MSBuild process in a way that's not unloadable, potentially causing problems on subsequent builds (the same problem you're tackling for task assemblies in #7132).
Fortunately since we just need the assembly identity, we don't need to use System.Reflection.Metadata
here.
string assemblyVersion = File.Exists(path) ? Assembly.LoadFile(path).GetName().Version.ToString() : version; | |
string assemblyVersion = AssemblyName.GetAssemblyName(path).Version.ToString(); |
I don't think the File.Exists
default is right--we want to guarantee that we ship the file if we have a binding redirect for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've found a number of cases that seem pretty reasonable that we should ignore like M.B.Conversion.Core, M.B.Engine, and M.NET.StringTools.net35. I can make a list of assemblies to ignore, but it's a bit messy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll ignore all of them, then let you comment on which to keep. (So far, I'd say those three and none of the others.)
{ | ||
if (!(String.Equals(name, "System.ValueTuple", StringComparison.OrdinalIgnoreCase) && String.Equals(version, "4.0.0.0") && String.Equals(assemblyVersion, "4.0.3.0"))) | ||
{ | ||
Log.LogError($"Binding redirect for '{name}' redirects to a different version ({version}) than MSBuild ships ({assemblyVersion})."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be really nice if you could log the line number in the app.config in this error--then GitHub can put a nice annotation up indicating "you should edit here!"
This appears to be possible but nontrivial: https://stackoverflow.com/a/45182162
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly more complicated—this could be an issue in Packages.props or app.config, so if I specify a specific line (in app.config), I may be completely off. I think the current version is roughly as informative (gives the assembly name, so you can find it quickly) but without that possibility of erring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I agree with this reasoning--why not point explicitly to one of the locations? But since it's fiddly to get the line number you can leave it if you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much cleaner!
{ | ||
if (!(String.Equals(name, "System.ValueTuple", StringComparison.OrdinalIgnoreCase) && String.Equals(version, "4.0.0.0") && String.Equals(assemblyVersion, "4.0.3.0"))) | ||
{ | ||
Log.LogError($"Binding redirect for '{name}' redirects to a different version ({version}) than MSBuild ships ({assemblyVersion})."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I agree with this reasoning--why not point explicitly to one of the locations? But since it's fiddly to get the line number you can leave it if you prefer.
Co-authored-by: Rainer Sigwald <[email protected]>
Co-authored-by: Rainer Sigwald <[email protected]>
Co-authored-by: Rainer Sigwald <[email protected]>
…ithub.com/Forgind/msbuild into validate-packages-match-binding-redirects
This reverts commit cbb140d.
This reverts commit b75a202.
[Required] | ||
public string AssemblyPath { get; set; } | ||
|
||
// Microsoft.Build.Conversion.Core and Microsoft.Build.Engine are deprecated. We don't ship them, but they're still used in VS for now. We should ensure they're the right version if present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Microsoft.Build.Conversion.Core and Microsoft.Build.Engine are deprecated. We don't ship them, but they're still used in VS for now. We should ensure they're the right version if present. | |
// Microsoft.Build.Conversion.Core and Microsoft.Build.Engine are deprecated. We don't ship them, but they're still used in VS for now. We should ensure they're the right version if present. |
Wait, sorry, I didn't notice this before. We do ship these assemblies. Why does this say we don't? Are they maybe not present in this project's output because they're not direct projectreferences?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. Don't know what I was thinking here.
Fixes #7078
Context
If our binding redirects are off from the packages we actually ship, that can cause problems downstream when we try to integrate with anything other than MSBuild.
Changes Made
Added a post-build (and tests) validation step.
Testing
Built
Notes
How do I convert from a 3-part version to a 4-part version or vice versa? I imagine 3 -> 4 is easier if I can find the relevant assembly, but that would mean looking in our artifacts folder for something that matches its name and seeing if its version matches?Worked around by looking for shipped assemblies with versions not matching our binding redirects.
I was timeboxing this with little bash experience. Sorry it's a mess. Please help fix 🙂Has been fixed.