-
Notifications
You must be signed in to change notification settings - Fork 235
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
Content for Minimal APIs scaffolding with .NET 7 features #1937
Comments
We should figure out if we want to just switch the scaffolders to using the new |
Spoke to Kathleen Dollard about new C# and Roslyn features we may want to accommodate. An updated list can be found here: Sounds like there shouldn't be any features that we will need to support or add. Main C#/Roslyn updates are:
|
Strawman proposal based on what we did for .NET 6 plus new Minimal API features: Sample generated code updated for .NET 7Given the existing model class namespace WebApplication126;
public class Widget
{
public int Id { get; set; }
public string? Name { get; set; }
} Basic CRUD without OpenAPIThe following class will be generated for the basic CRUD case without OpenAPI: namespace WebApplication126;
public static class WidgetEndpoints
{
public static void MapWidgetEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/widgets");
group.MapGet("/", () =>
{
return new [] { new Widget() };
})
.WithName("GetAllWidgets");
group.MapGet("/{id}", (int id) =>
{
return new Widget { Id = id };
})
.WithName("GetWidgetById");
group.MapPut("/{id}", (int id, Widget input) =>
{
return Results.NoContent();
})
.WithName("UpdateWidget");
group.MapPost("/", (Widget widget) =>
{
return Results.Created($"{group.RoutePrefix}/{widget.Id}", widget);
})
.WithName("CreateWidget");
group.MapDelete("/{id}", (int id) =>
{
return Results.Ok(new Widget { Id = id });
})
.WithName("DeleteWidget");
}
} Basic CRUD with OpenAPIThe following class will be generated for the basic CRUD case without OpenAPI: namespace WebApplication126;
public static class WidgetEndpoints
{
public static void MapWidgetEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/widgets");
group.WithOpenApi();
group.MapGet("/", () =>
{
return new [] { new Widget() };
})
.WithName("GetAllWidgets");
group.MapGet("/{id}", (int id) =>
{
return new Widget { Id = id };
})
.WithName("GetWidgetById");
group.MapPut("/{id}", (int id, Widget input) =>
{
return TypedResults.NoContent();
})
.WithName("UpdateWidget");
group.MapPost("/", (Widget widget) =>
{
return TypedResults.Created($"{group.RoutePrefix}/{widget.Id}", widget);
})
.WithName("CreateWidget");
group.MapDelete("/{id}", (int id) =>
{
return TypedResults.Ok(new Widget { Id = id });
})
.WithName("DeleteWidget");
}
} Entity Framework without OpenAPIThe following class will be generated for the Entity Framework case without OpenAPI: using Microsoft.EntityFrameworkCore;
namespace WebApplication126;
public static class WidgetEndpoints
{
public static void MapWidgetEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/widgets");
group.MapGet("/", async (AppDbContext db) =>
{
return await db.Widgets.ToListAsync();
})
.WithName("GetAllWidgets");
group.MapGet("/{id}", async (int id, AppDbContext db) =>
{
return await db.Widgets.FindAsync(id)
is Widget widget
? Results.Ok(widget)
: Results.NotFound();
})
.WithName("GetWidgetById");
group.MapPut("/{id}", async (int id, Widget input, AppDbContext db) =>
{
var widget = await db.Widgets.FindAsync(id);
if (widget is null)
{
return Results.NotFound();
}
widget.Name = input.Name;
await db.SaveChangesAsync();
return Results.NoContent();
})
.WithName("UpdateWidget");
group.MapPost("/", async (Widget widget, AppDbContext db) =>
{
db.Widgets.Add(widget);
await db.SaveChangesAsync();
return Results.Created($"{group.RoutePrefix}/{widget.Id}", widget);
})
.WithName("CreateWidget");
group.MapDelete("/{id}", async (int id, AppDbContext db) =>
{
if (await db.Widgets.FindAsync(id) is Widget widget)
{
db.Widgets.Remove(widget);
await db.SaveChangesAsync();
return Results.Ok(widget);
}
return Results.NotFound();
})
.WithName("DeleteWidget");
}
} Entity Framework with OpenAPIThe following class will be generated for the Entity Framework case with OpenAPI: using Microsoft.EntityFrameworkCore;
namespace WebApplication126;
public static class WidgetEndpoints
{
public static void MapWidgetEndpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/widgets");
group.WithOpenApi();
group.MapGet("/", async (AppDbContext db) =>
{
return await db.Widgets.ToListAsync();
})
.WithName("GetAllWidgets");
group.MapGet("/{id}", async Task<Results<Ok<Widget>, NotFound>> (int id, AppDbContext db) =>
{
return await db.Widgets.FindAsync(id)
is Widget widget
? TypedResults.Ok(widget)
: TypedResults.NotFound();
})
.WithName("GetWidgetById");
group.MapPut("/{id}", async Task<Results<NotFound, NoContent>> (int id, Widget input, AppDbContext db) =>
{
var widget = await db.Widgets.FindAsync(id);
if (widget is null)
{
return TypedResults.NotFound();
}
widget.Name = input.Name;
await db.SaveChangesAsync();
return TypedResults.NoContent();
})
.WithName("UpdateWidget");
group.MapPost("/", async (Widget widget, AppDbContext db) =>
{
db.Widgets.Add(widget);
await db.SaveChangesAsync();
return TypedResults.Created($"/widgets/{widget.Id}", widget);
})
.WithName("CreateWidget");
group.MapDelete("/{id}", async Task<Results<Ok<Widget>, NotFound>> (int id, AppDbContext db) =>
{
if (await db.Widgets.FindAsync(id) is Widget widget)
{
db.Widgets.Remove(widget);
await db.SaveChangesAsync();
return TypedResults.Ok(widget);
}
return TypedResults.NotFound();
})
.WithName("DeleteWidget");
}
} |
Apologies for the delay, PR is up here |
Does it make sense to make the return type for these a public static void MapWidgetEndpoints(this IEndpointRouteBuilder routes)
|
Yes I think the static method should return Do folks think we should add a scaffolder option RE the use of |
@DamianEdwards @captainsafia Should I make this change in the current PR? |
Closing this since the base support is checked in. Will use follow-up issues for specific open items. |
The following group.MapPost("/", (Widget widget) =>
{
return Results.Created($"{group.RoutePrefix}/{widget.Id}", widget);
})
.WithName("CreateWidget"); generates
Where is |
@pstricks-fans |
@captainsafia I wrote the code based on Damien Edwards' code in the section Basic CRUD without OpenAPI. It was not generated by scaffolding. Thank you. |
I think the speclet there was based on an earlier design of route groups. Whatever the scaffolding produces now is what we'd recommend you use as a starting point. |
The team will be rolling out a number of features for .NET 7, some of which we want to include in our scaffolding to make the new functionalities more easily adopted.
Existing scaffolded items include:
List of our .NET 7 features:
Results
API improvements: easier testing and interactingIdeas for scaffolded items:
Result
APIResult
API (with OpenAPI)From the previous minimal API issue:
The text was updated successfully, but these errors were encountered: