<file_sep>﻿using System;
using System.IO;
using Logic;
using ZmqConnector;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Extensions.Logging;

namespace Application
{
    class Program
    {
        static void Main(string[] args)
        {
            var logger = LogManager.GetCurrentClassLogger();

            try
            {
                var configuration = BuildConfig();

                var servicesProvider = BuildDi(configuration);
                using (servicesProvider as IDisposable)
                {
                    var app = servicesProvider.GetRequiredService<Application>();
                    app.Start();
                }
            }
            catch (Exception e)
            {
                logger.Error(e, "Error");
                throw;
            }
            finally
            {
                LogManager.Shutdown();
            }
        }

        private static IConfiguration BuildConfig()
        {
            return new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false)
                .Build();
        }

        private static IServiceProvider BuildDi(IConfiguration config)
        {
            return new ServiceCollection()
                .Configure<ApplicationSettings>(config.GetSection("Application"))
                .Configure<ConnectionSettings>(config.GetSection("Connection"))
                .AddSingleton<Application>()
                .AddSingleton<ISender, Sender>()
                .AddSingleton<IReceiver, Receiver>()
                .AddSingleton<ITextOperations, TextOperations>()
                .AddLogging(loggingBuilder =>
                {
                    loggingBuilder.ClearProviders();
                    loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                    loggingBuilder.AddNLog(config);
                })
                .BuildServiceProvider();
        }
    }
}
<file_sep>﻿using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NetMQ;
using NetMQ.Sockets;

namespace ZmqConnector
{
    public class Receiver : IReceiver
    {
        private readonly ConnectionSettings _settings;

        private readonly ILogger<Receiver> _logger;

        public Receiver(IOptions<ConnectionSettings> settings, ILogger<Receiver> logger)
        {
            _settings = settings.Value;
            _logger = logger;
        }

        public void Run()
        {
            var subAddress = _settings.SubAddress;
            var pullAddress = _settings.PullAddress;
            var topic = _settings.SubTopic;

            using (var subscriber = new SubscriberSocket())
            using (var puller = new PullSocket())
            {
                subscriber.Connect(subAddress);
                subscriber.Subscribe(topic);
                _logger.LogInformation($"Sub socket on {subAddress} topic {topic}");

                puller.Connect(pullAddress);
                _logger.LogInformation($"Pull socket on {pullAddress}");

                using (var poller = new NetMQPoller { subscriber, puller })
                {
                    subscriber.ReceiveReady += SubReceiveReady;
                    puller.ReceiveReady += PullReceiveReady;

                    poller.Run();
                }
            }
        }

        private void SubReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            var message = e.Socket.ReceiveFrameString();

            _logger.LogTrace($"Sub: {message}");

            OnSubMessageReceived(new MessageReceivedEventArgs
            {
                Message = message
            });
        }

        private void PullReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            var message = e.Socket.ReceiveFrameString();

            _logger.LogTrace($"Pull: {message}");

            OnPullMessageReceived(new MessageReceivedEventArgs
            {
                Message = message
            });
        }

        protected virtual void OnSubMessageReceived(MessageReceivedEventArgs e)
        {
            var handler = SubMessageReceived;
            handler?.Invoke(this, e);
        }

        protected virtual void OnPullMessageReceived(MessageReceivedEventArgs e)
        {
            var handler = PullMessageReceived;
            handler?.Invoke(this, e);
        }

        public event EventHandler<MessageReceivedEventArgs> SubMessageReceived;
        public event EventHandler<MessageReceivedEventArgs> PullMessageReceived;
    }
}
<file_sep>﻿using System;

namespace ZmqConnector
{
    public class MessageReceivedEventArgs : EventArgs
    {
        public string Message { get; set; }
    }
}
<file_sep>﻿using System.Threading.Tasks;
using Logic;
using ZmqConnector;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Application
{
    public class Application
    {
        private readonly ApplicationSettings _settings;

        private readonly ILogger<Application> _logger;
        private readonly IReceiver _receiver;
        private readonly ISender _sender;
        private readonly ITextOperations _operations;

        public Application(IOptions<ApplicationSettings> settings, ILogger<Application> logger, IReceiver receiver, ISender sender, ITextOperations operations)
        {
            _settings = settings.Value;
            _logger = logger;
            _receiver = receiver;
            _sender = sender;
            _operations = operations;

            _receiver.SubMessageReceived += OnSubMessage;
            _receiver.PullMessageReceived += OnPullMessage;
            _sender.PushMessageSent += OnPushMessage;

            _logger.LogInformation(_settings.Tag);
        }

        public void Start()
        {
            var receiveTask = Task.Run(() =>
            {
                _receiver.Run();
            });

            _sender.Run();

            Task.WaitAll(receiveTask);
        }

        private void OnSubMessage(object sender, MessageReceivedEventArgs e)
        {
            // просто получаем длину сообщения
            var length = _operations.GetLength(e.Message);
            
            // и отправляем обратно
            _sender.SendMessage(length.ToString());
        }

        private void OnPullMessage(object sender, MessageReceivedEventArgs e)
        {
            // ...
        }

        private void OnPushMessage(object sender, MessageSentEventArgs e)
        {
            // ...
        }
    }
}
<file_sep>﻿using System;

