Можно ли использовать ASP.NET.Core без DI-контейнера - PullRequest
0 голосов
/ 31 мая 2018

Я использую ASP.NET.Core для встраивания веб-сервера в большое устаревшее настольное приложение.Мои компоненты промежуточного программного обеспечения должны ссылаться на уже существующие объекты приложения.

С трудом я получил эту работу, используя собственный контейнер DI, но полученный код чрезвычайно тупой и непрозрачный.

Что бы я хотелдействительно нравится делать, это явно вставлять зависимости, которые являются конкретными ранее существующими экземплярами объекта, через параметры конструктора.Авто-магия контейнера DI не дает мне никаких преимуществ, только много боли!

Можно ли использовать ASP.NET.Core без контейнера DI?

Вот несколько упрощенных кодов, иллюстрирующих моё текущее решение:

    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?

1 Ответ

0 голосов
/ 31 мая 2018

Невозможно полностью удалить встроенный DI-контейнер из ASP.NET Core, поскольку он полностью интегрирован во весь процесс;все зависит от его существования.

Это означает, что как разработчик приложения, так или иначе, вам придется взаимодействовать с ним в какой-то момент, когда речь заходит об изменении поведения по умолчанию.

Этооднако это не означает, что вы вынуждены использовать встроенный DI-контейнер или фактически используете любой контейнер для построения графов объектов приложения комплектующие.Построение графов объектов без использования контейнера DI - довольно распространенная практика, называемая Pure DI , и это, по большей части, возможно и при использовании ASP.NET Core.

Если вы хотите практиковать Pure DI, это обычно означает замену нескольких общих точек перехвата.На такой общей точке перехвата находится IControllerActivator абстракция.Заменив реализацию по умолчанию, вы можете перехватить создание экземпляров контроллера MVC, которые обычно являются корневыми объектами графов объектов вашего приложения. Вот пример репозитория Github , который демонстрирует, как применять Pure DI при создании контроллеров.

Однако в вашем примере вы, похоже, имеете дело только с пользовательским промежуточным ПО.В этом случае проще использовать Pure DI, поскольку он не требует замены фабричных абстракций, таких как IControllerActivator.Это можно сделать следующим образом:

var middleware = new MyMiddleware(_dep1, _dep2);

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

Обратите внимание, как я переместил RequestDelegate из конструктора MyMiddleware в метод InvokeAsync.Причина для этого заключается в том, что это позволяет создавать MyMiddleware независимо от любых значений времени выполнения.RequestDelegate - это значение времени выполнения, а в предыдущем примере MyMiddleware создается только один раз при запуске.Другими словами, это просто Singleton.

В случае, если MyMiddleware содержит некоторое изменяемое состояние и, следовательно, не может кэшироваться бесконечно, вы можете создать его внутри делегата.Это означает, что он будет создан один раз за запрос.

...