- Регистрация
- 05.06.2016
- Сообщения
- 258
- Благодарностей
- 307
- Баллы
- 63
Вечер в хату, автоматизаторы всего и вся!
Данное писание можно считать продолжением статьи «Начинаем кодить на c#» от господина @Brabus_bots.
Собственно, это для тех, кому было мало, и, кто ищет новые подходы к разработке...
Долго ходить вокруг да около не буду, начну сразу лить воду, готовьтесь принимать душ…(ʘ ͜ʖ ʘ)
Вот мы уже знаем, что такое переменные, циклы и goto, который не раз выстреливал нам в левое колено…
Да и вообще мы крутые ребята, которые умеют писать “Hello, world” закрытыми глазами!
Но всё-таки мы - зеннолабовцы - с форума «Сообщество профессионалов автоматизации», а значит нам всегда хочется знать больше!
Мы хотим покорять новые горизонты! Что ж, погнали! Время писать «Hello, world!» используя контейнеры (⊙ˍ⊙)
Что у нас по плану?
Если вам здесь всё понятно, то проблем в понимании материала ниже возникнуть не должно.
Начнем с небольшой теории, для большего понимания:
Универсальный узел - инкапсулирует все ресурсы приложения и функциональные возможности времени существования
(согласен, мелкомягкие пишут как-то страшно, но всё, что нам нужно будет – пихнуть заранее созданную конфигурацию сервисов в "IHostBuilder" и всё забилдить ключевым словом "Build").
Инкапсуляция – механизм сокрытия какой-либо реализации/деталей от лишних глаз и предоставление итоговому клиенту
только того функционала, который мы задумывали (для этого используются модификаторы доступа, такие как: private, internal, public и т.д.).
Dependency Injection (DI) – процесс предоставления внешней зависимости программному компоненту.
В проекте, осуществлять инъекции будем через конструктор класса. Следует знать, что это не единственная возможность,
есть и другие способы: инъекция через метод и свойств, но, как говорил мой сэмпай - “это бэд практис” - ¯\_(ツ)_/¯.
Зависимость — это любой объект, от которого зависит другой объект (например, если мы в методе используем инстанс зенки,
то сам метод будет зависим от этого инстанса зенки, получается, инстанс – наша внешняя зависимость).
IoC-контейнер — это библиотека/фреймворк которая позволит нам упростить и автоматизировать написание кода с использованием данного подхода.
Она будет создавать и предоставлять нам готовые инстансы в проекте (если мы их конечно же зарегистрировали в конфиге).
Основные IoC библиотеки, которые предоставляют нам магию: «Microsoft.Extensions.DependencyInjection» и «Autofac» (мы будем использовать реализацию от Microsoft).
Интерфейс – это контракт, некая абстракция, который должен реализовать класс (например, в созданном проекте,
у нас есть класс “Program”, который реализует интерфейс “IZennoExternalCode”, то есть, “Program” должен по контракту реализовать
метод “Execute”, который прописан в интерфейсе “IZennoExternalCode”, а как именно это будет реализовано – уже наша забота,
а не разработчиков ZennoPoster (они и так лапочки).
Подготовка инструментов:
(1) Медлить не будем, поэтому, сразу врываемся с ноги на сайт Microsoft, вежливо говорим “Ня, аригато”, качаем Visual Studio 2022 и устанавливаем её по инструкциям из интернетов.
Запускаем скаченный “Visual Studio Setup” и выбираем “.NET Desktop Development” (не уверен, но этого должно хватить)
Проекты для ZP у нас будут создаваться на древнем .NET Framework 4.6.2, так что, на всякий случай ставим эти пакеты тоже.
Тыкаем "Install" (у меня "Modify", так, как студия уже установлена)
(2) Создаём новый проект в “ProjectMaker” и добавляем сие чудо-кубик.
(3) Кликаем на создание нового проекта в свойствах кубика.
(4)Заполняем поля и кликаем “OK”
“Название решения” – даём более общее название, ибо там может быть много проектов (решение – это то, что объединяет проекты).
“Название проекта” – даём более конкретное название, там будет наш код (повторять название, как я – не обязательно, просто люблю такое соблюдение неймспейсов).
То есть, такое именование будет так же корректным.
А вот и произошла магия - наш первый проект в Visual Studio создан.
П.С. Наши свойства кубика будут заполнены автоматически и в будущем мы сможем спокойно подключаться к проекту.
Примечание:
Замечу, мы должны выставить в “ProjectMaker” и “Visual Studio” тёмную тему.
Для чего? Ходят слухи, что иначе программы могут работать некорректно…(⊙ˍ⊙)
Сделали?! Ну всё, теперь, мы точно готовы двигаться дальше…(¬‿¬)
Практика:
Вообще, всё интуитивно понятно, но пакеты тут, если что
(1) Я создал тут папочку для вас, в которую добавил новый статический класс.
(2) Так же добавляем в него юзинг установленной библиотеки для работы с IoC.
(3) В классе добавляем статический метод расширения для "IServiceCollection", где будет проходить наша регистрация сервисов
для последующего предоставления в качестве внешних зависимостей. На данный момент, там зарегистрированы: инстанс браузера и инстанс зенки.
(1) Ключевое слово “this”, в данном контексте, говорит нам о том, что это метод расширения, а расширяем мы "IServiceCollection".
То есть, когда в следующий раз, мы тыкнем « . » после объекта типа "IServiceCollection" (правильнее сказать, объекта, который реализовывает данный интерфейс,
но нам это знать сейчас не обязательно), то у нас будет доступен наш метод “AddApplication” в который мы должны будем передать "Instance" и "IZennoPosterProjectModel"
(первый параметры – IServiceCollection – передавать не нужно, поскольку, именно у его мы вызываем этот метод и он будет передан автоматически).
П.С. Методы расширения могут быть только в статическом классе и статическом методе.
(2) Тут мы добавляем/регистрируем наши сервисы/инстансы в рамках жизненного цикла называемого “Scoped”
(он, кстати, написан тоже, как метод расширения; это видно на всплывашке при наведении курсора на метод и ключевому слову “extension”).
(3) "IServiceCollection" – это возвращаемый тип (то есть, мы используем метод расширения для "IServiceCollection" и его же возвращаем, таким образом, это образует Fluent Interface/Fluent Api).
(4) Всё это входные параметры метода (сигнатура метода).
Ещё чуть-чуть разжую, на всякий…)
(1) Это сервисы, которые мы регистрируем.
(2) А это мы запихиваем готовые инстансы этих сервисов (обычно, контейнер сам нам создает и предоставляет инстансы, но, в данном случае,
нам нужны уже готовые, которые пришли прямиком из ZennoPoster или ProjectMaker).
Чтоб всё у нас завелось - я вернулся в наш класс “Program” и…
(1) Добавляем юзинг хостинга (пакета, который мы ранее должны были установить).
(2) Так же добавляем стандартный метод для создания хост билдера, в который передаём инстансы пришедшие из зенки.
(3) И именно тут используем наш, выше написанный, метод расширения.
“services” – это и есть тот самый первый параметр “IServiceCollection” (можете сами потом убедиться, наведя мышку на этот объект).
(4) Разумеется, вызываем метод для создания хост билдера.
(5) А следом вызываем и метод сборки.
Всё! Теперь наш контейнер сможет нам творить магию в виде инъекций инстансов зарегистрированных сервисов в конструкторы классов,
то бишь, будет предоставлять нам внешние зависимости (~ ̄▽ ̄)~
Собственно, толку пока не много, нужно вывести наш первый “Hello, world!”
«Hello, world!» в контейнере:
(1) Собственно, мы создали наш первый условный сервис (да, обычный класс).
(2) Добавили метод “Run”, который будем вызывать для старта сервиса (название может быть любым).
(3) Добавили конструктор класса, именно сюда IoC будет производить нашу инъекцию, когда мы обратимся к методу “Run”.
Заметьте, что у конструктора класса “0 references”, а это значит, что на него никто не ссылается, а он будет вызваться…
Что-то это, если не магия?! Атеистам шах и мат! (⊙_(⊙_⊙)_⊙)
(1) Теперь регистрируем созданный сервис в нашем регистраторе.
Опять же, обратите внимание, что никакого инстанса мы не пихаем,
IoC за нас будет создавать его и предоставлять конструктору нужные внешние зависимости.
Получается так, что в конструкторе сервиса (созданном нами классе) мы можем использовать любой порядок внешних зависимостей.
(1) Всё, теперь нам требуется просто запросить наш сервис у хоста (если быть точным, то у "IServiceProvider", который обитает в свойствах "IHost".
Не устану повторять: мы запрашиваем сервис у которого есть конструктор, но ничего не передаём для самого конструктора, IoC сам всё сделает исходя из конфига.
По поводу "IServiceProvider": мы так же можем использовать его в конструкторах не статических классов, если нам потребуется
выдернуть какой-то инстанс сервиса похожим образом, при этом, не нужно заранее регистрировать "IServiceProvider" в нашем конфиге, он уже зарегистрирован под капотом.
(2) И вызвать тот самый метод “Run”
Теперь просто запускаем проект в зенке и наблюдаем за нашим итоговым результатом - «Hello, world!» - в контейнере!
Задачка на подумать: это не обязательно, но, в идеале, теперь неплохо бы было избавиться от завязки на реализации,
и завязаться на абстракции, то есть, на интерфейсе, например “IHelloWorldService”, а как это сделать – придётся решать вам самим.
Резюме по Dependency Injection и IoC-контейнеру:
DI и IoC – вещи не сложные, но это прям то, что доктор прописал для больших проектов
планируемых расширяться в будущем (для мелких так же подойдёт), где есть куча зависимостей и сложной реализации и т.д.
Данный подход к разработке проекта: упрощает написание кода, делает его более гибким, поддерживаемым, расширяемым и более приятным.
К тому же, не нужно беспокоиться за стейт объектов и хранить всё по статическим переменным /ᐠ。ꞈ。ᐟ\
Резюме по кубику “Проект Visual Studio”:
Очевидно, что данная фича будет очень полезна тем, кто начал начал использовать C# в своих проектах.
Разработчики ZennoPoster делают шаги в правильном направлении (осталось открыть API для решения ReCaptcha2 из Visual Studio, - цены бы вам тогда не было).
Написание проектов в VS ускоряет и упрощает разработку за счёт умного "Интеллисенс", а "Nuget package manager" - открывает доступ к огромному количеству библиотек,
да и дебажить в студии просто волшебно (✿◡‿◡)
П.С. Это была моя первая статья, и это был лишь косплей на программиста, не судите строго...
Данное писание можно считать продолжением статьи «Начинаем кодить на c#» от господина @Brabus_bots.
Собственно, это для тех, кому было мало, и, кто ищет новые подходы к разработке...
Долго ходить вокруг да около не буду, начну сразу лить воду, готовьтесь принимать душ…(ʘ ͜ʖ ʘ)
Вот мы уже знаем, что такое переменные, циклы и goto, который не раз выстреливал нам в левое колено…
Да и вообще мы крутые ребята, которые умеют писать “Hello, world” закрытыми глазами!
Но всё-таки мы - зеннолабовцы - с форума «Сообщество профессионалов автоматизации», а значит нам всегда хочется знать больше!
Мы хотим покорять новые горизонты! Что ж, погнали! Время писать «Hello, world!» используя контейнеры (⊙ˍ⊙)
Что у нас по плану?
- Кто такой этот магический кубик «Проект Visual Studio»
- Познакомиться с Dependency Injection (DI), IoC-контейнерами и зачем оно нам нужно...
- Напишем мелкий и бесполезный проект в Visual Studio 2022 для демонстрации использования DI
Если вам здесь всё понятно, то проблем в понимании материала ниже возникнуть не должно.
Код обычного C# кубика:
// дёргаем локальный метод для отправки полученного текста в лог
Print(GetTextFromSite());
// отправка сообщения в лог
void Print(string sendText)
{
project.SendToLog(sendText, ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Green);
}
// получение текста текста с сайта
string GetTextFromSite()
{
// получаем страницу вики
var doc = new Global.Zennolab.HtmlAgilityPack.HtmlWeb().Load("https://en.wikipedia.org/wiki/%22Hello,_World!%22_program");
// получаем текст по xPath
var hw = doc.DocumentNode?.SelectSingleNode("//div[contains(@id, 'content')]/descendant::div[contains([USER=46442]@class[/USER], 'c#')]")?.InnerText;
// выдёргиваем нужное регуляркой и возвращаем
return hw != null ? Regex.Match(hw, @"(?<=").*?(?=")").Value : string.Empty;
}
Начнем с небольшой теории, для большего понимания:
Универсальный узел - инкапсулирует все ресурсы приложения и функциональные возможности времени существования
(согласен, мелкомягкие пишут как-то страшно, но всё, что нам нужно будет – пихнуть заранее созданную конфигурацию сервисов в "IHostBuilder" и всё забилдить ключевым словом "Build").
Инкапсуляция – механизм сокрытия какой-либо реализации/деталей от лишних глаз и предоставление итоговому клиенту
только того функционала, который мы задумывали (для этого используются модификаторы доступа, такие как: private, internal, public и т.д.).
Dependency Injection (DI) – процесс предоставления внешней зависимости программному компоненту.
В проекте, осуществлять инъекции будем через конструктор класса. Следует знать, что это не единственная возможность,
есть и другие способы: инъекция через метод и свойств, но, как говорил мой сэмпай - “это бэд практис” - ¯\_(ツ)_/¯.
Зависимость — это любой объект, от которого зависит другой объект (например, если мы в методе используем инстанс зенки,
то сам метод будет зависим от этого инстанса зенки, получается, инстанс – наша внешняя зависимость).
IoC-контейнер — это библиотека/фреймворк которая позволит нам упростить и автоматизировать написание кода с использованием данного подхода.
Она будет создавать и предоставлять нам готовые инстансы в проекте (если мы их конечно же зарегистрировали в конфиге).
Основные IoC библиотеки, которые предоставляют нам магию: «Microsoft.Extensions.DependencyInjection» и «Autofac» (мы будем использовать реализацию от Microsoft).
Интерфейс – это контракт, некая абстракция, который должен реализовать класс (например, в созданном проекте,
у нас есть класс “Program”, который реализует интерфейс “IZennoExternalCode”, то есть, “Program” должен по контракту реализовать
метод “Execute”, который прописан в интерфейсе “IZennoExternalCode”, а как именно это будет реализовано – уже наша забота,
а не разработчиков ZennoPoster (они и так лапочки).
Подготовка инструментов:
(1) Медлить не будем, поэтому, сразу врываемся с ноги на сайт Microsoft, вежливо говорим “Ня, аригато”, качаем Visual Studio 2022 и устанавливаем её по инструкциям из интернетов.
Запускаем скаченный “Visual Studio Setup” и выбираем “.NET Desktop Development” (не уверен, но этого должно хватить)
Проекты для ZP у нас будут создаваться на древнем .NET Framework 4.6.2, так что, на всякий случай ставим эти пакеты тоже.
Тыкаем "Install" (у меня "Modify", так, как студия уже установлена)
Создаём новый проект (сама студия должна быть закрыта)
Нашёл оригинал по вопросику (?) в правом верхнем углу:
Проект Visual Studio - Русская справка Zennolab - Confluence (atlassian.net)
Нашёл оригинал по вопросику (?) в правом верхнем углу:
Проект Visual Studio - Русская справка Zennolab - Confluence (atlassian.net)
(2) Создаём новый проект в “ProjectMaker” и добавляем сие чудо-кубик.
(3) Кликаем на создание нового проекта в свойствах кубика.
(4)Заполняем поля и кликаем “OK”
“Название решения” – даём более общее название, ибо там может быть много проектов (решение – это то, что объединяет проекты).
“Название проекта” – даём более конкретное название, там будет наш код (повторять название, как я – не обязательно, просто люблю такое соблюдение неймспейсов).
То есть, такое именование будет так же корректным.
А вот и произошла магия - наш первый проект в Visual Studio создан.
П.С. Наши свойства кубика будут заполнены автоматически и в будущем мы сможем спокойно подключаться к проекту.
Примечание:
Замечу, мы должны выставить в “ProjectMaker” и “Visual Studio” тёмную тему.
Для чего? Ходят слухи, что иначе программы могут работать некорректно…(⊙ˍ⊙)
Сделали?! Ну всё, теперь, мы точно готовы двигаться дальше…(¬‿¬)
Практика:
Вообще, всё интуитивно понятно, но пакеты тут, если что
(1) Я создал тут папочку для вас, в которую добавил новый статический класс.
(2) Так же добавляем в него юзинг установленной библиотеки для работы с IoC.
(3) В классе добавляем статический метод расширения для "IServiceCollection", где будет проходить наша регистрация сервисов
для последующего предоставления в качестве внешних зависимостей. На данный момент, там зарегистрированы: инстанс браузера и инстанс зенки.
(1) Ключевое слово “this”, в данном контексте, говорит нам о том, что это метод расширения, а расширяем мы "IServiceCollection".
То есть, когда в следующий раз, мы тыкнем « . » после объекта типа "IServiceCollection" (правильнее сказать, объекта, который реализовывает данный интерфейс,
но нам это знать сейчас не обязательно), то у нас будет доступен наш метод “AddApplication” в который мы должны будем передать "Instance" и "IZennoPosterProjectModel"
(первый параметры – IServiceCollection – передавать не нужно, поскольку, именно у его мы вызываем этот метод и он будет передан автоматически).
П.С. Методы расширения могут быть только в статическом классе и статическом методе.
(2) Тут мы добавляем/регистрируем наши сервисы/инстансы в рамках жизненного цикла называемого “Scoped”
(он, кстати, написан тоже, как метод расширения; это видно на всплывашке при наведении курсора на метод и ключевому слову “extension”).
Transient (AddTransient) - инстанс сервиса создается каждый раз, когда его запрашивают. Этот жизненный цикл лучше всего подходит для легковесных, не фиксирующих состояние, сервисов.
Scoped (AddScoped) - инстанс сервиса создается единожды для каждого запроса.
Singleton (AddSingleton) - инстанс сервиса создается при первом запросе (или при запуске ConfigureServices, если вы указываете инстанс там), а затем каждый последующий запрос будет использовать этот же инстанс.
Источник: Разница между AddTransient, AddScoped и AddSingleton в ASP.NET Core / Хабр (habr.com)
Могу ошибаться, но, в рамках зенки, "Scoped" и "Singleton" - будет практически одно и тоже.
Scoped (AddScoped) - инстанс сервиса создается единожды для каждого запроса.
Singleton (AddSingleton) - инстанс сервиса создается при первом запросе (или при запуске ConfigureServices, если вы указываете инстанс там), а затем каждый последующий запрос будет использовать этот же инстанс.
Источник: Разница между AddTransient, AddScoped и AddSingleton в ASP.NET Core / Хабр (habr.com)
Могу ошибаться, но, в рамках зенки, "Scoped" и "Singleton" - будет практически одно и тоже.
(4) Всё это входные параметры метода (сигнатура метода).
Ещё чуть-чуть разжую, на всякий…)
(1) Это сервисы, которые мы регистрируем.
(2) А это мы запихиваем готовые инстансы этих сервисов (обычно, контейнер сам нам создает и предоставляет инстансы, но, в данном случае,
нам нужны уже готовые, которые пришли прямиком из ZennoPoster или ProjectMaker).
Чтоб всё у нас завелось - я вернулся в наш класс “Program” и…
(1) Добавляем юзинг хостинга (пакета, который мы ранее должны были установить).
(2) Так же добавляем стандартный метод для создания хост билдера, в который передаём инстансы пришедшие из зенки.
(3) И именно тут используем наш, выше написанный, метод расширения.
“services” – это и есть тот самый первый параметр “IServiceCollection” (можете сами потом убедиться, наведя мышку на этот объект).
(4) Разумеется, вызываем метод для создания хост билдера.
(5) А следом вызываем и метод сборки.
Всё! Теперь наш контейнер сможет нам творить магию в виде инъекций инстансов зарегистрированных сервисов в конструкторы классов,
то бишь, будет предоставлять нам внешние зависимости (~ ̄▽ ̄)~
Собственно, толку пока не много, нужно вывести наш первый “Hello, world!”
«Hello, world!» в контейнере:
(1) Собственно, мы создали наш первый условный сервис (да, обычный класс).
(2) Добавили метод “Run”, который будем вызывать для старта сервиса (название может быть любым).
(3) Добавили конструктор класса, именно сюда IoC будет производить нашу инъекцию, когда мы обратимся к методу “Run”.
Заметьте, что у конструктора класса “0 references”, а это значит, что на него никто не ссылается, а он будет вызваться…
Что-то это, если не магия?! Атеистам шах и мат! (⊙_(⊙_⊙)_⊙)
(1) Теперь регистрируем созданный сервис в нашем регистраторе.
Опять же, обратите внимание, что никакого инстанса мы не пихаем,
IoC за нас будет создавать его и предоставлять конструктору нужные внешние зависимости.
Получается так, что в конструкторе сервиса (созданном нами классе) мы можем использовать любой порядок внешних зависимостей.
(1) Всё, теперь нам требуется просто запросить наш сервис у хоста (если быть точным, то у "IServiceProvider", который обитает в свойствах "IHost".
Не устану повторять: мы запрашиваем сервис у которого есть конструктор, но ничего не передаём для самого конструктора, IoC сам всё сделает исходя из конфига.
По поводу "IServiceProvider": мы так же можем использовать его в конструкторах не статических классов, если нам потребуется
выдернуть какой-то инстанс сервиса похожим образом, при этом, не нужно заранее регистрировать "IServiceProvider" в нашем конфиге, он уже зарегистрирован под капотом.
(2) И вызвать тот самый метод “Run”
Теперь просто запускаем проект в зенке и наблюдаем за нашим итоговым результатом - «Hello, world!» - в контейнере!
Задачка на подумать: это не обязательно, но, в идеале, теперь неплохо бы было избавиться от завязки на реализации,
и завязаться на абстракции, то есть, на интерфейсе, например “IHelloWorldService”, а как это сделать – придётся решать вам самим.
¯\_( ͡° ͜ʖ ͡°)_/¯
Резюме по Dependency Injection и IoC-контейнеру:
DI и IoC – вещи не сложные, но это прям то, что доктор прописал для больших проектов
планируемых расширяться в будущем (для мелких так же подойдёт), где есть куча зависимостей и сложной реализации и т.д.
Данный подход к разработке проекта: упрощает написание кода, делает его более гибким, поддерживаемым, расширяемым и более приятным.
К тому же, не нужно беспокоиться за стейт объектов и хранить всё по статическим переменным /ᐠ。ꞈ。ᐟ\
Резюме по кубику “Проект Visual Studio”:
Очевидно, что данная фича будет очень полезна тем, кто начал начал использовать C# в своих проектах.
Разработчики ZennoPoster делают шаги в правильном направлении (осталось открыть API для решения ReCaptcha2 из Visual Studio, - цены бы вам тогда не было).
Написание проектов в VS ускоряет и упрощает разработку за счёт умного "Интеллисенс", а "Nuget package manager" - открывает доступ к огромному количеству библиотек,
да и дебажить в студии просто волшебно (✿◡‿◡)
П.С. Это была моя первая статья, и это был лишь косплей на программиста, не судите строго...
Visual Studio 2022 v17.2.1
ZennoPoster v7.7.1.0 (это минимальная версия для поддержки 22-й студии)
ZennoPoster v7.7.1.0 (это минимальная версия для поддержки 22-й студии)
- Тема статьи
- Нестандартные хаки, Парсинг, Другое
- Номер конкурса статей
- Семнадцатый конкурс статей
Вложения
-
1 МБ Просмотры: 187
Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...
Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.
Последнее редактирование: