Wcf сервис что это

Windows Communication Foundation (WCF) служба

Давайте рассмотрим процесс создания и вызова службы WCF.

Создание службы WCF

Для начала необходимо создать новый проект WCF. Пусть наша Windows Communication Foundation служба будет возвращать количество оставшихся дней до нового года.

Wcf сервис что это. 996. Wcf сервис что это фото. Wcf сервис что это-996. картинка Wcf сервис что это. картинка 996

Visual studio создаст интерфейс и класс службы по умолчанию с именем IService1.cs и Service1.svc.

Wcf сервис что это. 520. Wcf сервис что это фото. Wcf сервис что это-520. картинка Wcf сервис что это. картинка 520

Нам необходимо переименовать их в соответствии с нашей предметной областью.

Wcf сервис что это. 905. Wcf сервис что это фото. Wcf сервис что это-905. картинка Wcf сервис что это. картинка 905

Давайте рассмотрим интерфейс INewYearService. Для начала нам необходимо в теле интерфейса объявить метод, который будет предоставлять служба для вызова. Для этого его необходимо пометить атрибутом [OperationContract].

Как вы видите данный метод возвращает экземпляр класса TimeToNewYear. Это вспомогательный класс, содержащий значения времени до нового года. Ниже приведена его структура. Для того, чтобы данный класс можно было использовать в качестве возвращаемого аргумента, его необходимо пометить атрибутом [DataContract], а свойства, доступные для чтения клиенту в возвращаемом значении помечаются атрибутом [DataMember].

Теперь нам остается реализовать интерфейс Windows Communication Foundation службы в классе NewYearService.svc.cs следующим образом:

Давайте проверим работу нашей службы wcf. Для этого нажмем кнопку Начать отладку. Обратите внимание, что возможные два варианта поведения системы. Если мы начнем отладку находясь в NewYearService.svc, от откроется отладчик службы. Во всех остальных случаях откроется окно браузера. Давайте рассмотрим каждый из вариантов подробнее.

Браузер

После запуска отладки отобразится браузер с файловой структурой нашей службы wcf.

Wcf сервис что это. 263. Wcf сервис что это фото. Wcf сервис что это-263. картинка Wcf сервис что это. картинка 263

Нам необходимо нажать на ссылку с именем нашей службы NewYearService.svc. Если все работает корректно, то мы увидим следующее окно, иначе будет показано сообщение с ошибкой.

Wcf сервис что это. 846. Wcf сервис что это фото. Wcf сервис что это-846. картинка Wcf сервис что это. картинка 846

Тестовый клиент WCF

Wcf сервис что это. 309. Wcf сервис что это фото. Wcf сервис что это-309. картинка Wcf сервис что это. картинка 309

В левой верхней части отладчика можно увидеть структура нашей службы wcf. Для проверки нашего метода выполним двойной щелчок левой кнопкой мыши по его имени. В правой части отладчика откроется форма запроса. Мы можем указать значение, которое будет передано в метод.

Wcf сервис что это. 228. Wcf сервис что это фото. Wcf сервис что это-228. картинка Wcf сервис что это. картинка 228

После установки передаваемых значений необходимо нажать кнопку Вызвать. Появится предупредительное сообщение. Можно смело ставить галочку Не выводить это сообщение в дальнейшем и нажимать кнопку ОК.

Wcf сервис что это. 610. Wcf сервис что это фото. Wcf сервис что это-610. картинка Wcf сервис что это. картинка 610

После этого в нижней правой части отладчика будет отображены значения возвращаемые нашей службой wcf.

Wcf сервис что это. 863. Wcf сервис что это фото. Wcf сервис что это-863. картинка Wcf сервис что это. картинка 863

Консольный клиент для WCF

Теперь нам необходимо создать клиент, который будет обращаться к нашей службе wcf. Для этого для начала создадим новое консольное приложение.

Wcf сервис что это. 583. Wcf сервис что это фото. Wcf сервис что это-583. картинка Wcf сервис что это. картинка 583

Wcf сервис что это. 819. Wcf сервис что это фото. Wcf сервис что это-819. картинка Wcf сервис что это. картинка 819

В созданном консольном приложении нам необходимо добавить ссылку на службу wcf.

Wcf сервис что это. 626. Wcf сервис что это фото. Wcf сервис что это-626. картинка Wcf сервис что это. картинка 626

В открывшимся окне службы необходимо указать имя службы wcf и ввести ее адрес.

Wcf сервис что это. 539. Wcf сервис что это фото. Wcf сервис что это-539. картинка Wcf сервис что это. картинка 539

Для простоты можно нажать кнопку Найти, тогда адрес службы wcf будет определен автоматически.

Wcf сервис что это. 601. Wcf сервис что это фото. Wcf сервис что это-601. картинка Wcf сервис что это. картинка 601

После этого необходимо развернуть дерево Windows Communication Foundation службы, чтобы удостоверится что выбран правильность выбора. В правой части должен быть отображен вызываемый метод.

Wcf сервис что это. 669. Wcf сервис что это фото. Wcf сервис что это-669. картинка Wcf сервис что это. картинка 669

Если настройка прошла корректно, то в обозревателе решения в консольном приложении отобразится ссылка на нашу службу wcf.

Wcf сервис что это. 591. Wcf сервис что это фото. Wcf сервис что это-591. картинка Wcf сервис что это. картинка 591

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

Перед началом отладки не забудьте установить консольное приложение автозагружаемым проектом. Получаем следующий результат.

Wcf сервис что это. 829. Wcf сервис что это фото. Wcf сервис что это-829. картинка Wcf сервис что это. картинка 829

Web клиент для WCF

Теперь рассмотрим, как нам обратиться к службе wcf из веб-приложения. Процесс подключения службы не отличается от подключения в консольном приложении. Давайте рассмотрим как можно настроить авторизацию с помощью Windows. Это потребует дополнительной настройки приложения. Для начала создадим проект нового MVC приложения.

Wcf сервис что это. 754. Wcf сервис что это фото. Wcf сервис что это-754. картинка Wcf сервис что это. картинка 754

Нажимаем кнопку ОК, и попадаем в меню настройки создания веб-приложения. Выберем MVC шаблон и изменим способ авторизации. Для этого нажмем на кнопку Изменить способ проверки подлинности.

Wcf сервис что это. 572. Wcf сервис что это фото. Wcf сервис что это-572. картинка Wcf сервис что это. картинка 572

Выбираем авторизацию с помощью Windows и нажимаем ОК в обоих окнах.

Wcf сервис что это. 883. Wcf сервис что это фото. Wcf сервис что это-883. картинка Wcf сервис что это. картинка 883

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

Для того, чтобы IISExpres перестала ругаться на нас за попытку создания windows-аутентификации нужно сделать ряд действий в наше службе.

Нужно дополнить наш web.config

Находим раздел и в нем вставляем следующее.

Далее нужно указать разделы биндинг и сервис

Раздел дополняем такой вот строчкой. В ней мы говорим, что именно такая схема аутентификации будет использоваться у нас.

На этом настройка web.config заканчивается. В итоге у нас должен получиться файл примерно следующего содержания.

Настройка applicationhost.config

Далее идем в папку vs нашего проекта (она скрыта по умолчанию). В ней ищем папку config, а уже в ней находим файл applicationhost.config, его то нам нужно будет поправить.

Wcf сервис что это. 326. Wcf сервис что это фото. Wcf сервис что это-326. картинка Wcf сервис что это. картинка 326

Находим вот такой раздел. Все Deny меняем на Allow, разрешая изменение установленного по умолчанию режима аутентификации.

Далее находим данную настройку. В ней false меняем на true, разрешая механизму работать.

И под конец находим вот эту настройку. Тут мы true меняем на false. Говоря нашему IISExpres, чтобы он не блокировал службу windows-аутентификации.

После этого сохраняем все конфигурационные файлы и пробуем сделать ссылку на службу wcf аналогично как при добавлении службы в консольное приложение.

Wcf сервис что это. 189. Wcf сервис что это фото. Wcf сервис что это-189. картинка Wcf сервис что это. картинка 189

