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

我很难用本地DI容器来完成此工作,但是生成的代码异常笨拙且不透明。

我真正想做的是通过构造函数参数显式注入(inject)依赖项,这些依赖项是特定的预先存在的对象实例。 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);
        }
    }

启动和应用程序代码:
    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();
        }
    }

可以重构此示例代码以消除DI容器吗?

最佳答案

由于它完全集成在整个过程中,因此无法从ASP.NET Core中完全删除内置的DI容器。一切都取决于它的存在。该内置容器是ASP.NET Core提供的较大配置API的一部分。

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

如果您想练习Pure DI,通常意味着要替换一些常见的拦截点。这样的常见拦截点就是IControllerActivator抽象。通过替换默认实现,您可以拦截MVC Controller 实例的创建,这些实例通常是应用程序对象图的根对象。 Here is an example Github repository演示了如何在创建 Controller 方面应用Pure DI。

但是,在您的示例中,您似乎只处理自定义中间件。在那种情况下,使用Pure DI甚至更加简单,因为它不需要替换工厂抽象,例如IControllerActivator。可以按照以下步骤进行操作:

var middleware = new MyMiddleware(_dep1, _dep2);

app.Use((context, next) =>
{
    return middleware.InvokeAsync(context, next);
});

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

如果MyMiddleware确实包含某些可变状态,因此无法无限期地缓存(例如,因为它取决于DbContext),则可以在委托(delegate)内部创建它。这意味着每个请求将创建一次。

关于c# - 可以在没有DI容器的情况下使用ASP.NET.Core,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50621061/

10-15 23:43