namespace ZmqConnector
{
    public interface IReceiver
    {
        void Run();
        event EventHandler<MessageReceivedEventArgs> SubMessageReceived;
        event EventHandler<MessageReceivedEventArgs> PullMessageReceived;
    }
}
<file_sep>﻿using System;

namespace ZmqConnector
{
    public class MessageSentEventArgs : EventArgs
    {
        public string Message { get; set; }
    }
}
<file_sep>﻿namespace ZmqConnector
{
    /// <summary>
    /// Настройки ZMQ соединения
    /// </summary>
    public class ConnectionSettings
    {
        /// <summary>
        /// Протокол
        /// </summary>
        public string Protocol { get; set; }

        /// <summary>
        /// Имя хоста
        /// </summary>
        public string Host { get; set; }

        /// <summary>
        /// Номер порта Push
        /// </summary>
        public int PushPort { get; set; }

        /// <summary>
        /// Номер порта Pull
        /// </summary>
        public int PullPort { get; set; }

        /// <summary>
        /// Номер порта Sub
        /// </summary>
        public int SubPort { get; set; }

        /// <summary>
        /// Имя топика для подписки
        /// </summary>
        public string SubTopic { get; set; }

        /// <summary>
        /// Полный адрес Push сокета
        /// </summary>
        public string PushAddress => GetAddress(Protocol, Host, PushPort);

        /// <summary>
        /// Полный адрес Pull сокета
        /// </summary>
        public string PullAddress => GetAddress(Protocol, Host, PullPort);

        /// <summary>
        /// Полный адрес Sub сокета
        /// </summary>
        public string SubAddress => GetAddress(Protocol, Host, SubPort);

        private static string GetAddress(string protocol, string host, int port)
        {
            return $"{protocol}://{host}:{port}";
        }
    }
}
<file_sep>﻿namespace Logic
{
    public interface ITextOperations
    {
        int GetLength(string message);
    }
}
<file_sep>﻿using Microsoft.Extensions.Logging;

namespace Logic
{
    public class TextOperations : ITextOperations
    {
        private readonly ILogger<TextOperations> _logger;

        public TextOperations(ILogger<TextOperations> logger)
        {
            _logger = logger;
        }

        public int GetLength(string message)
        {
            var length = message.Length;

            _logger.LogTrace($"Message: '{message}',  length: {length}");

            return length;
        }
    }
}
<file_sep>﻿namespace Application
{
    public class ApplicationSettings
    {
        public string Tag { get; set; }
    }
}
<file_sep>﻿using System;

namespace ZmqConnector
{
    public interface ISender
    {
        void Run();
        void SendMessage(string message);
        event EventHandler<MessageSentEventArgs> PushMessageSent;
    }
}
<file_sep>﻿using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NetMQ;
using NetMQ.Sockets;

namespace ZmqConnector
{
    public class Sender : ISender
    {
        private readonly ConnectionSettings _settings;

        private readonly ILogger<Sender> _logger;

        private PushSocket Socket { get; }

        public Sender(IOptions<ConnectionSettings> settings, ILogger<Sender> logger)
        {
            _settings = settings.Value;
            _logger = logger;

            Socket = new PushSocket();
        }

        public void Run()
        {
            var pushAddress = _settings.PushAddress;
            Socket.Connect(pushAddress);
            _logger.LogInformation($"Push socket on {pushAddress}");
        }

        public void SendMessage(string message)
        {
            _logger.LogTrace($"Push: {message}");

            OnPushMessageSent(new MessageSentEventArgs
            {
                Message = message
            });
            Socket.SendFrame(message);
        }

        protected virtual void OnPushMessageSent(MessageSentEventArgs e)
        {
            var handler = PushMessageSent;
            handler?.Invoke(this, e);
        }

        public event EventHandler<MessageSentEventArgs> PushMessageSent;
    }
}