Изменим контроллер главной страницы web-приложения, чтобы взывать нашу службу wcf.

Теперь нам осталось только изменить представление, чтобы вывести результат работы Windows Communication Foundation службы на экран пользователя.

Получаем следующий результат работы веб-приложения.

Wcf сервис что это. 646. Wcf сервис что это фото. Wcf сервис что это-646. картинка Wcf сервис что это. картинка 646

Итоги WCF

Исходный код приложения можно скачать из репозитория https://github.com/shwanoff/wcf.

Мы подробно рассмотрели процесс создания и настройки Windows Communication Foundation службы, а также продемонстрировали как можно подключится к wcf через консольное и веб-приложение. Также рекомендую прочитать статью Принципы SOLID C#. И не забудьте подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.

Источник

Действительно прозрачное использование WCF

Мотивация

По крайней мере, так должно быть. На практике добавление нового сервиса — это рутина. Нужно не забыть прописать конфигурацию на сервере, сделать то же самое на клиенте, нужно написать или сгенерировать proxy-класс. Поддерживать конфиги неудобно. Если сервис изменился, то нужно вносить изменения в proxy-класс. А ещё не забыть про регистрации в IoC-контейнере. И добавление новых хостов для новых сервисов. И еще хочется простой асинхронности. По отдельности всё просто, но даже для статьи я дописывал этот список уже трижды, и не уверен, что не упустил чего-нибудь.

Quick start

Создадим клиент-серверное приложение. Клиенты передают серверу индекс числа из последовательности Фибоначчи, сервер возвращает число из последовательности с заданным индексом. Из кода в статье убрано логирование и обработка ошибок, но в коде на github я привожу более полный пример для иллюстрации целостного подхода.
Структура проектов, приближенная к реальности:

Wcf сервис что это. d36990efb8754fff968fed27238ae44c. Wcf сервис что это фото. Wcf сервис что это-d36990efb8754fff968fed27238ae44c. картинка Wcf сервис что это. картинка d36990efb8754fff968fed27238ae44c

Server.Contracts содержит интерфейсы wcf-сервисов, Server — их реализацию, а так же реализацию хостера — класса, который будет поднимать wcf-сервисы. BL — логика сервера. ConsoleServiceHost хостит сервисы в домене консольного приложения. Client.Presentaion содержит соответствующий слой клиента. В нашем примере там только команда вызова сервиса и обработка результата. Client — консольное приложение, использующее предыдущую сборку для обработки ввода пользователя.

Реализация в CalculatorService.cs будет передавать запрос и возвращать результат из слоя бизнес-логики:

Пока можно заметить одну особенность — wcf-сервис использует async/await для описания асинхронности. В остальном никаких специфических конструкций нет.

Теперь перейдем к регистрации. Простейший синтаксис для сервера указывает тип привязки (NetTcp) список поведений, которые должны быть добавлены к сервисам:

Для клиента указывается тип обёртки-исполнителя для сервисов (ServiceExecutor), тип обёртки над привязкой (Standart предполагает NetTcp) и, собственно, адрес сервера:

Всё. Не нужно регистрировать каждый сервис по интерфейсу, не нужно создавать Proxy, не нужно прописывать wcf в конфигурации — эти регистрации позволят сразу начать работать с сервисами так, будто это локальные вызовы.
Но сначала нужно захостить их на сервере. Библиотека Rikrop.Core.Wcf уже включает класс ServiceHostManager, который сделает всю работу самостоятельно. Прописывать каждый сервис не нужно:

Wcf сервис что это. 7dc29752b09c4ed5abc345fdbb9271bb. Wcf сервис что это фото. Wcf сервис что это-7dc29752b09c4ed5abc345fdbb9271bb. картинка Wcf сервис что это. картинка 7dc29752b09c4ed5abc345fdbb9271bb

Сравнение с классическим подходом и расширяемость

Может показаться, что предложенное решение требует довольно много инфраструктурного кода и не несёт преимуществ перед обычным использованием wcf. Проще всего будет показать разницу на примере типовых ситуаций, возникающих при работе над проектами.

Добавление нового метода в существующий wcf-сервис или изменение сигнатуры существующего метода
Добавление нового wcf-сервиса в существующий хост
Изменение настроек всех wcf-сервисов (на примере типа привязки)
Изменение настроек нескольких wcf-сервисов (на примере типа привязки)

Расширяемость. Behavior для авторизации и работы с сессиями

Расширение функциональности и изменение поведения происходит за счёт добавления при регистрации Behavior. Наиболее частым в применении является поведение, отвечающее за передачу в заголовке wcf-сообщения информации о сессии.
Для демонстрации функционала был создан отдельный branch с расширенным кодом предыдущего примера. В стандартной настройке поведения разработчику предлагается выбрать метод авторизации — это OperationContract, который будет доступен пользователям без сессии в заголовке сообщения. Вызов остальных методов будет возможен только при заполненном заголовке.

Регистрация на сервере будет выглядеть следующим образом:

Можно изменить способ авторизации, добавив свою имплементацию System.ServiceModel.ServiceAuthorizationManager, изменить способ инициализации идентификатора сессии, метод проверки авторизации, способ извлечения сессии из контекста выполнения запроса, способ хранения и копирования сессий на сервере. В обобщенном случае регистрация AuthorizationBehavior может выглядеть следующим образом:

Клиентская регистрация так же меняется:

Wcf сервис что это. f78329ebdbb646fd9edff227ef74462d. Wcf сервис что это фото. Wcf сервис что это-f78329ebdbb646fd9edff227ef74462d. картинка Wcf сервис что это. картинка f78329ebdbb646fd9edff227ef74462d

Алгоритм работы

Что внутри

Большую часть инфраструктуры предоставляет библиотека System.ServiceModel.dll. Однако, есть несколько решений, которые нужно рассмотреть подробнее.

Основой взаимодействия между клиентом и сервером служат реализации интерфейса IServiceExecutor, находящиеся в библиотеке Rikrop.Core.Wcf.

В простейшем случае открывается канал и метод вызывается в контексте этого канала:

Более сложные реализации могут конвертировать ошибки или дополнительно извещать об окончании обработки изменением свойства. Наибольшее распространение эти идеи получили в WPF-реализациях IServiceExecutor, где с помощью ServiceExecutorFactory можно создать обёртки над wcf-сервисом, позволяющие использовать DataBinding для оповещения UI о продолжительной операции, или отображающие popup с произвольной информацией во время ожидания ответа от сервера.
Для легкой реализации главную роль играют Fluent interface при регистрации и стандартные реализации инфраструктуры библиотеки, из-за чего даже даже в самых сложных конструкциях легко разобраться с первого раза с помощью подскзок студии:

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Итоги

Единожды настроив инфраструктуру на проекте, можно надолго забыть о сетевой природе взаимодействия через IServiceExexutor. Лучше всего применять системный подход и использовать так же бибилиотки для построения настольных приложений с применением mvvm-паттерна, взаимодействия с БД, логирования и других типовых задач. Но даже при нежелании использовать незнакомый и не всегда привычный фреймворк, можно найти применение идеям, лежащим в его основе. Расширяемость компонент, строгая типизация при конфигурировании, прозрачность взаимодействия на всех слоях, минимизация инфраструктурного кода и затрат времени на поддержание инфрастурктуры — это то, о чём важно не забывать при написании калькулятора и многопользовательской Enterprise-системы. Можно скачать код библиотек и подключить их к решению проектом вместо использования библиотеки. Это позволит изучить работу под отладчиком и при необходимости внести свои изменения.

Бонус

Еще есть решение для wpf с информированием пользователя через блокировку ui или всплывающие окна, реализованные через ServiceExecutorFactory. Это частный пример и он относится куда больше к wpf, чем к wcf. Но это может дать больше информации о преимуществах библиотеки и мотивации к использованию.

Источник

Пример создания WCF-сервиса, работающего внутри службы Windows

Windows Communication Foundation – программная платформа от Microsoft для создания, настройки и развертывания распределенных сетевых сервисов. WCF-runtime и его пространство имен System.ServiceModel, представляющее его главный программный интерфейс, это преемник технологий создания распределенных систем, успешно применяемых разработчиками для создания распределенных приложений на платформе Windows в последнее десятилетие. Разберём тестовый пример создания WCF-сервиса.

Открываем Visual Studio 2015 и создаём новый проект типа Class Library. Проект назовём WCFMyServiceLibrary.

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Файл Class1.cs переименуем в MyService.cs и добавим ещё один класс, файл для которого назовём IMyService.cs.

Добавим ссылку на сборку System.ServiceModel.

На этом разработка сервиса завершена. Переходим к созданию службы Windows, которая будет контейнером для данного сервиса.

В том же решении (Solution) создадим новый проект типа «Служба Windows». Называем проект WindowsServiceHostForMyService.

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Затем файл Service1.cs (только что созданного проекта) переименуем в MyService.cs. В этот проект добавим ссылку на сборку System.ServiceModel, а также не забываем указывать в файле MyService.cs директивы:

В классе MyService добавляем новый член:

Также необходимо добавить ссылку на проект WCFMyServiceLibrary, который находится в этом же решении:

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Затем в классе MyService изменим метод OnStart таким образом, чтобы в этом методе добавлялись конечные точки нашего сервиса (endpoint):

Затем реализуем остановку сервиса в методе OnStop:

Затем в Обозревателе решения — двойной клик на файле MyService.cs (проекта WindowsServiceHostForMyService) откроет этот файл в режиме конструктора (Design Mode).

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

На пустом пространстве вызываем контекстное меню (щелчок правой кнопкой мыши) и выбираем «Добавить установщик».

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

При этом будет создан новый класс ProjectInstaller.cs
Переименуем файл ProjectInstaller.cs в MyServiceInstaller.cs.
При этом выйдет окно с вопросом, следует ли переименовать зависимые объекты – отвечаем «Да».

Добавим в файл ссылку

Затем изменим код конструктора класса MyServiceInstaller:

Заметим, что вызов метода InitializeComponent() мы заблокировали с помощью комментария.
На этом разработка службы Windows завершена. Собираем всё решение (Build Solution) и переходим к следующему этапу – установка службы Windows.

Для установки нашей службы создадим bat-файл (с произвольным названием, например Install_Windows_Service.bat) следующего содержания:

Нужно скопировать этот bat-файл в ту же папку, где находится скомпилированный файл WindowsServiceHostForMyService.exe (вам нужно заранее продумать, в какой папке будет лежать этот файл, который будет всегда запущен в качестве службы Windows).

Запускаем bat-файл, после чего наша программа WindowsServiceHostForMyService.exe будет установлена в качестве службы Windows.

Запустим эту службу с помощью стандартной программы управления службами.

Следующий этап – разработка клиентского приложения для использования предоставляемых сервисом услуг.

Для этого прежде всего нужно организовать так называемый «переходник» — Service Proxy – набор настроек, описывающих сервис для клиентского приложения.

Воспользуемся для этого стандартной утилитой SvcUtil.exe. Создадим файл Generate_Proxy.bat следующего содержания

Запустим этот файл (стандартная утилита SvcUtil.exe находится в папке C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin).

Этот файл нужно запустить во время работы нашего сервиса, т.е. в данном случае, после успешного запуска службы Windows WindowsServiceHostForMyService.

В случае успешного запуска, программа SvcUtil.exe сгенерирует 2 файла — MyServiceProxy.cs и App.config.

Эти файлы необходимо добавить для клиентского приложения, чтобы это приложение могло вызывать методы нашей службы (чуть ниже вы узнаете, что файл App.config я решил не добавлять — обойдёмся и без него).

Примечание. Аналогичного результата можно было добиться, запустив

Т.е. можно запускать эту утилиту, указав только одну конечную точку, либо http либо net.tcp.

В том же решении (Solution) создадим обычное приложение Windows Forms. Назовем его WindowsFormsApplication1

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Добавим в этот проект ссылку на System.ServiceModel и, конечно же,

