1. 程式人生 > >ASP.NET Core中使用GraphQL - 第三章 依賴注入

ASP.NET Core中使用GraphQL - 第三章 依賴注入

ASP.NET Core中使用GraphQL


SOLID原則中的D表示依賴倒置原則。這個原則的內容是:

  • 上層模組不應該直接依賴底層模組,而應該依賴其抽象
  • 抽象不應該依賴於細節, 細節應該依賴抽象

來源:WIKIPEDIA

在一個模組中建立一個其他模組的例項會導致這個模組與其他模組之間的緊耦合。 為了讓不同的模組解耦,我們需要遵循依賴倒置原則。按照這種原則,一個模組不會依賴於其他模組的實現,會依賴於其他模組的抽象,例如介面。

一個抽象會存在許多個實現。無論何時我們碰到一個抽象,我們都需要傳遞一個該抽象的實現。所以我們需要一個類來負責配置他們之間的對映,這裡我們稱這個類為依賴注入容器(dependency injection container)。

ASP.NET Core中已經內建了一個依賴注入容器。它使用起來非常簡單。它不僅能夠配置抽象介面與實現類之間的對映,還可以配置實現類例項的生命週期。

在我們之前的Hello World專案中,我們沒有關注過例項的生命週期。到目前為止,我們會將所有實現類物件設定為了Singleton

這裡我們首先需要解除對DocumentWriterDocumentExecuter

類依賴。方法就是使用抽象介面IDocumentWriterIDocumentExecuter替換DocumentWriterDocumentExecuter

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:ISchemagraphql-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 = _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