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 = 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM