-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
WPF projects that use a versioned custom SDK fail to build #5426
WPF projects that use a versioned custom SDK fail to build #5426
Conversation
@ryalanms is there a way to get this in 6.0? |
Thank you, @ThomasGoulet73. @clairernovotny: Yes, either the first servicing release or GA. |
This is a showstopper for us for shipping on top of .NET6. I would really appreciate getting this for GA |
@SamBent: Can you take a look at this? Unit tests looks good, all the WPF samples are building, and the original regression (custom versioned SDK that requires source generators) is now building correctly. @vishalmsft: Nothing in the internal test automation covers this scenario (or the markup compiler, in general). Additional unit tests had to be written. |
// <Project Sdk="Microsoft.NET.Sdk"> | ||
// <Project Sdk="Microsoft.NET.Sdk"> | ||
// <Project Sdk="My.Custom.Sdk/1.0.0" /> | ||
// <Project Sdk="My.Custom.Sdk/min=1.0.0" /> |
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.
@ryalanms Is this something new in MSBuild or specific to WPF ? I cannot find anything about this in the doc and it does not seem to work using .Net SDK 6.0.100-rc.2.21505.57.
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.
Yes, I don't think this is documented anywhere other than the API reference for msbuild.
WPF needs to match msbuild's behavior when parsing the Project Sdk attributes, so the generated .csproj for the temp project build succeeds and fails the same way a non-WPF project does.
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 didn't know about this API. Should we call SdkReference.TryParse
directly instead of reproducing the parse here ? It's a public API and it does not require another dependency.
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 tried using SdkReference.TryParse
locally and it seems to be working. For now, I have it as a local commit. Let me know it you want me to push it, it's also a lot cleaner.
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.
Yes, please push. Thanks. I will run through the tests again locally.
If returning early due to a parsing failure, make sure to not remove the element (edit: Sdk attribute, not element).
static private void ReplaceImplicitImports(XmlDocument xmlProjectDoc)
{
if (xmlProjectDoc == null)
{
// When the parameters are not valid, simply return it, instead of throwing exceptions.
return;
}
XmlNode root = xmlProjectDoc.DocumentElement;
for (int i = 0; i < root.Attributes.Count; i++)
{
XmlAttribute xmlAttribute = root.Attributes[i] as XmlAttribute;
if (xmlAttribute.Name.Equals("Sdk", StringComparison.OrdinalIgnoreCase))
{
// <Project Sdk="Microsoft.NET.Sdk">
// <Project Sdk="My.Custom.Sdk/1.0.0" />
// <Project Sdk="My.Custom.Sdk/min=1.0.0" />
var sdkValue = xmlAttribute.Value;
SdkReference sdkReference;
SdkReference.TryParse(sdkValue, out sdkReference);
if (sdkReference == null) return;
// Remove Sdk attribute
root.Attributes.Remove(xmlAttribute);
//
// Add explicit top import
//
// <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
//
XmlNode nodeImportProps = CreateImportProjectSdkNode(xmlProjectDoc, "Sdk.props", sdkReference);
// Prepend this Import to the root of the XML document
root.PrependChild(nodeImportProps);
//
// Add explicit bottom import
//
// <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk"
//
XmlNode nodeImportTargets = CreateImportProjectSdkNode(xmlProjectDoc, "Sdk.targets", sdkReference);
// Append this Import to the end of the XML document
root.AppendChild(nodeImportTargets);
}
}
}
// Creates an XmlNode that contains an Import Project element
//
// <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
static XmlNode CreateImportProjectSdkNode(XmlDocument xmlProjectDoc, string projectAttributeValue, SdkReference sdkReference)
{
XmlNode nodeImport = xmlProjectDoc.CreateElement("Import", xmlProjectDoc.DocumentElement.NamespaceURI);
XmlAttribute projectAttribute = xmlProjectDoc.CreateAttribute("Project");
projectAttribute.Value = projectAttributeValue;
XmlAttribute sdkAttributeProps = xmlProjectDoc.CreateAttribute("Sdk");
sdkAttributeProps.Value = sdkReference.Name;
nodeImport.Attributes.Append(projectAttribute);
nodeImport.Attributes.Append(sdkAttributeProps);
if (!string.IsNullOrEmpty(sdkReference.Version))
{
XmlAttribute sdkVersionAttributeProps = xmlProjectDoc.CreateAttribute("Version");
sdkVersionAttributeProps.Value = sdkReference.Version;
nodeImport.Attributes.Append(sdkVersionAttributeProps);
}
if (!string.IsNullOrEmpty(sdkReference.MinimumVersion))
{
XmlAttribute sdkVersionAttributeProps = xmlProjectDoc.CreateAttribute("MinimumVersion");
sdkVersionAttributeProps.Value = sdkReference.MinimumVersion;
nodeImport.Attributes.Append(sdkVersionAttributeProps);
}
return nodeImport;
}
}
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.
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.
LGTM, especially using MSBuild's parser instead of rolling our own.
All unit tests passed with the most recent revision. I'll submit this for approval if the WPF samples and AppCompat applications build without any issues. |
@ThomasGoulet73: If this is approved, it will need to be retargeted to release/6.0. |
@ryalanms Would you prefer that I open a separate PR for release/6.0 and keep this one targeted to main ? I'm not familiar with the way you merge PR in previous release but in dotnet/runtime, they seem to merge PRs in main and then backport them to an older release. But I don't mind retargeting to release/6.0 once/if approved and letting you handle porting to main. |
This was approved by .NET Tactics in email. @ThomasGoulet73: I'll open another PR for 6.0. This one can be merged. |
Thank you @ryalanms ! |
* Fix build when using and SDK that comes from a PackageReference * Update custom Sdk attribute version parsing to match msbuild * Use SdkReference.TryParse Co-authored-by: Ryland <41491307+ryalanms@users.noreply.github.com>
…ild (#5536) * Port changes from #5426 to release/6.0 * WPF projects that use a versioned custom SDK fail to build (#5426) * Fix build when using and SDK that comes from a PackageReference * Update custom Sdk attribute version parsing to match msbuild * Use SdkReference.TryParse Authored-by: ThomasGoulet73 <51839772+ThomasGoulet73@users.noreply.github.com>
Thank you @ThomasGoulet73 for the investigation and fix. |
@ryalanms I'm glad to see this merged, and thank you for the help! |
Fixes #5239
Description:
WPF projects that use a versioned custom SDK fail to build:
<Project Sdk="My.Custom.Sdk/1.2.3" />
. Parse and add an explicit Version attribute when creating the temporary WPF .csproj.Customer Impact:
Any customer that requires a WPF project with a versioned custom SDK with SourceGenerator/PackageReference support will be blocked until this is fixed.
Regression:
Yes, partially. Using a custom SDK with a version works in 5.0 and 6.0 with PackageReference support turned off.
Testing:
Added/ran new unit tests and confirmed custom SDKs work with fix. Verified WPF Samples build against markup compiler containing change. Performed additional manual validation.
Risk:
Low. The Sdk attribute parsing uses the same public method from Microsoft.Build.Framework used by msbuild.