ASP.NET Core Minimal API 實戰 DevOps 部署 IIS Server
2024-07-02
實作將 ASP.NET Core Minimal API 部署到 IIS Server 的 DevOps 流程與設定細節。
說明
Coding
建立專案安裝所需要的 Nuget Packges
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
加入 .editorconfig
檔案,設定 namespace declarations 為 file scoped。
csharp_style_namespace_declarations = file_scoped:silent
建立 Todo.cs
作為 Model
public class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
建立 TodoDb.cs
作為 DbContext,進行與資料庫的溝通,這裡使用 InMemory Database,簡化範例。
class TodoDb : DbContext
{
public TodoDb(DbContextOptions<TodoDb> options)
: base(options) { }
public DbSet<Todo> Todos => Set<Todo>();
}
接著建立 TodoItemDTO.cs
作為 Data Transfer Object,用來將 Entity 轉換為 DTO。
public class TodoItemDTO
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public TodoItemDTO() { }
public TodoItemDTO(Todo todoItem) =>
(Id, Name, IsComplete) = (todoItem.Id, todoItem.Name, todoItem.IsComplete);
}
主要的執行設定在 Program.cs ,設定 Minimal API 與 Swagger。
不同於預設 Minimal API 使用 MapGet
以及 MapPost
等方法,這裡使用 MapTodoEndpoints
來將 Todo 相關的 API 路由設定獨立出來。
using Microsoft.EntityFrameworkCore;
using MinimalAPI;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<TodoDb>(opt => opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Register Swagger services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Enable middleware about Swagger
app.UseSwagger();
app.UseSwaggerUI();
// Register Todo endpoints
app.MapTodoEndpoints();
app.Run();
TodoEndpoints.cs
中設定 Todo 相關的 API Routing,一共使用以下的技巧:
MapGroup
整合相同路由前綴的 API- 使用 static method 來定義 API 的實作
- 使用
TypedResults
來回傳不同的 HTTP Status Code - 使用
TodoItemDTO
來將 Entity 轉換為 DTO,避免直接回傳 Entity
using Microsoft.EntityFrameworkCore;
namespace MinimalAPI;
public static class TodoEndpointsExtensions
{
public static void MapTodoEndpoints(this WebApplication app)
{
RouteGroupBuilder todoItems = app.MapGroup("/todoitems");
todoItems.MapGet("/", GetAllTodos);
todoItems.MapGet("/complete", GetCompleteTodos);
todoItems.MapGet("/{id}", GetTodo);
todoItems.MapPost("/", CreateTodo);
todoItems.MapPut("/{id}", UpdateTodo);
todoItems.MapDelete("/{id}", DeleteTodo);
}
static async Task<IResult> GetAllTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Select(x => new TodoItemDTO(x)).ToArrayAsync());
}
static async Task<IResult> GetCompleteTodos(TodoDb db)
{
return TypedResults.Ok(await db.Todos.Where(t => t.IsComplete).Select(x => new TodoItemDTO(x)).ToListAsync());
}
static async Task<IResult> GetTodo(int id, TodoDb db)
{
return await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(new TodoItemDTO(todo))
: TypedResults.NotFound();
}
static async Task<IResult> CreateTodo(TodoItemDTO todoItemDTO, TodoDb db)
{
var todoItem = new Todo
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
db.Todos.Add(todoItem);
await db.SaveChangesAsync();
todoItemDTO = new TodoItemDTO(todoItem);
return TypedResults.Created($"/todoitems/{todoItem.Id}", todoItemDTO);
}
static async Task<IResult> UpdateTodo(int id, TodoItemDTO todoItemDTO, TodoDb db)
{
var todo = await db.Todos.FindAsync(id);
if (todo is null) return TypedResults.NotFound();
todo.Name = todoItemDTO.Name;
todo.IsComplete = todoItemDTO.IsComplete;
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
static async Task<IResult> DeleteTodo(int id, TodoDb db)
{
if (await db.Todos.FindAsync(id) is Todo todo)
{
db.Todos.Remove(todo);
await db.SaveChangesAsync();
return TypedResults.NoContent();
}
return TypedResults.NotFound();
}
}
Deploy
接著我們要透過 Azure DevOps 來進行部署,將專案推上 Azure DevOps 後,首先要設定 Pipeline 與 .NET Framework 的設定相同,只需要注意 Build Machine 要選擇支援 .NET 8 的版本。
在 Deploy Pipeline 中,設定也是相同,只要注意應用程式集區的 .NET 版本要選擇為 No Managed Code。
最重要的是部署的伺服器,需要預先安裝 .NET 8 的 Hosting Bundle,這樣才能正確執行 ASP.NET Core Minimal API (注意下載的時候不要選 x32 或 x64 版本,要選 Hosting Bundle 版本)。
參考資料
https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-8.0&tabs=visual-studio