Skip to content

Commit

Permalink
minimal api templates update (#2269) (#2271)
Browse files Browse the repository at this point in the history
* init, not working yet

* all changes added, works well

* nit, removed unused statement.
  • Loading branch information
deepchoudhery committed Feb 13, 2023
1 parent fa0f9e9 commit a186d89
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 63 deletions.
2 changes: 1 addition & 1 deletion scripts/install-aspnet-codegenerator.cmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set VERSION=8.0.0-dev
set VERSION=7.0.4
set DEFAULT_NUPKG_PATH=%userprofile%\.nuget\packages
set SRC_DIR=%cd%
set NUPKG=artifacts/packages/Debug/Shipping/
Expand Down
2 changes: 1 addition & 1 deletion scripts/install-aspnet-codegenerator.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

VERSION=8.0.0-dev
VERSION=7.0.4
DEFAULT_NUPKG_PATH=~/.nuget/packages
SRC_DIR=$(pwd)
echo $SRC_DIR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,14 +744,9 @@ private void ValidateRequiredDependencies()
var dependencies = new HashSet<string>()
{
"Microsoft.AspNetCore.Identity.UI",
"Microsoft.EntityFrameworkCore.Design"
EfConstants.EfToolsPackageName
};

const string EfDesignPackageName = "Microsoft.EntityFrameworkCore.Design";
var isEFDesignPackagePresent = _projectContext
.PackageDependencies
.Any(package => package.Name.Equals(EfDesignPackageName, StringComparison.OrdinalIgnoreCase));

var missingPackages = dependencies.Where(d => !_projectContext.PackageDependencies.Any(p => p.Name.Equals(d, StringComparison.OrdinalIgnoreCase)));
if (CalledFromCommandline && missingPackages.Any())
{
Expand Down
20 changes: 10 additions & 10 deletions src/Scaffolding/VS.Web.CG.Mvc/Minimal Api/MinimalApiGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class MinimalApiGenerator : ICodeGenerator
private IModelTypesLocator ModelTypesLocator { get; set; }
private IFileSystem FileSystem { get; set; }
private IProjectContext ProjectContext { get; set; }
private IEntityFrameworkService EntityFrameworkService { get; set;}
private IEntityFrameworkService EntityFrameworkService { get; set; }
private ICodeGeneratorActionsService CodeGeneratorActionsService { get; set; }
private Workspace Workspace { get; set; }
private ConsoleLogger ConsoleLogger { get; set; }
Expand Down Expand Up @@ -74,7 +74,7 @@ public async Task GenerateCode(MinimalApiGeneratorCommandLineModel model)
EntityFrameworkService,
ModelTypesLocator,
Logger,
areaName : string.Empty);
areaName: string.Empty);

if (!string.IsNullOrEmpty(modelTypeAndContextModel.DbContextFullName) && CalledFromCommandline)
{
Expand All @@ -85,7 +85,7 @@ public async Task GenerateCode(MinimalApiGeneratorCommandLineModel model)
{
ValidateOpenApiDependencies(ProjectContext.PackageDependencies);
}

var templateModel = new MinimalApiModel(modelTypeAndContextModel.ModelType, modelTypeAndContextModel.DbContextFullName, model.EndpintsClassName)
{
EndpointsName = model.EndpintsClassName,
Expand Down Expand Up @@ -116,7 +116,7 @@ public async Task GenerateCode(MinimalApiGeneratorCommandLineModel model)
}
}
//execute CodeGeneratorActionsService.AddFileFromTemplateAsync to add endpoints file.
else
else
{
//Add endpoints file with endpoints class since it does not exist.
ValidateModel(model);
Expand Down Expand Up @@ -178,7 +178,7 @@ internal async Task AddEndpointsMethod(string membersBlockText, string endpoints
{
usings.Add("Microsoft.AspNetCore.Http.HttpResults");
}
var endpointsCodeFile = new CodeFile { Usings = usings.ToArray()};
var endpointsCodeFile = new CodeFile { Usings = usings.ToArray() };
var docBuilder = new DocumentBuilder(docEditor, endpointsCodeFile, ConsoleLogger);
var newRoot = docBuilder.AddUsings(new CodeChangeOptions());
var classNode = newRoot.DescendantNodes().FirstOrDefault(node => node is ClassDeclarationSyntax classDeclarationSyntax && classDeclarationSyntax.Identifier.ValueText.Contains(className));
Expand All @@ -196,7 +196,7 @@ internal async Task AddEndpointsMethod(string membersBlockText, string endpoints
classDeclaration = SyntaxFactory.ClassDeclaration($"{templateModel.ModelType.Name}Endpoints")
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
.NormalizeWhitespace()
.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed);
.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed);
}
var modifiedClass = classDeclaration.AddMembers(
SyntaxFactory.GlobalStatement(SyntaxFactory.ParseStatement(membersBlockText)).WithLeadingTrivia(SyntaxFactory.Tab));
Expand All @@ -212,7 +212,7 @@ internal async Task AddEndpointsMethod(string membersBlockText, string endpoints
{
newRoot = newRoot.ReplaceNode(classNode, modifiedClass);
}

docEditor.ReplaceNode(docRoot, newRoot);
var classFileSourceTxt = await docEditor.GetChangedDocument()?.GetTextAsync();
var classFileTxt = classFileSourceTxt?.ToString();
Expand Down Expand Up @@ -323,7 +323,7 @@ internal async Task ModifyProgramCs(MinimalApiModel templateModel)
newRoot = newRoot?.ReplaceNode(mainMethod.Body, updatedMethod);
}
}

