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

标签 c# asp.net-core dependency-injection asp.net-core-2.0 asp.net-core-middleware

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

我很困难地使用 native 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 Container 没有办法完全去掉,因为它完全集成在整个过程中;一切都取决于它的存在。该内置容器是 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 仅在启动时创建一次。换句话说,它只是一个单例。

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

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

相关文章:

c# - 在新线程上使用 ObservableCollection

asp.net-mvc - 将对象列表绑定(bind)到表单

angular - 尝试手动注入(inject) NgControl 时出现 Lint 警告 "get is deprecated"

java - Wicket @SpringBean 和 Spring @Autowired 通过构造函数注入(inject)

c# - 每个 Web 请求一个 DbContext ......为什么?

c# - 如何为 Lua(对于 Windows)创建可加载的自定义 .NET dll?

C# One Writer Many Readers 只读一次

c# - 合并多个 AndroidManifest.xml 时出现问题

c# - 如何使用 .NET Core Web 应用程序分发数据保护 key ?

https - 设置 Identity Server 4 反向代理