-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Generate appconfig for full framework project #2447
Conversation
} | ||
|
||
// intersection of https://docs.microsoft.com/en-us/nuget/reference/target-frameworks | ||
// and https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/startup/supportedruntime-element#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.
Use this map is good enough? Also, net30
is not a tfm in dotnet core. So, this is not a valid tfm
[InlineData("net30")] | ||
[InlineData("net999")] | ||
[InlineData("netstandard20")] | ||
public void It_does_not_generate_version_and_sku_for_non_supported(string targetframework) |
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.
If it is not a valid TFM, no supportedRuntime
is generated
</ItemGroup> | ||
|
||
<!--Override the AppConfigWithTargetPath for downstream target--> | ||
<ItemGroup> |
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.
This override I am not sure. PrepareForBuild
will find and put AppConfigWithTargetPath
. And GenerateBindingRedirects
will read AppConfigWithTargetPath, and add binding redirect on top of it.
And this task will point AppConfigWithTargetPath to its intermediate result. So GenerateBindingRedirects will use the generated file.
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 have time to review the whole thing, but I did leave some feedback.
|
||
namespace Microsoft.NET.Build.Tasks.UnitTests | ||
{ | ||
public class GivenAGenerateAppConfig |
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.
Rename this class/file to GivenAGeneratedAppConfig
(it's missing a "d").
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.
Ah, forget to run through a round of spell checker
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.
fixed
public class GivenAGenerateAppConfig | ||
{ | ||
[Fact] | ||
public void It_creates_startup_and_supportedRuntime_nod_when_there_is_not_any() |
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.
Typo in method name: nod
-> node
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.
fixed
public ITaskItem AppConfigFile { get; set; } | ||
|
||
[Required] | ||
public string TargetFramework { get; set; } |
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.
This task should be based on the TargetFrameworkIdentifier
and TargetFrameworkVersion
properties (which are by default inferred from TargetFramework
) instead of directly depending on TargetFramework
.
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.
used TargetFrameworkIdentifier and TargetFrameworkVersion instead
{ | ||
if (targetFrameworkParsed.Version.Major < 4) | ||
{ | ||
if (_targetFrameworkBelow40RuntimeVersionMap.TryGetValue(targetFrameworkParsed.GetShortFolderName(), out string 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.
Instead of using a map here, I would just use if statements, which check the range of values. IE any version >= 2.0 but < 4.0 should use v2.0.50727 in the app.config.
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.
Fixed, check between version range
|
||
[Required] | ||
public string TargetFrameworkVersion { get; set; } | ||
|
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.
For completeness, this should have optional TargetFrameworkProfile as well.
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.
fixed, added TargetFrameworkProfile
new XElement( | ||
"supportedRuntime", | ||
new XAttribute("version", "v4.0"), | ||
new XAttribute("sku", $"{targetFrameworkIdentifier},Version={targetFrameworkVersion}")); |
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.
For completeness, sku should include Profile (if any) as well in TFM. We don't support net40-client directly with our target framework inference, but I believe some folks do it explicitly or use community "extras" package to do 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.
an example? And is there a easy way to test it to make sure profile and tfm is in correct "format"? I am afraid of adding more property and it ends up cannot be read by runtime. Today, I avoid this issue by matching exactly to the following doc.
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 find it, it is also a doc
So it will just do Profile="${TargetFrameworkProfile}"
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 will need to make profile optional and only use it if set.
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.
Fixed, it is optional. Only add it when it is set
supportedRuntime = null; | ||
|
||
if (targetFrameworkIdentifier == ".NETFramework" | ||
&& NuGetVersion.TryParse(targetFrameworkVersion.TrimStart('v', 'V'), out NuGetVersion parsedVersion)) |
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.
TargetFrameworkVersion should parse as System.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.
Fixed, used System.Version.Parse
if (File.Exists(OutputAppConfigFile.ItemSpec)) | ||
{ | ||
File.Delete(OutputAppConfigFile.ItemSpec); | ||
} |
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.
This doesn't seem necessary: FileMode.Create below will truncate the existing file.
Create | Specifies that the operating system should create a new file. If the file already exists, it will be overwritten. This requires FileIOPermissionAccess.Write permission. FileMode.Create is equivalent to requesting that if the file does not exist, use CreateNew; otherwise, use Truncate. If the file already exists but is a hidden file, an UnauthorizedAccessException exception is thrown. |
---|
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.
Fixed, removed File.Exists File.Delete
FileMode.Create, | ||
FileAccess.Write, | ||
FileShare.Read); | ||
using (var stream = new StreamWriter(fileStream)) |
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.
nit: newline here.
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.
fixed
<Target Name="GenerateAppConfig" | ||
Condition="'$(GenerateAppConfig)' != 'false' and '$(TargetFrameworkIdentifier)' == '.NETFramework' and '$(HasRuntimeOutput)' == 'true'" | ||
DependsOnTargets="_WriteAppConfig" | ||
BeforeTargets="GenerateBindingRedirects"> |
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.
This means that if I set GenerateBindingRedirects to false, but GenerateAppConfig to true, that it won't work? I think in practice all SDK projects should generate binding redirects, but it feels a little clunky to tie them together.
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.
Fixed, beforetargets ResolveReferences
.
<_GenerateAppConfigIntermediateAppConfig>$(IntermediateOutputPath)$(TargetFileName).withSupportedRuntime.config</_GenerateAppConfigIntermediateAppConfig> | ||
</PropertyGroup> | ||
|
||
<Target Name="GenerateAppConfig" |
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'm wondering if GenerateAppConfig is a good name. Probably better to say what in app config we're generating to match GenerateBindingRedirects. GenerateSupportedRuntime, perhaps? It is a common case for netfx apps to already have an app.config for other reasons so we aren't always generating one from scratch, but that's what the name reads like to me.
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.
Fixed, renamed target to GenerateSupportedRuntime and the task is called WriteAppConfigWithSupportedRuntime (since it will create one)
7f3d8aa
to
c3719c1
Compare
<Target Name="GenerateSupportedRuntime" | ||
Condition="'$(GenerateSupportedRuntime)' != 'false' and '$(TargetFrameworkIdentifier)' == '.NETFramework' and '$(HasRuntimeOutput)' == 'true'" | ||
DependsOnTargets="_WriteAppConfigWithSupportedRuntime" | ||
BeforeTargets="GenerateBindingRedirects"> |
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.
@rainersigwald this is the issue I asked. We are worried about if this target can still run when GenerateBindingRedirects is disable.
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.
Before a target is executed or skipped, any target that lists it in a BeforeTargets attribute is run.
@nguerrera plus I tested out disable AutoGenerateBindingRedirects=false . it is fine to use BeforeTargets="GenerateBindingRedirects"
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.
Ah, ok, I always get confused by that.
@nguerrera all comments are addressed |
Fix #2319