ASP.NET Core中使用GraphQL
SOLID
原則中的D
表示依賴倒置原則。這個原則的內容是:
- 上層模塊不應該直接依賴底層模塊,而應該依賴其抽象
- 抽象不應該依賴於細節, 細節應該依賴抽象
來源:WIKIPEDIA
在一個模塊中創建一個其他模塊的實例會導致這個模塊與其他模塊之間的緊耦合。 為了讓不同的模塊解耦,我們需要遵循依賴倒置原則。按照這種原則,一個模塊不會依賴於其他模塊的實現,會依賴於其他模塊的抽象,例如接口。
一個抽象會存在許多個實現。無論何時我們碰到一個抽象,我們都需要傳遞一個該抽象的實現。所以我們需要一個類來負責配置他們之間的映射,這里我們稱這個類為依賴注入容器(dependency injection container)。
ASP.NET Core中已經內置了一個依賴注入容器。它使用起來非常簡單。它不僅能夠配置抽象接口與實現類之間的映射,還可以配置實現類實例的生命周期。
在我們之前的Hello World項目中,我們沒有關注過實例的生命周期。到目前為止,我們會將所有實現類對象設置為了Singleton
。
這里我們首先需要解除對DocumentWriter
和DocumentExecuter
類依賴。方法就是使用抽象接口IDocumentWriter
和IDocumentExecuter
替換DocumentWriter
和DocumentExecuter
。
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IDocumentWriter, DocumentWriter>();
services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
}
對於HelloWorldQuery
實例,我們沒有編寫任何抽象接口,所以這里我們簡單的使用了其原始實現。
services.AddSingleton<HelloWorldQuery>();
當前的結構(Schema)中包含了一個query
, 在后續的博文中我們還會添加mutation
和其他字段,所以這里我們最好創建一個獨立的類來設置它。所以這里我們創建了一個HelloWorldSchema
類,它繼承自Schema
, 並在構造中注入了一個HelloWorldQuery
實例。
public class HelloWorldSchema : Schema
{
public HelloWorldSchema(HelloWorldQuery query)
{
Query = query;
}
}
最后我們在Startup.cs
文件的Configure
方法中注入HelloWorldSchame
services.AddSingleton<ISchema, HelloWorldSchema>();
TIPS:
ISchema
是graphql-dotnet
庫中一個接口,Schema
類實現了ISchema
接口
現在我們將之前創建的中間件移到一個單獨的類中,我們將它命名為GraphQLMiddleware
, 其代碼如下。
public class GraphQLMiddleware
{
private readonly RequestDelegate _next;
private readonly IDocumentWriter _writer;
private readonly IDocumentExecuter _executor;
private readonly ISchema _schema;
public GraphQLMiddleware(RequestDelegate next,
IDocumentWriter writer,
IDocumentExecuter executor,
ISchema schema)
{
_next = next;
_writer = writer;
_executor = executor;
_schema = schema;
}
public async Task InvokeAsync(HttpContext httpContext)
{
if (httpContext.Request.Path.StartsWithSegments("/api/graphql")
&& string.Equals(httpContext.Request.Method,
"POST",
StringComparison.OrdinalIgnoreCase))
{
string body;
using (var streamReader = new StreamReader(httpContext.Request.Body))
{
body = await streamReader.ReadToEndAsync();
var request = JsonConvert.DeserializeObject<GraphQLRequest>(body);
var result = await _executor.ExecuteAsync(doc =>
{
doc.Schema = _schema;
doc.Query = request.Query;
}).ConfigureAwait(false);
var json = await _writer.WriteToStringAsync(result);
await httpContext.Response.WriteAsync(json);
}
}
else
{
await _next(httpContext);
}
}
}
這里你會注意到我們是如何使用抽象接口來解耦的,在GraphQLMiddleware
的構造函數中,我們注入了當前中間件所需的所有服務IDocumentWriter
, IDocumentExecuter
, 以及ISchema
最后我們需要將這個中間件注冊到應用程序管道中。IApplicationBuilder
接口提供了一個擴展方法UseMiddleware
, 我們可以使用它來注冊中間件。所以最終Configure
方法中的代碼如下:
public void Configure(IApplicationBuilder app,
IHostingEnvironment env)
{
app.UseMiddleware<GraphQLMiddleware>();
}
現在我們重新使用POSTMAN來測試。
結果正確輸出了。
本文源代碼:https://github.com/lamondlu/GraphQL_Blogs/tree/master/Part%20III