• GraphQL Part III: 依赖注入


    在 SOLID 设计原则中,D 表示依赖反转原则

    • 高层组件不应该依赖于底层组件,双方应该基于抽象
    • 抽象不应该依赖于实现,实现应该依赖于抽象

    使用 new 操作符来创建对象实例会导致不同组件之间的紧耦合。为了保持它们之间的松耦合,我们应该遵循依赖反转原则。这样模块将不依赖与具体的实现,而是依赖于抽象,例如接口。

    抽象可以有用多种不同的实现,所以,当遇到抽象的时候,应该有某种方式提供某个特定的实现。我们称负责管理这类问题的类为依赖注入容器,它应该可以通过某种方式进行配置。

    ASP.NET Core 提供了内置的依赖注入容器。它简单但是对我们的需求已经足够好用。它不仅可以配置抽象对应的实现,还可以控制其所创建对象的生命周期。

    当前,对于我们简单的 Hello, World 应用来说,我们还不关心生命周期,所以,我们将对所有的实例仅仅使用 Singleton 单例模式。

    我们不再实例化 DocumentWriter 和 DocumentExecutor,我们可以使用它们的抽象接口 IDocumentWriter 和 IDocumentExecutor。因此,我们可以使用内置的依赖注入容器如下配置:

    public void ConfigureServices(IServiceCollection services)  
    {
        services.AddSingleton<IDocumentWriter, DocumentWriter>();
        services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
    }

    对于 HelloWordQuery,我们没有定义接口,我们也可以直接使用这个实现。

    services.AddSingleton<HelloWordQuery>();  

    Schema 包含 Query,以后我们还会增加 Mutation 和其它字段。所以,我们最好创建一个独立的类来管理它。该类将扩展 Schema 类型,我们通过构造函数进行依赖注入。

    public class HelloWorldSchema : Schema
    {
        public HelloWorldSchema(HelloWorldQuery query)
        {
            Query = query;
        }
    }

    最后,我们在 ConfigureServices 方法中配置 HelloWorldSchema 。

    services.AddSingleton<ISchema, HelloWorldSchema>();  

    注:ISchema 来自 GraphQL 库。

    现在,我们可以将中间件的代码分离到它自己的类中。如下代码我们命名为 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.Write(result);
                    await httpContext.Response.WriteAsync(json);
                }
            }
            else
            {
                await _next(httpContext);
            }
        }
    }

    注意,我们将所有实例类型替换为抽象类型,使我们代码松耦合。每个可注入的服务通过构造函数进行注入。

    最后但不是最后一步,我们必须将中间件连接到应用处理管线中。IApplicationBuilder 拥有名为 UseMiddleware 的扩展方法,以用于连接中间件,所以,最后的 Configure 方法如下所示:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMiddleware<GraphQLMiddleware>();
    }

    上一篇:GraphQL Part II: 中间件

  • 相关阅读:
    安卓中期小作业
    安卓大作业UI预定搞
    实验3
    实验一总结
    实验8 SQLite数据库操作
    实验6 在应用程序中播放音频和视频
    实验4 颜色、字符串资源的使用
    实验四
    实验三
    实验二
  • 原文地址:https://www.cnblogs.com/haogj/p/9173680.html
Copyright © 2020-2023  润新知