Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ internal override Parameter ToParameter()
/// <summary>
/// Gets the normalized CLI option name.
/// </summary>
private string FixedName => CliOption ?? $"--{DisplayName.ToLowerInvariant().Replace(" ", "-")}";
private string FixedName => Parameter.GetParameterName(CliOption, DisplayName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,18 @@ public static CliTypes GetCliType(Type type)
/// <returns>The corresponding CLI type.</returns>
public static CliTypes GetCliType<T>()
=> GetCliType(typeof(T));


/// <summary>
/// Generates the command-line parameter name based on the specified option or display name.
/// </summary>
/// <param name="cliOption">The explicit command-line option name to use. If not specified, the parameter name is generated from <paramref
/// name="displayName"/>.</param>
/// <param name="displayName">The display name used to generate the command-line parameter name if <paramref name="cliOption"/> is null.</param>
/// <returns>A string containing the command-line parameter name. If <paramref name="cliOption"/> is not null, its value is
/// returned; otherwise, a name is generated from <paramref name="displayName"/>.</returns>
internal static string GetParameterName(string? cliOption, string displayName)
{
return cliOption ?? $"--{displayName.ToLowerInvariant().Replace(" ", "-")}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,4 @@ private static bool CanConvertToType(string value, Type type)
return false;
}
}

