pull/1/head
Ogoun 6 years ago
parent d30d681f0c
commit 0f47f1cc13

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net;
using System.Reflection; using System.Reflection;
using ZeroLevel.Network.Microservices; using ZeroLevel.Network.Microservices;
using ZeroLevel.Services.Network; using ZeroLevel.Services.Network;
@ -16,8 +15,7 @@ namespace ZeroLevel.Microservices
private static readonly ConcurrentDictionary<string, ExClient> _clientInstances = new ConcurrentDictionary<string, ExClient>(); private static readonly ConcurrentDictionary<string, ExClient> _clientInstances = new ConcurrentDictionary<string, ExClient>();
/// <summary> /// <summary>
/// Сканирование указанной сборки для поиска типов реализующих интерфейсы /// Scanning the specified assembly to find the types that implement the IExchangeServer or IExchangeClient interfaces
/// IExchangeServer или IExchangeClient
/// </summary> /// </summary>
internal static void ScanAndRegisterCustomTransport(Assembly asm) internal static void ScanAndRegisterCustomTransport(Assembly asm)
{ {
@ -41,16 +39,16 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Создает сервер для приема сообщений по указанному протоколу /// Creates a server to receive messages using the specified protocol
/// </summary> /// </summary>
/// <param name="protocol">Протокол</param> /// <param name="protocol">Protocol</param>
/// <returns>Сервер</returns> /// <returns>Server</returns>
internal static ExService GetServer(string protocol) internal static ExService GetServer(string protocol)
{ {
ExService instance = null; ExService instance = null;
if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase))
{ {
instance = new ExService(new ZExSocketObservableServer(new System.Net.IPEndPoint(IPAddress.Any, IPFinder.GetFreeTcpPort()))); instance = new ExService(new ZExSocketObservableServer(new System.Net.IPEndPoint(IPFinder.GetNonLoopbackAddress(), IPFinder.GetFreeTcpPort())));
} }
else else
{ {
@ -68,11 +66,11 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Создает клиента для обращений к серверу по указанному протоколу /// Creates a client to access the server using the specified protocol
/// </summary> /// </summary>
/// <param name="protocol">Протокол</param> /// <param name="protocol">Protocol</param>
/// <param name="endpoint">Адрес сервера</param> /// <param name="endpoint">Server endpoint</param>
/// <returns>Клиент</returns> /// <returns>Client</returns>
internal static ExClient GetClient(string protocol, string endpoint) internal static ExClient GetClient(string protocol, string endpoint)
{ {
ExClient instance = null; ExClient instance = null;
@ -85,6 +83,7 @@ namespace ZeroLevel.Microservices
return instance; return instance;
} }
_clientInstances.TryRemove(cachee_key, out instance); _clientInstances.TryRemove(cachee_key, out instance);
instance.Dispose();
instance = null; instance = null;
} }
if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase)) if (protocol.Equals("socket", StringComparison.OrdinalIgnoreCase))

@ -1 +1 @@
02ab5562f7a9f633d41e073aff759527ff59696c 4f0bbfe8ac44b56784f7eeaa3cdef96609d6b97e

@ -115,11 +115,7 @@ namespace ZeroLevel.ProxyREST
} }
catch (Exception ex) catch (Exception ex)
{ {
var line = string.Format("Сбой запроса ресурса {0} методом {1}. Код ошибки: {2}. Комментарий: {3}", var line = $"Resource request failed. [{method}] {resource}. Error code: {(statusCode ?? "Uncknown")}. Comment: {(reason ?? ex.Message)}";
resource,
method,
statusCode ?? "Uncknown",
reason ?? ex.Message);
Log.Error(ex, line); Log.Error(ex, line);
throw new InvalidOperationException(line, ex); throw new InvalidOperationException(line, ex);
} }

