可以在没有 DI 容器的情况下使用 ASP.NET.Core

Met*_*per 6 c# dependency-injection asp.net-core asp.net-core-middleware asp.net-core-2.0

我正在使用 ASP.NET.Core 将 Web 服务器嵌入到大型遗留桌面应用程序中。我的中间件组件需要引用预先存在的应用程序对象。

我很困难地使用本机 DI 容器完成了这项工作,但生成的代码非常迟钝和不透明。

我真正想做的是通过构造函数参数显式注入依赖项,这些依赖项是特定的预先存在的对象实例。DI 容器的自动魔法并没有给我任何好处,只是给我带来了很多痛苦!

是否可以在没有 DI 容器的情况下使用 ASP.NET.Core?

下面是一些简化的代码来说明我当前的解决方案:

    class Dependency 
    { 
        public string Text { get; } 
        public Dependency(string text) => Text = text; 
    }

    class MyMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly Dependency _dep1;
        private readonly Dependency _dep2;

        public MyMiddleware(RequestDelegate next, Dependency dep1, Dependency dep2)
        {
            _next = next;
            _dep1 = dep1;
            _dep2 = dep2;
        }

        public Task InvokeAsync(HttpContext context)
        {
            return context.Response.WriteAsync(_dep1.Text + _dep2.Text);
        }
    }
Run Code Online (Sandbox Code Playgroud)

启动和应用代码:

    class Startup
    {
        private readonly Dependency _dep1;
        private readonly Dependency _dep2;

        public Startup(Dependency dep1, Dependency dep2)
        {
            _dep1 = dep1;
            _dep2 = dep2;
        }

        public void Configure(IApplicationBuilder appBuilder)
        {
            appBuilder.UseMiddleware<MyMiddleware>(_dep1, _dep2);
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var dep1 = new Dependency("Hello ");
            var dep2 = new Dependency("World");
            int port = 5000;
            StartWebServer(port, dep1, dep2);
            Process.Start($"http://localhost:{port}");
        }

        void StartWebServer(int port, Dependency dep1, Dependency dep2)
        {
            IWebHostBuilder builder = new WebHostBuilder();
            builder.UseUrls($"http://0.0.0.0:{port}/");
            builder.UseKestrel();
            builder.ConfigureServices(servicesCollection => servicesCollection.AddSingleton(new Startup(dep1, dep2)));
            builder.UseStartup<Startup>();
            IWebHost webHost = builder.Build();
            var task = webHost.StartAsync();
        }
    }
Run Code Online (Sandbox Code Playgroud)

能否重构此示例代码以消除 DI 容器?

Ste*_*ven 3

没有办法从 ASP.NET Core 中完全删除内置的 DI 容器,因为它\xe2\x80\x99s 完全集成在整个过程中;一切都取决于它的存在。该内置容器是 ASP.NET Core 提供的更大配置 API 的一部分。

\n\n

这意味着作为应用程序开发人员,在更改默认行为时,您必须以某种方式与它进行交互。\n但这并不意味着您被迫使用内置的- 在 DI 容器中,或者实际上使用任何容器,来构建应用程序组件的对象图。不使用 DI 容器构建对象图是一种非常常见的做法,称为纯 DI,并且在大多数情况下,在使用 ASP.NET Core 时也是可能的。

\n\n

如果您想练习纯 DI,通常意味着替换一些常见的拦截点。一种常见的拦截点就是IControllerActivator抽象。通过替换默认实现,您可以拦截 MVC 控制器实例的创建,这些实例通常是应用程序对象图的根对象。这是一个 Github 存储库示例,演示了如何应用 Pure DI 来创建控制器。

\n\n

然而,在您的示例中,您似乎只处理自定义中间件。在这种情况下,使用 Pure DI 就更简单了,因为它不需要替换工厂抽象,例如IControllerActivator. 这可以按如下方式完成:

\n\n
var middleware = new MyMiddleware(_dep1, _dep2);\n\napp.Use((context, next) =>\n{\n    return middleware.InvokeAsync(context, next);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意我如何将构造函数中RequestDelegate的 移出MyMiddlewareInvokeAsync方法中。这样做的原因是这样可以MyMiddleware独立于任何运行时值进行创建。RequestDelegate是一个运行时值,在前面的示例中,MyMiddleware仅在启动时创建一次。换句话说,它只是一个单例。

\n\n

如果确实MyMiddleware包含某些可变状态,因此不能无限期地缓存 xe2x80x99(例如,因为它依赖于 DbContext),您可以在委托内创建它。这意味着每个请求都会创建一次。

\n