public static bool IsTargetFrameworkOption(Parameter parameter)
{
return string.Equals(parameter.DisplayName, Model.TargetFrameworkConstants.TargetFrameworkDisplayName, StringComparison.Ordinal);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Extensions.Logging;
using NuGet.Versioning;

namespace Microsoft.DotNet.Scaffolding.Core.Model;
Expand Down Expand Up @@ -28,15 +29,16 @@ internal static class PackageExtensions
/// <param name="package">The package instance for which to resolve the version. Must not be null.</param>
/// <param name="targetFramework">The target framework identifier used to determine the appropriate package version. For example, "net6.0".</param>
/// <param name="nugetVersionHelper">The NuGet version helper to use for version resolution.</param>
/// <param name="logger">The logger to use for logging messages.</param>
/// <returns>A package instance with the version property set to the resolved version for the specified target framework, or
/// the original package if the version is already set or cannot be resolved.</returns>
public static async Task<Package> WithResolvedVersionAsync(this Package package, string targetFramework, NuGetVersionService nugetVersionHelper)
public static async Task<Package> WithResolvedVersionAsync(this Package package, string targetFramework, NuGetVersionService nugetVersionHelper, ILogger? logger = null)
{
if (package.PackageVersion is not null)
{
return package;
}
NuGetVersion? resolvedVersion = await package.GetVersionForTargetFrameworkAsync(targetFramework, nugetVersionHelper);
NuGetVersion? resolvedVersion = await package.GetVersionForTargetFrameworkAsync(targetFramework, nugetVersionHelper, logger);
if (resolvedVersion is null)
{
return package;
Expand All @@ -54,11 +56,10 @@ public static async Task<Package> WithResolvedVersionAsync(this Package package,
/// <param name="targetFramework">The target framework identifier (for example, "net8.0", "net9.0", or "net10.0") for which the package version is
/// requested. Case-insensitive.</param>
/// <param name="nugetVersionHelper">The NuGet version helper to use for version resolution.</param>
/// <param name="logger">The logger to use for logging messages.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the corresponding NuGet package
/// version if available; otherwise, <see langword="null"/> if the package does not require a version.</returns>
/// <exception cref="NotSupportedException">Thrown if <paramref name="targetFramework"/> is not one of the supported frameworks ("net8.0", "net9.0", or
/// "net10.0").</exception>
private static Task<NuGetVersion?> GetVersionForTargetFrameworkAsync(this Package package, string targetFramework, NuGetVersionService nugetVersionHelper)
/// version if available; otherwise, <see langword="null"/> if the package does not require a version or target framework is not supported.</returns>
private static Task<NuGetVersion?> GetVersionForTargetFrameworkAsync(this Package package, string targetFramework, NuGetVersionService nugetVersionHelper, ILogger? logger = null)
{
if (!package.IsVersionRequired)
{
Expand All @@ -79,7 +80,8 @@ public static async Task<Package> WithResolvedVersionAsync(this Package package,
}
else
{
throw new NotSupportedException($"Target framework '{targetFramework}' is not supported.");
logger?.LogError("Target framework '{TargetFramework}' is not supported. Installing recent release of '{PackageName}'. Consider upgrading your target framework to install a compatible package version.", targetFramework, package.Name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies if I've asked this before, but does this need to be localized?

What does "Installing recent release of ..." mean in this context? I'm not 100% clear on this error message.

return Task.FromResult<NuGetVersion?>(null);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;

namespace Microsoft.DotNet.Scaffolding.Core.Model;

internal static class TargetFrameworkConstants
{
public const string TargetFrameworkCliOption = "--framework";
public const string TargetFrameworkDisplayName = "Target Framework";
public const string TargetFrameworkDescription = "Specifies the target framework for the scaffolded project.";
public const string TargetFrameworkPropertyName = "TargetFramework";

public const string Net8 = "net8.0";
public const string Net9 = "net9.0";
public const string Net10 = "net10.0";

public static readonly ImmutableArray<string> SupportedTargetFrameworks = [ Net8, Net9, Net10];
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ public static class ScaffolderContextExtensions
/// <returns>The target framework name if present; otherwise, null.</returns>
public static string? GetSpecifiedTargetFramework(this ScaffolderContext context)
{
if (context.GetOptionResult<string>(Model.TargetFrameworkConstants.TargetFrameworkCliOption) is string tfm)
string? targetFramework = null;
if (context.Properties.TryGetValue(TargetFrameworkConstants.TargetFrameworkPropertyName, out object? tfm))
{
return tfm;
targetFramework = tfm as string;
}

return null;
return targetFramework;
}

public static string? SetSpecifiedTargetFramework(this ScaffolderContext context, string? targetFramework)
{
context.Properties[TargetFrameworkConstants.TargetFrameworkPropertyName] = targetFramework;
return targetFramework;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public override async Task<bool> ExecuteAsync(ScaffolderContext context, Cancell
Package resolvedPackage = package;
if (package.IsVersionRequired && !string.IsNullOrEmpty(targetFramework) && !Prerelease)
{
resolvedPackage = await package.WithResolvedVersionAsync(targetFramework, _nugetVersionHelper);
resolvedPackage = await package.WithResolvedVersionAsync(targetFramework, _nugetVersionHelper, _logger);
packageVersion = resolvedPackage.PackageVersion;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps;
using Microsoft.DotNet.Tools.Scaffold.AspNet.ScaffoldSteps.Settings;
using Microsoft.DotNet.Tools.Scaffold.Command;
using Microsoft.DotNet.Tools.Scaffold.ScaffoldingSteps;

namespace Microsoft.DotNet.Tools.Scaffold.AspNet
{
Expand Down Expand Up @@ -40,7 +39,6 @@ public Type[] GetScaffoldSteps()
typeof(ValidateIdentityStep),
typeof(ValidateMinimalApiStep),
typeof(ValidateRazorPagesStep),
typeof(ValidateTargetFrameworkStep),
typeof(ValidateViewsStep),
typeof(WrappedAddPackagesStep),
typeof(WrappedCodeModificationStep),
Expand Down Expand Up @@ -132,13 +130,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.Api.ApiControllerCrudDisplayName)
.WithCategory(AspnetStrings.Catagories.API)
.WithDescription(AspnetStrings.Api.ApiControllerCrudDescription)
.WithOptions([options.Project, options.ModelName, options.ControllerName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.ModelName, options.ControllerName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.Prerelease])
.WithStep<ValidateEfControllerStep>(config =>
{
var step = config.Step;
Expand All @@ -161,13 +153,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.MVC.CrudDisplayName)
.WithCategory(AspnetStrings.Catagories.MVC)
.WithDescription(AspnetStrings.MVC.CrudDescription)
.WithOptions([options.Project, options.ModelName, options.ControllerName, options.Views, options.DataContextClassRequired, options.DatabaseProviderRequired, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.ModelName, options.ControllerName, options.Views, options.DataContextClassRequired, options.DatabaseProviderRequired, options.Prerelease])
.WithStep<ValidateEfControllerStep>(config =>
{
var step = config.Step;
Expand All @@ -191,13 +177,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.Blazor.CrudDisplayName)
.WithCategory(AspnetStrings.Catagories.Blazor)
.WithDescription(AspnetStrings.Blazor.CrudDescription)
.WithOptions([options.Project, options.ModelName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.PageType, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.ModelName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.PageType, options.Prerelease])
.WithStep<ValidateBlazorCrudStep>(config =>
{
var step = config.Step;
Expand All @@ -219,13 +199,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.RazorPage.CrudDisplayName)
.WithCategory(AspnetStrings.Catagories.RazorPages)
.WithDescription(AspnetStrings.RazorPage.CrudDescription)
.WithOptions([options.Project, options.ModelName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.PageType, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.ModelName, options.DataContextClassRequired, options.DatabaseProviderRequired, options.PageType, options.Prerelease])
.WithStep<ValidateRazorPagesStep>(config =>
{
var step = config.Step;
Expand Down Expand Up @@ -263,13 +237,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.Api.MinimalApiDisplayName)
.WithCategory(AspnetStrings.Catagories.API)
.WithDescription(AspnetStrings.Api.MinimalApiDescription)
.WithOptions([options.Project, options.ModelName, options.EndpointsClass, options.OpenApi, options.DataContextClass, options.DatabaseProvider, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.ModelName, options.EndpointsClass, options.OpenApi, options.DataContextClass, options.DatabaseProvider, options.Prerelease])
.WithStep<ValidateMinimalApiStep>(config =>
{
var step = config.Step;
Expand Down Expand Up @@ -306,13 +274,7 @@ public void AddScaffolderCommands()
.WithCategory(AspnetStrings.Catagories.Blazor)
.WithCategory(AspnetStrings.Catagories.Identity)
.WithDescription(AspnetStrings.Blazor.IdentityDescription)
.WithOptions([options.Project, options.DataContextClassRequired, options.IdentityDbProviderRequired, options.Overwrite, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.DataContextClassRequired, options.IdentityDbProviderRequired, options.Overwrite, options.Prerelease])
.WithStep<ValidateIdentityStep>(config =>
{
var step = config.Step;
Expand All @@ -335,13 +297,7 @@ public void AddScaffolderCommands()
.WithDisplayName(AspnetStrings.Identity.DisplayName)
.WithCategory(AspnetStrings.Catagories.Identity)
.WithDescription(AspnetStrings.Identity.Description)
.WithOptions([options.Project, options.DataContextClassRequired, options.IdentityDbProviderRequired, options.Overwrite, options.TargetFramework, options.Prerelease])
.WithStep<ValidateTargetFrameworkStep>(config =>
{
var step = config.Step;
var context = config.Context;
step.TargetFramework = context.GetOptionResult(options.TargetFramework);
})
.WithOptions([options.Project, options.DataContextClassRequired, options.IdentityDbProviderRequired, options.Overwrite, options.Prerelease])
.WithStep<ValidateIdentityStep>(config =>
{
var step = config.Step;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ internal class AspNetOptions
public ScaffolderOption<bool> Views { get; }
public ScaffolderOption<bool> Overwrite { get; }
public ScaffolderOption<string> Application { get; }
public ScaffolderOption<string> TargetFramework { get; }

private ScaffolderOption<string>? _username = null;
private ScaffolderOption<string>? _tenantId = null;
Expand Down Expand Up @@ -193,16 +192,6 @@ public AspNetOptions()
PickerType = InteractivePickerType.ConditionalPicker,
CustomPickerValues = AspnetStrings.Options.Application.Values
};

TargetFramework = new ScaffolderOption<string>
{
DisplayName = Scaffolding.Core.Model.TargetFrameworkConstants.TargetFrameworkDisplayName,
CliOption = Scaffolding.Core.Model.TargetFrameworkConstants.TargetFrameworkCliOption,
Description = Scaffolding.Core.Model.TargetFrameworkConstants.TargetFrameworkDescription,
Required = false,
PickerType = InteractivePickerType.CustomPicker,
CustomPickerValues = Scaffolding.Core.Model.TargetFrameworkConstants.SupportedTargetFrameworks
};
}

public ScaffolderOption<string> Username => _username ??= new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,12 @@ internal static ProjectInfo GetProjectInfo(string projectPath, ILogger logger)
* unlike ICodeService, also no chance for a wasted op because at this point in the scaffolder,
* we will definitely to have MSBuild initialized.*/
new MsBuildInitializer(logger).Initialize();
var codeService = new CodeService(logger, projectPath);
var msBuildProject = new MSBuildProjectService(projectPath);
var lowestTFM = msBuildProject.GetLowestTargetFramework();
var capabilities = msBuildProject.GetProjectCapabilities().ToList();
var projectInfo = new ProjectInfo()
CodeService codeService = new(logger, projectPath);
MSBuildProjectService msBuildProject = new(projectPath);
List<string> capabilities = msBuildProject.GetProjectCapabilities().ToList();
ProjectInfo projectInfo = new(projectPath)
{
CodeService = codeService,
ProjectPath = projectPath,
LowestTargetFramework = lowestTFM,
Capabilities = capabilities
};

Expand Down
Loading