@ -253,12 +253,12 @@ namespace ZeroLevel.Microservices
#region Inboxes #region Inboxes
/// <summary> /// <summary>
/// Регистрация обработчика входящих сообщений /// Registering an Inbox Handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="protocol">Транспортный протокол</param> /// <param name="protocol">Protocol</param>
/// <param name="inbox">Имя точки приема</param> /// <param name="inbox">Inbox name</param>
/// <param name="handler">Обработчик</param> /// <param name="handler">Handler</param>
private void RegisterHandler<T>(MetaService meta, string inbox, Action<T, long, IZBackward> handler) private void RegisterHandler<T>(MetaService meta, string inbox, Action<T, long, IZBackward> handler)
{ {
if (_disposed) return; if (_disposed) return;
@ -273,13 +273,13 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Регистрация метода отдающего ответ на входящий запрос /// Registration method responding to an incoming request
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип входного сообщения</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="protocol">Транспортный протокол</param> /// <param name="protocol">Protocol</param>
/// <param name="inbox">Имя точки приема</param> /// <param name="inbox">Inbox name</param>
/// <param name="replier">Обработчик</param> /// <param name="replier">Handler</param>
private void RegisterReplier<Treq, Tresp>(MetaService meta, string inbox, Func<Treq, long, IZBackward, Tresp> handler) private void RegisterReplier<Treq, Tresp>(MetaService meta, string inbox, Func<Treq, long, IZBackward, Tresp> handler)
{ {
if (_disposed) return; if (_disposed) return;
@ -294,12 +294,12 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Регистрация метода отдающего ответ на входящий запрос, не принимающего входящих данных /// Registration of the method of responding to the incoming request, not receiving incoming data
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="protocol">Транспортный протокол</param> /// <param name="protocol">Protocol</param>
/// <param name="inbox">Имя точки приема</param> /// <param name="inbox">Inbox name</param>
/// <param name="replier">Обработчик</param> /// <param name="replier">Handler</param>
private void RegisterReplierWithNoRequestBody<Tresp>(MetaService meta, string inbox, Func<long, IZBackward, Tresp> handler) private void RegisterReplierWithNoRequestBody<Tresp>(MetaService meta, string inbox, Func<long, IZBackward, Tresp> handler)
{ {
if (_disposed) return; if (_disposed) return;

@ -10,7 +10,7 @@ using ZeroLevel.Services.Network;
namespace ZeroLevel.Microservices namespace ZeroLevel.Microservices
{ {
/// <summary> /// <summary>
/// Обеспечивает обмен данными между сервисами /// Provides data exchange between services
/// </summary> /// </summary>
public sealed class Exchange : public sealed class Exchange :
IDisposable IDisposable
@ -29,7 +29,7 @@ namespace ZeroLevel.Microservices
#endregion Ctor #endregion Ctor
/// <summary> /// <summary>
/// Регистрация сервиса /// Registration service
/// </summary> /// </summary>
public IExService RegisterService(IExchangeService service) public IExService RegisterService(IExchangeService service)
{ {
@ -44,11 +44,11 @@ namespace ZeroLevel.Microservices
#region Balanced send #region Balanced send
/// <summary> /// <summary>
/// Отправка сообщения сервису /// Sending a message to the service
/// </summary> /// </summary>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="inbox">Имя точки приема сообщений</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns></returns> /// <returns></returns>
public bool Send<T>(string serviceKey, string inbox, T data) public bool Send<T>(string serviceKey, string inbox, T data)
{ {
@ -262,13 +262,13 @@ namespace ZeroLevel.Microservices
#region Broadcast #region Broadcast
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам с указанным ключом в указанный обработчик /// Sending a message to all services with the specified key to the specified handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcast<T>(string serviceKey, string inbox, T data) public bool SendBroadcast<T>(string serviceKey, string inbox, T data)
{ {
try try
@ -296,22 +296,22 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам с указанным ключом, в обработчик по умолчанию /// Sending a message to all services with the specified key, to the default handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcast<T>(string serviceKey, T data) => SendBroadcast(serviceKey, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data); public bool SendBroadcast<T>(string serviceKey, T data) => SendBroadcast(serviceKey, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data);
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам конкретного типа в указанный обработчик /// Sending a message to all services of a specific type to the specified handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcastByType<T>(string serviceType, string inbox, T data) public bool SendBroadcastByType<T>(string serviceType, string inbox, T data)
{ {
try try
@ -339,23 +339,23 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам конкретного типа, в обработчик по умолчанию /// Sending a message to all services of a particular type, to the default handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcastByType<T>(string serviceType, T data) => public bool SendBroadcastByType<T>(string serviceType, T data) =>
SendBroadcastByType(serviceType, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data); SendBroadcastByType(serviceType, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data);
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам конкретной группы в указанный обработчик /// Sending a message to all services of a specific group to the specified handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Сообщение</param> /// <param name="data">Message</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcastByGroup<T>(string serviceGroup, string inbox, T data) public bool SendBroadcastByGroup<T>(string serviceGroup, string inbox, T data)
{ {
try try
@ -383,25 +383,25 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Отправка сообщения всем сервисам конкретной группы, в обработчик по умолчанию /// Sending a message to all services of a specific group in the default handler
/// </summary> /// </summary>
/// <typeparam name="T">Тип сообщения</typeparam> /// <typeparam name="T">Message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="data">Сообщение</param> /// <param name="data">Messsage</param>
/// <returns>true - при успешной отправке</returns> /// <returns>true - on successful submission</returns>
public bool SendBroadcastByGroup<T>(string serviceGroup, T data) => public bool SendBroadcastByGroup<T>(string serviceGroup, T data) =>
SendBroadcastByGroup(serviceGroup, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data); SendBroadcastByGroup(serviceGroup, ZBaseNetwork.DEFAULT_MESSAGE_INBOX, data);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по ключу /// Broadcast polling services by key
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcast<Treq, Tresp>(string serviceKey, string inbox, Treq data) public IEnumerable<Tresp> RequestBroadcast<Treq, Tresp>(string serviceKey, string inbox, Treq data)
{ {
try try
@ -417,13 +417,13 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по ключу, без сообщеня запроса /// Broadcast polling services by key, without message request
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcast<Tresp>(string serviceKey, string inbox) public IEnumerable<Tresp> RequestBroadcast<Tresp>(string serviceKey, string inbox)
{ {
try try
@ -439,37 +439,37 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по ключу, в обработчик по умолчанию /// Broadcast polling services by key, to default handler
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcast<Treq, Tresp>(string serviceKey, Treq data) => public IEnumerable<Tresp> RequestBroadcast<Treq, Tresp>(string serviceKey, Treq data) =>
RequestBroadcast<Treq, Tresp>(serviceKey, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data); RequestBroadcast<Treq, Tresp>(serviceKey, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по ключу, без сообщеня запроса, в обработчик по умолчанию /// Broadcast polling of services by key, without message of request, to default handler
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceKey">Ключ сервиса</param> /// <param name="serviceKey">Service key</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcast<Tresp>(string serviceKey) => public IEnumerable<Tresp> RequestBroadcast<Tresp>(string serviceKey) =>
RequestBroadcast<Tresp>(serviceKey, ZBaseNetwork.DEFAULT_REQUEST_INBOX); RequestBroadcast<Tresp>(serviceKey, ZBaseNetwork.DEFAULT_REQUEST_INBOX);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по типу сервису /// Broadcast polling services by type of service
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByType<Treq, Tresp>(string serviceType, string inbox, Treq data) public IEnumerable<Tresp> RequestBroadcastByType<Treq, Tresp>(string serviceType, string inbox, Treq data)
{ {
try try
@ -485,13 +485,13 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по типу сервису, без сообщеня запроса /// Broadcast polling of services by type of service, without a request message
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByType<Tresp>(string serviceType, string inbox) public IEnumerable<Tresp> RequestBroadcastByType<Tresp>(string serviceType, string inbox)
{ {
try try
@ -507,37 +507,37 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по типу сервису, в обработчик по умолчанию /// Broadcast polling services by type of service, in the default handler
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByType<Treq, Tresp>(string serviceType, Treq data) => public IEnumerable<Tresp> RequestBroadcastByType<Treq, Tresp>(string serviceType, Treq data) =>
RequestBroadcastByType<Treq, Tresp>(serviceType, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data); RequestBroadcastByType<Treq, Tresp>(serviceType, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по типу, без сообщеня запроса, в обработчик по умолчанию /// Broadcast polling services by type, without message request, in the default handler
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceType">Тип сервиса</param> /// <param name="serviceType">Service type</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByType<Tresp>(string serviceType) => public IEnumerable<Tresp> RequestBroadcastByType<Tresp>(string serviceType) =>
RequestBroadcastByType<Tresp>(serviceType, ZBaseNetwork.DEFAULT_REQUEST_INBOX); RequestBroadcastByType<Tresp>(serviceType, ZBaseNetwork.DEFAULT_REQUEST_INBOX);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по группе сервисов /// Broadcast polling services for a group of services
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByGroup<Treq, Tresp>(string serviceGroup, string inbox, Treq data) public IEnumerable<Tresp> RequestBroadcastByGroup<Treq, Tresp>(string serviceGroup, string inbox, Treq data)
{ {
try try
@ -553,13 +553,13 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по группе сервисов, без сообщения запроса /// Broadcast polling services for a group of services, without prompting
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="inbox">Имя обработчика</param> /// <param name="inbox">Inbox name</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByGroup<Tresp>(string serviceGroup, string inbox) public IEnumerable<Tresp> RequestBroadcastByGroup<Tresp>(string serviceGroup, string inbox)
{ {
try try
@ -575,24 +575,24 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по группе сервисов в обработчик по умолчанию /// Broadcast polling services by service group to default handler
/// </summary> /// </summary>
/// <typeparam name="Treq">Тип запроса</typeparam> /// <typeparam name="Treq">Request message type</typeparam>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="data">Запрос</param> /// <param name="data">Request message</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByGroup<Treq, Tresp>(string serviceGroup, Treq data) => public IEnumerable<Tresp> RequestBroadcastByGroup<Treq, Tresp>(string serviceGroup, Treq data) =>
RequestBroadcastByGroup<Treq, Tresp>(serviceGroup, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data); RequestBroadcastByGroup<Treq, Tresp>(serviceGroup, ZBaseNetwork.DEFAULT_REQUEST_INBOX, data);
/// <summary> /// <summary>
/// Широковещательный опрос сервисов по группе сервисов, без сообщения запроса, в обработчик по умолчанию ///Broadcast polling services for a group of services, without sending a request, to the default handler
/// </summary> /// </summary>
/// <typeparam name="Tresp">Тип ответа</typeparam> /// <typeparam name="Tresp">Response message type</typeparam>
/// <param name="serviceGroup">Группа сервиса</param> /// <param name="serviceGroup">Service group</param>
/// <param name="responseHandler">Обработчик ответа</param> /// <param name="responseHandler">Response handler</param>
/// <returns>true - в случае успешной рассылки</returns> /// <returns>true - in case of successful mailing</returns>
public IEnumerable<Tresp> RequestBroadcastByGroup<Tresp>(string serviceGroup) => public IEnumerable<Tresp> RequestBroadcastByGroup<Tresp>(string serviceGroup) =>
RequestBroadcastByGroup<Tresp>(serviceGroup, ZBaseNetwork.DEFAULT_REQUEST_INBOX); RequestBroadcastByGroup<Tresp>(serviceGroup, ZBaseNetwork.DEFAULT_REQUEST_INBOX);

@ -15,8 +15,7 @@ namespace ZeroLevel.Microservices
private static readonly ConcurrentDictionary<string, ExClient> _clientInstances = new ConcurrentDictionary<string, ExClient>(); private static readonly ConcurrentDictionary<string, ExClient> _clientInstances = new ConcurrentDictionary<string, ExClient>();
/// <summary> /// <summary>
/// Сканирование указанной сборки для поиска типов реализующих интерфейсы /// Scanning the specified assembly to find the types that implement the IExchangeServer or IExchangeClient interfaces
/// IExchangeServer или IExchangeClient
/// </summary> /// </summary>
internal static void ScanAndRegisterCustomTransport(Assembly asm) internal static void ScanAndRegisterCustomTransport(Assembly asm)
{ {
@ -40,10 +39,10 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Создает сервер для приема сообщений по указанному протоколу /// Creates a server to receive messages using the specified protocol
/// </summary> /// </summary>
/// <param name="protocol">Протокол</param> /// <param name="protocol">Protocol</param>
/// <returns>Сервер</returns> /// <returns>Server</returns>
internal static ExService GetServer(string protocol) internal static ExService GetServer(string protocol)
{ {
ExService instance = null; ExService instance = null;
@ -67,11 +66,11 @@ namespace ZeroLevel.Microservices
} }
/// <summary> /// <summary>
/// Создает клиента для обращений к серверу по указанному протоколу /// Creates a client to access the server using the specified protocol
/// </summary> /// </summary>
/// <param name="protocol">Протокол</param> /// <param name="protocol">Protocol</param>
/// <param name="endpoint">Адрес сервера</param> /// <param name="endpoint">Server endpoint</param>
/// <returns>Клиент</returns> /// <returns>Client</returns>
internal static ExClient GetClient(string protocol, string endpoint) internal static ExClient GetClient(string protocol, string endpoint)
{ {
ExClient instance = null; ExClient instance = null;

@ -28,7 +28,6 @@ namespace ZeroLevel.Microservices
#endregion WebAPI #endregion WebAPI
// Таблица по ключам
private readonly ConcurrentDictionary<string, RoundRobinCollection<ServiceEndpointInfo>> _tableByKey = private readonly ConcurrentDictionary<string, RoundRobinCollection<ServiceEndpointInfo>> _tableByKey =
new ConcurrentDictionary<string, RoundRobinCollection<ServiceEndpointInfo>>(); new ConcurrentDictionary<string, RoundRobinCollection<ServiceEndpointInfo>>();

@ -1 +1 @@
1a68033c72e3e719a45c8165f48f4effb88b5e68 48781ba1f58e845d50aedda0cbff5881dfe0563f

@ -92,20 +92,20 @@ namespace ZeroLevel.Services.Config
#region Get #region Get
/// <summary> /// <summary>
/// Получение списка значение соотвествующих указанному ключу /// Getting a list of the value corresponding to the specified key
/// </summary> /// </summary>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>Список значений</returns> /// <returns>Values list</returns>
public IEnumerable<string> Items(string key) public IEnumerable<string> Items(string key)
{ {
return this[key]; return this[key];
} }
/// <summary> /// <summary>
/// Получение первого значения для указанного ключа /// Getting the first value for the specified key
/// </summary> /// </summary>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>Первое значение, или null если ключ есть, но нет значений, или KeyNotFoundException если нет ключа</returns> /// <returns>The first value, or null if the key is, but there are no values, or KeyNotFoundException if there is no key</returns>
public string First(string key) public string First(string key)
{ {
IList<string> result; IList<string> result;
@ -135,11 +135,11 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Получение первого значения для указанного ключа, с попыткой преобразования в указанный тип /// Getting the first value for the specified key, with an attempt to convert to the specified type
/// </summary> /// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam> /// <typeparam name="T">Expected type</typeparam>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>Первое значение, или default(T) если ключ есть, но нет значений, или KeyNotFoundException если нет ключа</returns> /// <returns>The first value, or default (T) if there is a key but no values, or KeyNotFoundException if there is no key</returns>
public T First<T>(string key) public T First<T>(string key)
{ {
IList<string> result; IList<string> result;
@ -153,11 +153,11 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию /// First value, or Default value if no value or key
/// </summary> /// </summary>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <param name="defaultValue">Значение по умолчанию</param> /// <param name="defaultValue">Default value</param>
/// <returns>Первое значение, или значение по умолчанию если нет значений или ключа</returns> /// <returns>First value, or Default value if no value or key</returns>
public string FirstOrDefault(string key, string defaultValue) public string FirstOrDefault(string key, string defaultValue)
{ {
IList<string> result; IList<string> result;
@ -170,11 +170,11 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип /// Getting the first value for the specified key, or defaults, with an attempt to convert to the specified type
/// </summary> /// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam> /// <typeparam name="T">Expected type</typeparam>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>Первое значение, или default(T) если нет значений или ключа</returns> /// <returns>The first value, or default (T) if there are no values or a key</returns>
public T FirstOrDefault<T>(string key) public T FirstOrDefault<T>(string key)
{ {
IList<string> result; IList<string> result;
@ -187,12 +187,12 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Получение первого значения для указанного ключа, или значения по умолчанию, с попыткой преобразования в указанный тип /// Getting the first value for the specified key, or defaults, with an attempt to convert to the specified type
/// </summary> /// </summary>
/// <typeparam name="T">Ожидаемый тип</typeparam> /// <typeparam name="T">Expected type</typeparam>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <param name="defaultValue">Значение по умолчанию</param> /// <param name="defaultValue">Default value</param>
/// <returns>Первое значение, или значение по умолчанию если нет значений или ключа</returns> /// <returns>First value, or Default value if no value or key</returns>
public T FirstOrDefault<T>(string key, T defaultValue) public T FirstOrDefault<T>(string key, T defaultValue)
{ {
IList<string> result; IList<string> result;
@ -205,10 +205,10 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Проверка наличия ключа и непустого списка связанных с ним значений /// Check for the presence of a key and a non-empty list of values associated with it
/// </summary> /// </summary>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>true - если существует ключ и есть хотя бы одно значение</returns> /// <returns>true - if a key exists and there is at least one value</returns>
public bool Contains(string key) public bool Contains(string key)
{ {
key = GetKey(key); key = GetKey(key);
@ -216,7 +216,7 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Проверка наличия одного из ключей /// Check for one of the keys
/// </summary> /// </summary>
public bool Contains(params string[] keys) public bool Contains(params string[] keys)
{ {
@ -226,11 +226,8 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Проверка наличия ключа и связанного с ним значения /// Check for the presence of a key and its associated value
/// </summary> /// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool ContainsValue(string key, string value) public bool ContainsValue(string key, string value)
{ {
IList<string> result; IList<string> result;
@ -242,10 +239,10 @@ namespace ZeroLevel.Services.Config
} }
/// <summary> /// <summary>
/// Количество значений связанных с указанным ключом /// The number of values associated with the specified key
/// </summary> /// </summary>
/// <param name="key">Ключ</param> /// <param name="key">Key</param>
/// <returns>Количество значений</returns> /// <returns>Number of values</returns>
public int Count(string key) public int Count(string key)
{ {
key = GetKey(key); key = GetKey(key);

@ -125,48 +125,48 @@ namespace ZeroLevel
#region Read configuration #region Read configuration
/// <summary> /// <summary>
/// Создание конфигурации из секции AppSettings файла app.config или web.config /// Creating a configuration from the AppSettings section of the app.config or web.config file
/// </summary> /// </summary>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfiguration ReadFromApplicationConfig() { return new ApplicationConfigReader().ReadConfiguration(); } public static IConfiguration ReadFromApplicationConfig() { return new ApplicationConfigReader().ReadConfiguration(); }
/// <summary> /// <summary>
/// Создание конфигурации из секции AppSettings файла app.config или web.config, дополняется секцией 'ConnectionStrings' /// Creating a configuration from the AppSettings section of the app.config file or web.config, is supplemented by the 'ConnectionStrings' section
/// </summary> /// </summary>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfigurationSet ReadSetFromApplicationConfig() { return new ApplicationConfigReader().ReadConfigurationSet(); } public static IConfigurationSet ReadSetFromApplicationConfig() { return new ApplicationConfigReader().ReadConfigurationSet(); }
/// <summary> /// <summary>
/// Создание конфигурации из секции AppSettings файла app.config или web.config /// Creating a configuration from the AppSettings section of the app.config or web.config file
/// </summary> /// </summary>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfiguration ReadFromApplicationConfig(string configFilePath) { return new ApplicationConfigReader(configFilePath).ReadConfiguration(); } public static IConfiguration ReadFromApplicationConfig(string configFilePath) { return new ApplicationConfigReader(configFilePath).ReadConfiguration(); }
/// <summary> /// <summary>
/// Создание конфигурации из секции AppSettings файла app.config или web.config, дополняется секцией 'ConnectionStrings' /// Creating a configuration from the AppSettings section of the app.config file or web.config, is supplemented by the 'ConnectionStrings' section
/// </summary> /// </summary>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfigurationSet ReadSetFromApplicationConfig(string configFilePath) { return new ApplicationConfigReader(configFilePath).ReadConfigurationSet(); } public static IConfigurationSet ReadSetFromApplicationConfig(string configFilePath) { return new ApplicationConfigReader(configFilePath).ReadConfigurationSet(); }
/// <summary> /// <summary>
/// Создание конфигурации из ini файла /// Create configuration from ini file
/// </summary> /// </summary>
/// <param name="path">Путь к ini-файлу</param> /// <param name="path">Path to the ini file</param>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfiguration ReadFromIniFile(string path) { return new IniFileReader(path).ReadConfiguration(); } public static IConfiguration ReadFromIniFile(string path) { return new IniFileReader(path).ReadConfiguration(); }
/// <summary> /// <summary>
/// Создание конфигурации из ini файла, с учетом секций /// Creating a configuration from an ini file, including sections
/// </summary> /// </summary>
/// <param name="path">Путь к ini-файлу</param> /// <param name="path">Path to the ini file</param>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfigurationSet ReadSetFromIniFile(string path) { return new IniFileReader(path).ReadConfigurationSet(); } public static IConfigurationSet ReadSetFromIniFile(string path) { return new IniFileReader(path).ReadConfigurationSet(); }
/// <summary> /// <summary>
/// Создание конфигурации из параметров командной строки /// Creating configuration from command line parameters
/// </summary> /// </summary>
/// <param name="args">Параметры командной строки</param> /// <param name="args">Command line parameters</param>
/// <returns>Конфигурация</returns> /// <returns>Configuration</returns>
public static IConfiguration ReadFromCommandLine(string[] args) { return new CommandLineReader(args).ReadConfiguration(); } public static IConfiguration ReadFromCommandLine(string[] args) { return new CommandLineReader(args).ReadConfiguration(); }
public static IConfigurationSet ReadBinary(IBinaryReader reader) public static IConfigurationSet ReadBinary(IBinaryReader reader)
@ -179,17 +179,17 @@ namespace ZeroLevel
#region Write configuration #region Write configuration
/// <summary> /// <summary>
/// Запись простой конфигурации в ini-файл /// Write a simple configuration to the ini file
/// </summary> /// </summary>
/// <param name="configuration">Конфигурация</param> /// <param name="configuration">Configuration</param>
/// <param name="path">Путь к ini-файлу</param> /// <param name="path">Path to the ini file</param>
public static void WriteToIniFile(IConfiguration configuration, string path) { new IniFileWriter(path).WriteConfiguration(configuration); } public static void WriteToIniFile(IConfiguration configuration, string path) { new IniFileWriter(path).WriteConfiguration(configuration); }
/// <summary> /// <summary>
/// Запись полной конфигурации в ini-файл /// Write the complete configuration to the ini-file
/// </summary> /// </summary>
/// <param name="configuration">Конфигурация</param> /// <param name="configuration">Configuration</param>
/// <param name="path">Путь к ini-файлу</param> /// <param name="path">Path to the ini file</param>
public static void WriteSetToIniFile(IConfigurationSet configuration, string path) { new IniFileWriter(path).WriteConfigurationSet(configuration); } public static void WriteSetToIniFile(IConfigurationSet configuration, string path) { new IniFileWriter(path).WriteConfigurationSet(configuration); }
#endregion Write configuration #endregion Write configuration

@ -51,8 +51,8 @@ namespace ZeroLevel
/// <summary> /// <summary>
/// Get configuration section by name /// Get configuration section by name
/// </summary> /// </summary>
/// <param name="sectionName">Название секции</param> /// <param name="sectionName">Section name</param>
/// <returns>Секция с данными</returns> /// <returns>Data section</returns>
IConfiguration GetSection(string sectionName); IConfiguration GetSection(string sectionName);
/// <summary> /// <summary>
@ -79,7 +79,7 @@ namespace ZeroLevel
/// <summary> /// <summary>
/// Remove a prohibition on changing configurations /// Remove a prohibition on changing configurations
/// </summary> /// </summary>
/// <returns>false - если запрет снят</returns> /// <returns>false - if the prohibition is removed</returns>
bool UnfreezeConfiguration(); bool UnfreezeConfiguration();
/// <summary> /// <summary>

@ -5,7 +5,7 @@ using System.IO;
namespace ZeroLevel.Services.Config.Implementation namespace ZeroLevel.Services.Config.Implementation
{ {
/// <summary> /// <summary>
/// Чтение конфигурации из ini файла /// Reading configuration from ini file
/// </summary> /// </summary>
internal sealed class IniFileReader internal sealed class IniFileReader
: IConfigurationReader : IConfigurationReader

@ -7,7 +7,7 @@
TToken TToken
{ {
/// <summary> /// <summary>
/// Имя элемента /// Element name
/// </summary> /// </summary>
public string ElementName; public string ElementName;

@ -15,7 +15,7 @@ namespace ZeroLevel.Services.Extensions
*/ */
/// <summary> /// <summary>
/// Каррирование /// Currying
/// </summary> /// </summary>
public static Func<A, Func<B, R>> Curry<A, B, R>(this Func<A, B, R> f) public static Func<A, Func<B, R>> Curry<A, B, R>(this Func<A, B, R> f)
{ {
@ -28,7 +28,7 @@ namespace ZeroLevel.Services.Extensions
*/ */
/// <summary> /// <summary>
/// Частичное исполнение /// Partial currying
/// </summary> /// </summary>
public static Func<B, R> Partial<A, B, R>(this Func<A, B, R> f, A a) public static Func<B, R> Partial<A, B, R>(this Func<A, B, R> f, A a)
{ {

@ -159,7 +159,7 @@ namespace ZeroLevel.Services.FileSystem
} }
/// <summary> /// <summary>
/// Файловый архив /// File archive
/// </summary> /// </summary>
public sealed class FileArchive : public sealed class FileArchive :
IDisposable IDisposable
@ -457,7 +457,7 @@ namespace ZeroLevel.Services.FileSystem
} }
/// <summary> /// <summary>
/// Сохранение данных в бинарном виде в архив /// Saving data in binary form in the archive
/// </summary> /// </summary>
/// <param name="data">Data</param> /// <param name="data">Data</param>
/// <param name="name">Archive file name (HH_mm_ss_fff_counter.{ext} by default)</param> /// <param name="name">Archive file name (HH_mm_ss_fff_counter.{ext} by default)</param>

@ -81,12 +81,12 @@ namespace ZeroLevel.Services.Impersonation
} }
/// <summary> /// <summary>
/// Вход от имени указанного пользователя с указанием способа авторизации /// Login on behalf of the specified user with the authorization method
/// </summary> /// </summary>
/// <param name="userName">Имя пользователя</param> /// <param name="userName">Login</param>
/// <param name="domain">Домен</param> /// <param name="domain">Domain</param>
/// <param name="password">Пароль</param> /// <param name="password">Password</param>
/// <param name="logonType">Тип авторизации</param> /// <param name="logonType">Authorization Type</param>
public void ImpersonateByUser(String userName, String domain, String password, ImpersonationNativeMethods.LogonType logonType) public void ImpersonateByUser(String userName, String domain, String password, ImpersonationNativeMethods.LogonType logonType)
{ {
MySafeTokenHandle token; MySafeTokenHandle token;
@ -101,9 +101,9 @@ namespace ZeroLevel.Services.Impersonation
} }
/// <summary> /// <summary>
/// Копирование прав указанного процесса /// Copying the rights of the specified process
/// </summary> /// </summary>
/// <param name="ProcessName">Имя процесса</param> /// <param name="ProcessName">Process name</param>
public void ImpersonateByProcess(string ProcessName) public void ImpersonateByProcess(string ProcessName)
{ {
Process[] myProcesses = Process.GetProcesses(); Process[] myProcesses = Process.GetProcesses();

@ -10,11 +10,11 @@ namespace ZeroLevel.Services.Network
void RegisterInbox<T>(string inbox, Action<T, long, IZBackward> handler); void RegisterInbox<T>(string inbox, Action<T, long, IZBackward> handler);
void RegisterInbox<Treq, Tresp>(string inbox, Func<Treq, long, IZBackward, Tresp> handдer); void RegisterInbox<Treq, Tresp>(string inbox, Func<Treq, long, IZBackward, Tresp> handler);
/// <summary> /// <summary>
/// Replier without request /// Replier without request
/// </summary> /// </summary>
void RegisterInbox<Tresp>(string inbox, Func<long, IZBackward, Tresp> handдer); void RegisterInbox<Tresp>(string inbox, Func<long, IZBackward, Tresp> handler);
} }
} }

@ -19,13 +19,13 @@ namespace ZeroLevel.Services.Network.Services
/// </summary> /// </summary>
private static Invoker CreateCompiledExpression(MethodInfo method) private static Invoker CreateCompiledExpression(MethodInfo method)
{ {
var targetArg = Expression.Parameter(typeof(object)); // Цель на которой происходит вызов var targetArg = Expression.Parameter(typeof(object)); // Target
var argsArg = Expression.Parameter(typeof(object[])); // Аргументы метода var argsArg = Expression.Parameter(typeof(object[])); // Method's args
var parameters = method.GetParameters(); var parameters = method.GetParameters();
Expression body = Expression.Call( Expression body = Expression.Call(
method.IsStatic method.IsStatic
? null ? null
: Expression.Convert(targetArg, method.DeclaringType), // тип в котором объявлен метод : Expression.Convert(targetArg, method.DeclaringType), // Method's type
method, method,
parameters.Select((p, i) => parameters.Select((p, i) =>
Expression.Convert(Expression.ArrayIndex(argsArg, Expression.Constant(i)), p.ParameterType))); Expression.Convert(Expression.ArrayIndex(argsArg, Expression.Constant(i)), p.ParameterType)));

@ -8,7 +8,7 @@ namespace ZeroLevel.Services.Reflection
#region TypeHelpers #region TypeHelpers
/// <summary> /// <summary>
/// Сonverting a string to a type, if there is a corresponding converter for the type, in the absence of a converter, the default state for the specified type is returned /// Converting a string to a type, if there is a corresponding converter for the type, in the absence of a converter, the default state for the specified type is returned
/// </summary> /// </summary>
public static object TryConvert(string input, Type to) public static object TryConvert(string input, Type to)
{ {

@ -84,7 +84,7 @@ namespace ZeroLevel.Services.Shedulling
/// Performs an action once per period, while the date is recalculated from the function transferred each time the task is recreated. /// Performs an action once per period, while the date is recalculated from the function transferred each time the task is recreated.
/// </summary> /// </summary>
/// <param name="nextEventDateCalcFunction">The function to calculate the next date</param> /// <param name="nextEventDateCalcFunction">The function to calculate the next date</param>
/// <param name="callback">Действие</param> /// <param name="callback">Action</param>
/// <returns>Task ID</returns> /// <returns>Task ID</returns>
public long RemindAsyncEveryNonlinearDate(Func<DateTime, DateTime> nextEventDateCalcFunction, public long RemindAsyncEveryNonlinearDate(Func<DateTime, DateTime> nextEventDateCalcFunction,
Func<long, Task> callback, Func<long, Task> callback,

Loading…
Cancel
Save

Powered by TurnKey Linux.