GraphQL在.NET?8中的全面實踐指南(最新推薦)
一、GraphQL與.NET 8概述
GraphQL是一種由Facebook開發(fā)的API查詢語言,它提供了一種更高效、更靈活的替代REST的方案。與REST不同,GraphQL允許客戶端精確指定需要的數(shù)據(jù)結(jié)構(gòu)和字段,避免了"過度獲取"或"不足獲取"的問題。
.NET 8對GraphQL的支持
.NET 8帶來了多項性能改進和新特性,使其成為構(gòu)建GraphQL服務的理想平臺:
- 性能提升:AOT編譯、改進的JIT編譯器
- 最小API增強:簡化GraphQL端點設置
- 原生AOT支持:適合云原生GraphQL服務部署
- 改進的依賴注入:更簡潔的服務注冊方式
二、環(huán)境準備與項目搭建
1. 創(chuàng)建.NET 8項目
dotnet new web -n GraphQLDemo cd GraphQLDemo
2. 添加必要的NuGet包
dotnet add package HotChocolate.AspNetCore dotnet add package HotChocolate.Data dotnet add package Microsoft.EntityFrameworkCore.SqlServer
三、基礎GraphQL服務搭建
1. 定義數(shù)據(jù)模型
// Models/Book.cs
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public DateTime PublishedDate { get; set; }
}
// Models/Author.cs
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Book> Books { get; set; } = new List<Book>();
}2. 配置DbContext
// Data/AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>()
.HasMany(a => a.Books)
.WithOne(b => b.Author)
.HasForeignKey(b => b.AuthorId);
}
}3. 注冊GraphQL服務
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 添加DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 添加GraphQL服務
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddProjections()
.AddFiltering()
.AddSorting();
var app = builder.Build();
app.MapGraphQL(); // 默認路徑為/graphql
app.Run();四、查詢(Query)實現(xiàn)
1. 基本查詢類型
// GraphQL/Query.cs
public class Query
{
[UseDbContext(typeof(AppDbContext))]
[UseProjection]
[UseFiltering]
[UseSorting]
public IQueryable<Book> GetBooks([ScopedService] AppDbContext context)
=> context.Books;
[UseDbContext(typeof(AppDbContext))]
public async Task<Book?> GetBookById(
[ScopedService] AppDbContext context,
int id)
=> await context.Books.FindAsync(id);
}2. 復雜查詢示例
query {
books(where: { title: { contains: "NET" } }, order: { publishedDate: DESC }) {
title
publishedDate
author {
name
}
}
}五、變更(Mutation)實現(xiàn)
1. 基本變更操作
// GraphQL/Mutation.cs
public class Mutation
{
[UseDbContext(typeof(AppDbContext))]
public async Task<AddBookPayload> AddBook(
AddBookInput input,
[ScopedService] AppDbContext context)
{
var book = new Book
{
Title = input.Title,
PublishedDate = input.PublishedDate,
AuthorId = input.AuthorId
};
context.Books.Add(book);
await context.SaveChangesAsync();
return new AddBookPayload(book);
}
}
public record AddBookInput(string Title, DateTime PublishedDate, int AuthorId);
public record AddBookPayload(Book Book);2. 輸入類型與Payload模式
mutation {
addBook(input: {
title: "Mastering GraphQL in .NET 8",
publishedDate: "2023-11-01",
authorId: 1
}) {
book {
id
title
}
}
}六、高級特性實現(xiàn)
1. 數(shù)據(jù)加載器(DataLoader)優(yōu)化
// GraphQL/Query.cs
public async Task<IEnumerable<Author>> GetAuthorsWithBooks(
[Service] AppDbContext context,
[Service] IResolverContext resolverContext)
{
var loader = resolverContext.BatchDataLoader<int, Author>(
"authorsById",
async (ids, ct) =>
{
var authors = await context.Authors
.Where(a => ids.Contains(a.Id))
.ToDictionaryAsync(a => a.Id, ct);
return ids.Select(id => authors.TryGetValue(id, out var author) ? author : null);
});
// 假設我們有一些作者ID
var authorIds = new[] { 1, 2, 3 };
return await loader.LoadAsync(authorIds);
}2. 訂閱(Subscription)實現(xiàn)
// GraphQL/Subscription.cs
[ExtendObjectType("Subscription")]
public class BookSubscriptions
{
[Subscribe]
[Topic("BookAdded")]
public Book OnBookAdded([EventMessage] Book book) => book;
}
// 在Mutation中發(fā)布事件
[UseDbContext(typeof(AppDbContext))]
public async Task<AddBookPayload> AddBook(
AddBookInput input,
[ScopedService] AppDbContext context,
[Service] ITopicEventSender eventSender)
{
var book = new Book { /* ... */ };
context.Books.Add(book);
await context.SaveChangesAsync();
await eventSender.SendAsync("BookAdded", book);
return new AddBookPayload(book);
}七、性能優(yōu)化與安全
1. 查詢復雜度分析
builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddMaxExecutionDepthRule(5) // 限制查詢深度
.AddQueryCostOptions(options =>
{
options.DefaultCost = 1;
options.MaxAllowedCost = 1000;
});2. 認證與授權(quán)
// 添加認證服務
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => { /* 配置JWT */ });
// 保護GraphQL端點
builder.Services
.AddGraphQLServer()
.AddAuthorization()
.AddHttpRequestInterceptor<AuthInterceptor>();
// 實現(xiàn)攔截器
public class AuthInterceptor : DefaultHttpRequestInterceptor
{
public override ValueTask OnCreateAsync(
HttpContext context,
IRequestExecutor requestExecutor,
IQueryRequestBuilder requestBuilder,
CancellationToken cancellationToken)
{
if (!context.User.Identity.IsAuthenticated)
{
throw new GraphQLException("未認證用戶");
}
return base.OnCreateAsync(context, requestExecutor, requestBuilder, cancellationToken);
}
}八、.NET 8特有優(yōu)化
1. AOT編譯支持
<PropertyGroup> <PublishAot>true</PublishAot> </PropertyGroup>
2. 最小API集成
app.MapGraphQL()
.WithTags("GraphQL")
.WithDescription("GraphQL API端點")
.RequireAuthorization();3. 性能監(jiān)控
builder.Services
.AddGraphQLServer()
.AddInstrumentation(options =>
{
options.RequestDetails = RequestDetails.All;
options.IncludeDocument = true;
})
.AddDiagnosticEventListener<PerformanceLogger>();
public class PerformanceLogger : DiagnosticEventListener
{
public override void RequestProcessing(HttpContext context, IRequestExecutor executor, IQueryRequest request)
{
var stopwatch = Stopwatch.StartNew();
base.RequestProcessing(context, executor, request);
stopwatch.Stop();
Console.WriteLine($"請求處理時間: {stopwatch.ElapsedMilliseconds}ms");
}
}九、測試GraphQL API
1. 使用Banana Cake Pop
HotChocolate內(nèi)置了Banana Cake Pop這個GraphQL IDE,訪問/graphql即可使用。
2. 單元測試示例
[TestClass]
public class GraphQLTests
{
[TestMethod]
public async Task GetBooks_ReturnsValidData()
{
// 安排
var executor = await new ServiceCollection()
.AddGraphQLServer()
.AddQueryType<Query>()
.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("TestDB"))
.BuildRequestExecutorAsync();
// 執(zhí)行
var result = await executor.ExecuteAsync(@"
query {
books {
title
author {
name
}
}
}");
// 斷言
Assert.IsFalse(result.Errors?.Any() ?? false);
var books = result.ToJson();
Assert.IsNotNull(books);
}
}十、部署與擴展
1. 容器化部署
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -o /app /p:PublishAot=true FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app . ENTRYPOINT ["./GraphQLDemo"]
2. 擴展架構(gòu)建議
- 聯(lián)邦架構(gòu):使用HotChocolate Federation擴展
- 緩存策略:實現(xiàn)查詢緩存中間件
- 限流:添加請求限流保護
結(jié)語
.NET 8為構(gòu)建高性能GraphQL服務提供了堅實的基礎,結(jié)合HotChocolate這樣的成熟庫,開發(fā)者可以快速構(gòu)建靈活、高效的API服務。本文涵蓋了從基礎到高級的各個方面,希望能幫助您在.NET生態(tài)中充分利用GraphQL的優(yōu)勢。
實際項目中,建議根據(jù)具體需求選擇合適的GraphQL特性,平衡靈活性與性能,并始終關注API的安全性和可維護性
到此這篇關于GraphQL在.NET 8中的全面實踐指南(最新推薦)的文章就介紹到這了,更多相關GraphQL .NET實踐內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于.NET Core 3.1 網(wǎng)站開發(fā)和部署的方法
這篇文章主要介紹了基于.NET Core 3.1 網(wǎng)站開發(fā)和部署的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08
.NET 6開發(fā)TodoList應用之實現(xiàn)接口請求驗證
在響應請求處理的過程中,我們經(jīng)常需要對請求參數(shù)的合法性進行校驗,如果參數(shù)不合法,將不繼續(xù)進行業(yè)務邏輯的處理。本文將介紹如何使用FluentValidation和MediatR實現(xiàn)接口請求驗證,需要的可以參考一下2021-12-12
.net Core連接MongoDB數(shù)據(jù)庫的步驟詳解
這篇文章主要給大家介紹了關于.net Core連接MongoDB數(shù)據(jù)庫步驟的相關資料,文中將實現(xiàn)的步驟一步步介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-02-02