if (templateModel.OpenAPI)
{
var builderVariable = ProjectModifierHelper.GetBuilderVariableIdentifierTransformation(newRoot.Members);
Expand All @@ -336,7 +336,7 @@ internal async Task ModifyProgramCs(MinimalApiModel templateModel)
{
filteredChanges = DocumentBuilder.AddLeadingTriviaSpaces(filteredChanges, spaces: 12);
var mainMethod = DocumentBuilder.GetMethodFromSyntaxRoot(newRoot, Main);
{
{
var updatedMethod = DocumentBuilder.ApplyChangesToMethod(mainMethod.Body, filteredChanges);
newRoot = newRoot?.ReplaceNode(mainMethod.Body, updatedMethod);
}
Expand Down Expand Up @@ -390,7 +390,7 @@ private void ValidateOpenApiDependencies(IEnumerable<DependencyDescription> pack
string.Format(MessageStrings.InstallPackagesForScaffoldingIdentity, string.Join(",", missingPackages)));
}
}

private string GetMinimalApiCodeModifierConfig()
{
string jsonText = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
string updateModel = $"Update{@modelName}";
string dbContextName = Model.ContextTypeName;
var entitySetName = Model.ModelMetadata.EntitySetName;
var entitySetNoTracking = $"{entitySetName}.AsNoTracking()";
var entityProperties = Model.ModelMetadata.Properties;
var primaryKeyName = Model.ModelMetadata.PrimaryKeys[0].PropertyName;
var primaryKeyNameLowerCase = primaryKeyName.ToLowerInvariant();
var primaryKeyShortTypeName = Model.ModelMetadata.PrimaryKeys[0].ShortTypeName;
Expand All @@ -23,9 +25,10 @@
var remove = $"{@entitySetName}.Remove({@Model.ModelVariable})";
string resultsExtension = Model.UseTypedResults ? "TypedResults" : "Results";
string typedTaskWithNotFound = Model.UseTypedResults ? $"Task<Results<Ok<{@modelName}>, NotFound>>" : "";
string typedTaskWithNoContent = Model.UseTypedResults ? $"Task<Results<NotFound, NoContent>>" : "";
string typedTaskOkNotFound = Model.UseTypedResults ? $"Task<Results<Ok, NotFound>>" : "";
string resultsNotFound = $"{resultsExtension}.NotFound()";
string resultsOkModel = $"{resultsExtension}.Ok(model)";
string resultsOkEmpty = $"{resultsExtension}.Ok()";
string resultsNoContent = $"{resultsExtension}.NoContent()";
string resultsOkModelVariable = $"{resultsExtension}.Ok({@Model.ModelVariable})";
string createdApiVar = string.Format("$\"{0}/{{{1}.{2}}}\",{3}", @routePrefix, @Model.ModelVariable, @primaryKeyName, @Model.ModelVariable);
Expand Down Expand Up @@ -76,7 +79,8 @@ public static class @endPointsClassName

group.MapGet("/{id}", async @typedTaskWithNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
{
return await db.@findModel
return await db.@entitySetNoTracking
.FirstOrDefaultAsync(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
is @modelName model
? @resultsOkModel
: @resultsNotFound;
Expand All @@ -95,19 +99,23 @@ public static class @endPointsClassName
@:@builderExtensions;
}

group.MapPut("/{id}", async @typedTaskWithNoContent (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @modelName @Model.ModelVariable, @dbContextName db) =>
group.MapPut("/{id}", async @typedTaskOkNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @modelName @Model.ModelVariable, @dbContextName db) =>
{
var foundModel = await db.@findModel;

if (foundModel is null)
{
return @resultsNotFound;
}

db.Update(@Model.ModelVariable);
await db.SaveChangesAsync();
var affected = await db.@entitySetName
.Where(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
.ExecuteUpdateAsync(setters => setters
@{
//should be atleast one property (primary key)
foreach(var modelProperty in entityProperties)
{
string modelPropertyName = modelProperty.PropertyName;
string setPropertyString = $".SetProperty(m => m.{modelPropertyName}, {Model.ModelVariable}.{modelPropertyName})";
@:@setPropertyString
}
}
);

return @resultsNoContent;
return affected == 1 ? @resultsOkEmpty : @resultsNotFound;
})
@{
builderExtensions = $".WithName(\"{@updateModel}\")";
Expand Down Expand Up @@ -143,16 +151,13 @@ public static class @endPointsClassName
@:@builderExtensions;
}

group.MapDelete("/{id}", async @typedTaskWithNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
group.MapDelete("/{id}", async @typedTaskOkNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
{
if (await db.@findModel is @modelName @Model.ModelVariable)
{
db.@remove;
await db.SaveChangesAsync();
return @resultsOkModelVariable;
}
var affected = await db.@entitySetName
.Where(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
.ExecuteDeleteAsync();

return @resultsNotFound;
return affected == 1 ? @resultsOkEmpty : @resultsNotFound;
})
@{
builderExtensions = $".WithName(\"{@deleteModel}\")";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
string modelName = Model.ModelType.Name;
string routePrefix = "/api/" + modelName;
string endPointsClassName = Model.EndpointsName;
string methodName = $"Map{@modelName}Endpoints";
string pluralModel = $"{@modelName}s";
string getAllModels = $"GetAll{@pluralModel}";
string getModelById = $"Get{@modelName}ById";
Expand All @@ -11,6 +12,8 @@
string updateModel = $"Update{@modelName}";
string dbContextName = Model.ContextTypeName;
var entitySetName = Model.ModelMetadata.EntitySetName;
var entitySetNoTracking = $"{entitySetName}.AsNoTracking()";
var entityProperties = Model.ModelMetadata.Properties;
var primaryKeyName = Model.ModelMetadata.PrimaryKeys[0].PropertyName;
var primaryKeyNameLowerCase = primaryKeyName.ToLowerInvariant();
var primaryKeyShortTypeName = Model.ModelMetadata.PrimaryKeys[0].ShortTypeName;
Expand All @@ -22,9 +25,10 @@
var remove = $"{@entitySetName}.Remove({@Model.ModelVariable})";
string resultsExtension = Model.UseTypedResults ? "TypedResults" : "Results";
string typedTaskWithNotFound = Model.UseTypedResults ? $"Task<Results<Ok<{@modelName}>, NotFound>>" : "";
string typedTaskWithNoContent = Model.UseTypedResults ? $"Task<Results<NotFound, NoContent>>" : "";
string typedTaskOkNotFound = Model.UseTypedResults ? $"Task<Results<Ok, NotFound>>" : "";
string resultsNotFound = $"{resultsExtension}.NotFound()";
string resultsOkModel = $"{resultsExtension}.Ok(model)";
string resultsOkEmpty = $"{resultsExtension}.Ok()";
string resultsNoContent = $"{resultsExtension}.NoContent()";
string resultsOkModelVariable = $"{resultsExtension}.Ok({@Model.ModelVariable})";
string createdApiVar = string.Format("$\"{0}/{{{1}.{2}}}\",{3}", @routePrefix, @Model.ModelVariable, @primaryKeyName, @Model.ModelVariable);
Expand Down Expand Up @@ -64,7 +68,8 @@

group.MapGet("/{id}", async @typedTaskWithNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
{
return await db.@findModel
return await db.@entitySetNoTracking
.FirstOrDefaultAsync(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
is @modelName model
? @resultsOkModel
: @resultsNotFound;
Expand All @@ -83,19 +88,23 @@
@:@builderExtensions;
}

group.MapPut("/{id}", async @typedTaskWithNoContent (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @modelName @Model.ModelVariable, @dbContextName db) =>
group.MapPut("/{id}", async @typedTaskOkNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @modelName @Model.ModelVariable, @dbContextName db) =>
{
var foundModel = await db.@findModel;

if (foundModel is null)
{
return @resultsNotFound;
}

db.Update(@Model.ModelVariable);
await db.SaveChangesAsync();
var affected = await db.@entitySetName
.Where(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
.ExecuteUpdateAsync(setters => setters
@{
//should be atleast one property (primary key)
foreach(var modelProperty in entityProperties)
{
string modelPropertyName = modelProperty.PropertyName;
string setPropertyString = $".SetProperty(m => m.{modelPropertyName}, {Model.ModelVariable}.{modelPropertyName})";
@:@setPropertyString
}
}
);

return @resultsNoContent;
return affected == 1 ? @resultsOkEmpty : @resultsNotFound;
})
@{
builderExtensions = $".WithName(\"{@updateModel}\")";
Expand Down Expand Up @@ -131,16 +140,13 @@
@:@builderExtensions;
}

group.MapDelete("/{id}", async @typedTaskWithNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
group.MapDelete("/{id}", async @typedTaskOkNotFound (@primaryKeyShortTypeName @primaryKeyNameLowerCase, @dbContextName db) =>
{
if (await db.@findModel is @modelName @Model.ModelVariable)
{
db.@remove;
await db.SaveChangesAsync();
return @resultsOkModelVariable;
}
var affected = await db.@entitySetName
.Where(model => model.@primaryKeyName == @primaryKeyNameLowerCase)
.ExecuteDeleteAsync();

return @resultsNotFound;
return affected == 1 ? @resultsOkEmpty : @resultsNotFound;
})
@{
builderExtensions = $".WithName(\"{@deleteModel}\")";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ internal static class EFValidationUtil
internal static void ValidateEFDependencies(IEnumerable<DependencyDescription> dependencies, DbProvider dataContextType)
{
var isEFDesignPackagePresent = dependencies
.Any(package => package.Name.Equals(EfConstants.EfDesignPackageName, StringComparison.OrdinalIgnoreCase));
.Any(package => package.Name.Equals(EfConstants.EfToolsPackageName, StringComparison.OrdinalIgnoreCase));

if (!isEFDesignPackagePresent)
{
throw new InvalidOperationException(
string.Format(MessageStrings.InstallEfPackages, $"{EfConstants.EfDesignPackageName}"));
string.Format(MessageStrings.InstallEfPackages, $"{EfConstants.EfToolsPackageName}"));
}

if (EfConstants.EfPackagesDict.TryGetValue(dataContextType, out var dbProviderPackageName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static class EfConstants
public static string SQLite = DbProvider.SQLite.ToString();
public static string CosmosDb = DbProvider.CosmosDb.ToString();
public static string Postgres = DbProvider.Postgres.ToString();
public const string EfDesignPackageName = "Microsoft.EntityFrameworkCore.Design";
public const string EfToolsPackageName = "Microsoft.EntityFrameworkCore.Tools";
public const string SqlServerPackageName = "Microsoft.EntityFrameworkCore.SqlServer";
public const string SqlitePackageName = "Microsoft.EntityFrameworkCore.Sqlite";
public const string CosmosPakcageName = "Microsoft.EntityFrameworkCore.Cosmos";
Expand Down

0 comments on commit a186d89

Please sign in to comment.