-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Validate binding redirects #7153
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
Changes from 14 commits
1eb3176
ef86539
11d1b98
ac03457
288ecc9
08bd7b5
39731bc
29e7068
45d54d4
d0b8b5b
a389c1a
747aa87
354316d
5f77395
f2c30e5
60274a2
c5583f7
1e4a18e
b75a202
cbb140d
70555c7
42a582f
1ecec1c
abf550f
9099712
0be049f
fe5159a
a4f3b4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||||||
| using Microsoft.Build.Framework; | ||||||||||||||||||
| using Microsoft.Build.Utilities; | ||||||||||||||||||
| using System; | ||||||||||||||||||
| using System.IO; | ||||||||||||||||||
| using System.Reflection; | ||||||||||||||||||
| using System.Xml; | ||||||||||||||||||
| namespace MSBuild | ||||||||||||||||||
| { | ||||||||||||||||||
| public class ValidateMSBuildPackageDependencyVersions : Task | ||||||||||||||||||
| { | ||||||||||||||||||
| [Required] | ||||||||||||||||||
| public string AppConfig { get; set; } | ||||||||||||||||||
| [Required] | ||||||||||||||||||
| public string AssemblyPath { get; set; } | ||||||||||||||||||
|
|
||||||||||||||||||
| public override bool Execute() | ||||||||||||||||||
| { | ||||||||||||||||||
| XmlDocument doc = new XmlDocument(); | ||||||||||||||||||
| doc.Load(AppConfig); | ||||||||||||||||||
| foreach (var topLevelElement in doc.ChildNodes) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (topLevelElement is XmlElement topLevelXmlElement && topLevelXmlElement.Name.Equals("configuration", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| foreach (var configurationElement in topLevelXmlElement.ChildNodes) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (configurationElement is XmlElement configurationXmlElement && configurationXmlElement.Name.Equals("runtime", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| foreach (var runtimeElement in configurationXmlElement.ChildNodes) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (runtimeElement is XmlElement runtimeXmlElement && runtimeXmlElement.Name.Equals("assemblyBinding", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| foreach (var assemblyBindingElement in runtimeXmlElement.ChildNodes) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (assemblyBindingElement is XmlElement assemblyBindingXmlElement && assemblyBindingXmlElement.Name.Equals("dependentAssembly", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| string name = string.Empty; | ||||||||||||||||||
| string version = string.Empty; | ||||||||||||||||||
| foreach (var dependentAssembly in assemblyBindingXmlElement.ChildNodes) | ||||||||||||||||||
| { | ||||||||||||||||||
rainersigwald marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
| if (dependentAssembly is XmlElement dependentAssemblyXmlElement) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (dependentAssemblyXmlElement.Name.Equals("assemblyIdentity", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| foreach (var assemblyIdentityAttribute in dependentAssemblyXmlElement.Attributes) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (assemblyIdentityAttribute is XmlAttribute assemblyIdentityAttributeXmlElement && assemblyIdentityAttributeXmlElement.Name.Equals("name", StringComparison.OrdinalIgnoreCase)) | ||||||||||||||||||
| { | ||||||||||||||||||
| name = assemblyIdentityAttributeXmlElement.Value; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
||||||||||||||||||
| foreach (var assemblyIdentityAttribute in dependentAssemblyXmlElement.Attributes) | |
| { | |
| if (assemblyIdentityAttribute is XmlAttribute assemblyIdentityAttributeXmlElement && assemblyIdentityAttributeXmlElement.Name.Equals("name", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| name = assemblyIdentityAttributeXmlElement.Value; | |
| } | |
| } | |
| name = dependentAssemblyXmlElement.GetAttribute("name"); |
Outdated
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.)
rainersigwald marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
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.
Only run this target on .NET Framework builds (since that's the only case where the binding redirects apply).