Добавим в этот проект файл MyServiceProxy.cs (именно его мы сгенерировали утилитой SvcUtil.exe). При этом следует добавить в файл MyServiceProxy.cs следующие строки:

После этого, мы сможем ссылаться на класс MyServiceClient (этот класс создан программой SvcUtil.exe), указав в файле формы директиву.

Поступим неординарно – и не будем добавлять файл App.Config в проект клиента!

Затем набросаем на форму 3 кнопки, текстовое поле textBox1 (пользователь вводит сюда строку для отправки на сервер) и поле richTextbox1 (имитация подсистемы сообщений нашего приложения – именно в это поле будут поступать сообщения от программы, в том числе и те, что вернул нам сервис)

Кнопка btn_Start – создаёт клиента
Кнопка btn_Send – отправляет сервису текстовую строку из текстового поля
Кнопка btn_Close – удаляет клиента из памяти и закрывает приложение

Компилируем и запускаем с другой машины из той же сети – и тестируем сервис, нажав сначала btn_Start, а затем отправляя сервису сообщения нажатием btn_Send.

Wcf сервис что это. image loader. Wcf сервис что это фото. Wcf сервис что это-image loader. картинка Wcf сервис что это. картинка image loader

Заметим, что в данном примере на клиенте мы совсем не использовали конечную точку

http://localhost:9001/MyService
а работали только с

net.tcp://localhost:9002/MyService
(вы легко сможете это сделать самостоятельно – раз уж вам net.tcp по плечу, то уж http-то с закрытыми глазами сделаете).

Кроме того, мы не использовали файл App.config, создав на клиенте конечную точку не с помощью настроек, а с помощью кода C#. Причины тому – субъективные – автор не любит возиться с XML-настройками, а по возможности всё делает явно в коде. Спасибо за внимание!

Лирическое отступление. Автор статейки познакомился с языком C# в марте сего года, первое приложение на C# написал в мае (до этого много лет формошлёпил на Delphi и даже на MS Access).

Источник

Практическое руководство. Размещение службы WCF в управляемой службе Windows

в этом разделе описаны основные шаги, необходимые для создания службы Windows Communication Foundation (WCF), размещенной в службе Windows. этот сценарий включается параметром размещения управляемой службы Windows, который является длительно запущенной службой WCF, размещенной за пределами службы IIS (IIS) в безопасной среде, которая не является активируемой сообщением. Вместо этого время существования службы контролируется операционной системой. Данный вариант размещения доступен во всех версиях Windows.

Службами Windows можно управлять при помощи Microsoft.ManagementConsole.SnapIn в консоли управления (MMC) и можно настроить их автоматический запуск при загрузке системы. этот вариант размещения состоит из регистрации домена приложения (AppDomain), в котором размещена служба WCF, в качестве управляемой службы Windows, чтобы время существования процесса службы управлялось диспетчером управления службами (SCM) для служб Windows services.

Создание службы и предоставление кода размещения

создайте новый проект консольного приложения Visual Studio с именем Service.

Измените имя файла Program.cs на Service.cs.

Добавьте ссылки на следующие сборки:

Добавьте следующие операторы using в файл Service.cs.

Переопределите метод OnStart(String[]), создав и открыв новый экземпляр ServiceHost, как показано в следующем коде.

Переопределите метод OnStop, закрывающий ServiceHost, как показано в следующем коде.

Добавьте в проект файл конфигурации приложения. Замените содержимое этого файла следующим XML-кодом конфигурации.

Щелкните правой кнопкой мыши файл App.config в Обозреватель решений и выберите пункт свойства. В разделе Копировать в выходной каталог выберите Копировать, если новее.

Установка и запуск службы

Пример

Ниже приведен полный список кода, используемого в этом разделе.

Как и в случае резидентного размещения, среда размещения службы Windows требует, чтобы код размещения являлся частью приложения. Служба реализуется как консольное приложение и содержит собственный код размещения. В других средах размещения, таких как служба активации Windows (WAS), размещающих в IIS, писать код размещения необязательно.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *