Приложение Service Monitor с .NET Core

Tags: .NET, SQL Server

Это руководство о том, как создать приложение Service Monitor, но что это такое? Проще говоря, это приложение, которое позволяет отслеживать сервисы в сети и сохранять результаты мониторинга в базе данных, в данном случае SQL Server.

Существует много инструментов, которые могут предоставить эту функцию, а также есть лучшие инструменты, которые можно купить за деньги, но цель этого руководства - показать, как использовать возможности .NET Core для создания приложения, которое разработчики могут расширить для пользовательских требований. ,

Основная идея заключается в следующем: иметь процесс для выполнения бесконечными способами для мониторинга хостов, баз данных и API; сохранить результаты мониторинга в базе данных SQL Server, затем мы можем создать удобный пользовательский интерфейс для конечного пользователя и показать статус для каждой службы, у нас может быть множество целей для мониторинга, но лучше разрешить пользователям подписываться на определенные службы, а не на все; например, администраторы баз данных должны следить за серверами баз данных, а не за API, разработчики должны наблюдать за базами данных и API-интерфейсами для разработки и т. д.

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

Одной из специальных функций может быть наличие службы уведомлений для отправки сообщений всем администраторам в случае сбоя одной или нескольких служб, в этом контексте под службой понимается цель, такая как хост, база данных, API

 

В этом руководстве мы будем работать с мониторингом следующих сервисов:

название

Описание

Хост

Пинг существующего хоста

База данных

Откройте и закройте соединение для существующей базы данных

RESTful API

Использовать одно действие из существующего API

Предыстория

 

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

Хосты будут осуществлять мониторинг с помощью действия ping, поэтому мы добавим пакеты, связанные с сетью, для выполнения этого действия.

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

API RESTful будут отслеживать с клиентом REST целевое действие, которое возвращает простой JSON.

База данных

Внутри репозитория есть каталог с именем \Resources\Database, и этот каталог содержит связанные файлы базы данных, поэтому обязательно запустите следующие файлы в следующем порядке:

Имя файла

Описание

00 - Database.sql

Определение базы данных

01 - Tables.sql

Определение таблиц

02 - Constraints.sql

Ограничения (первичные ключи, внешние ключи и уникальные)

03 - Rows.sql

Исходные данные

Мы можем найти скрипты для базы данных здесь

 

Таблица

Описание

EnvironmentCategory

Содержит все категории для сред: разработка, контроль качества и производство

ServiceCategory

Содержит все категории для сервисов: база данных, API остальных, сервер, URL и веб-сервис

Service

Содержит все определения услуг

ServiceWatcher

Содержит все компоненты со стороны C # для выполнения операций наблюдения

ServiceEnvironment

Содержит отношение к сервису и среде, например, мы можем определить сервис с именем FinanceService с различными средами: разработка, контроль качества и производство

ServiceEnvironmentStatus

Содержит статус для каждого сервиса в среде

ServiceEnvironmentStatusLog

Содержит детали для каждого статуса среды обслуживания

Owner

Содержит список пользователей для приложения, которое представляет всех владельцев

ServiceOwner

Содержит связь между сервисом и владельцем

User

Содержит всех пользователей для просмотра услуг

ServiceUser

Содержит отношение между сервисом и пользователем

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

Кроме того, не рекомендуется выставлять реальные строки подключения в таблице ServiceEnvironment. Пожалуйста, запросите у своего администратора базы данных, чтобы один пользователь мог только выполнить открытое подключение для целевой базы данных, в случае, если безопасность баз данных будет задачей с вашей стороны, создайте конкретных пользователей для выполнения. Открывайте ТОЛЬКО соединение с базами данных и не допускайте раскрытия конфиденциальной информации.

.NET Core Solution

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

название проекта

Тип

Описание

ServiceMonitor.Core

Библиотека классов

Содержит все определения, связанные с хранением базы данных

ServiceMonitor.Common

Библиотека классов

Содержит общие определения для проекта ServiceMonitor, такие как наблюдатели, сериализатор и клиенты (REST)

ServiceMonitor.WebAPI

Веб-API

Содержит контроллеры Web API для чтения и записи информации о мониторинге

ServiceMonitor

Консольное приложение

Содержит процесс для мониторинга всех услуг

ServiceMonitor.Core

Этот проект содержит все определения объектов и доступа к базе данных, поэтому нам необходимо добавить следующие пакеты для проекта:

название

Версия

Описание

Microsoft.EntityFrameworkCore.SqlServer

Последняя версия

Предоставляет доступ к SQL Server через EF Core

Этот проект состоит из трех уровней: бизнес-логика, доступ к базе данных и сущности; пожалуйста, ознакомьтесь со статьей EF Core для Entreprise, чтобы лучше понять этот проект и его слои.

Код класса DashboardService :

 

using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using ServiceMonitor.Core.BusinessLayer.Contracts;
using ServiceMonitor.Core.BusinessLayer.Responses;
using ServiceMonitor.Core.DataLayer;
using ServiceMonitor.Core.DataLayer.DataContracts;
using ServiceMonitor.Core.EntityLayer;

namespace ServiceMonitor.Core.BusinessLayer
{
   public class DashboardService : Service, IDashboardService
   {
       public DashboardService(ILogger<DashboardService> logger, ServiceMonitorDbContext dbContext)
           : base(logger, dbContext)
       {
       }

       public async Task<IListResponse<ServiceWatcherItemDto>> GetActiveServiceWatcherItemsAsync()
       {
           Logger?.LogDebug("'{0}' has been invoked", nameof(GetActiveServiceWatcherItemsAsync));

           var response = new ListResponse<ServiceWatcherItemDto>();

           try
           {
               response.Model = await DbContext.GetActiveServiceWatcherItems().ToListAsync();

               Logger?.LogInformation("The service watch items were loaded successfully");
           }
           catch (Exception ex)
           {
               response.SetError(Logger, nameof(GetActiveServiceWatcherItemsAsync), ex);
           }

           return response;
       }

       public async Task<IListResponse<ServiceStatusDetailDto>> GetServiceStatusesAsync(string userName)
       {
           Logger?.LogDebug("'{0}' has been invoked", nameof(GetServiceStatusesAsync));

           var response = new ListResponse<ServiceStatusDetailDto>();

           try
           {
               var user = await DbContext.GetUserAsync(userName);

               if (user == null)
               {
                   Logger?.LogInformation("There isn't data for user '{0}'", userName);

                   return new ListResponse<ServiceStatusDetailDto>();
               }
               else
               {
                   response.Model = await DbContext.GetServiceStatuses(user).ToListAsync();

                   Logger?.LogInformation("The service status details for '{0}' user were loaded successfully", userName);
               }
           }
           catch (Exception ex)
           {
               response.SetError(Logger, nameof(GetServiceStatusesAsync), ex);
           }

           return response;
       }

       public async Task<ISingleResponse<ServiceEnvironmentStatus>> GetServiceStatusAsync(ServiceEnvironmentStatus entity)
       {
           Logger?.LogDebug("'{0}' has been invoked", nameof(GetServiceStatusAsync));

           var response = new SingleResponse<ServiceEnvironmentStatus>();

           try
           {
               response.Model = await DbContext.GetServiceEnvironmentStatusAsync(entity);
           }
           catch (Exception ex)
           {
               response.SetError(Logger, nameof(GetServiceStatusAsync), ex);
           }

           return response;
       }
   }
}

 

ServiceMonitor.Common

контракты

  • IWatcher
  • IWatchResponse
  • ISerializer

Код интерфейса IWatcher:

Скрыть   копию кода

using System.Threading.Tasks;

namespace ServiceMonitor.Common.Contracts
{
   public interface IWatcher
   {
       string ActionName { get; }

       Task<WatchResponse> WatchAsync(WatcherParameter parameter);
   }
}

Код интерфейса IWatchResponse:

 

namespace ServiceMonitor.Common.Contracts
{
   public interface IWatchResponse
   {
       bool Success { get; set; }

       string Message { get; set; }

       string StackTrace { get; set; }
   }
}

Код интерфейса ISerializer:

Скрыть   копию кода

namespace ServiceMonitor.Common.Contracts
{
   public interface ISerializer
   {
       string Serialize<T>(T obj);

       T Deserialze<T>(string source);
   }
}

 

Наблюдатели

Это реализации:

  • DatabaseWatcher
  • HttpRequestWatcher
  • PingWatcher

Код класса DatabaseWatcher:

Скрыть   код   копии

using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor.Common
{
   public class DatabaseWatcher : IWatcher
   {
       public string ActionName
           => "OpenDatabaseConnection";

       public async Task<WatchResponse> WatchAsync(WatcherParameter parameter)
       {
           var response = new WatchResponse();

           using (var connection = new SqlConnection(parameter.Values["ConnectionString"]))
           {
               try
               {
                   await connection.OpenAsync();

                   response.Success = true;
               }
               catch (Exception ex)
               {
                   response.Success = false;
                   response.Message = ex.Message;
                   response.StackTrace = ex.ToString();
               }
           }

           return response;
       }
   }
}

Код класса HttpWebRequestWatcher:

Скрыть   код   копии

using System;
using System.Threading.Tasks;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor.Common
{
   public class HttpRequestWatcher : IWatcher
   {
       public string ActionName
           => "HttpRequest";

       public async Task<WatchResponse> WatchAsync(WatcherParameter parameter)
       {
           var response = new WatchResponse();

           try
           {
               var restClient = new RestClient();

               await restClient.GetAsync(parameter.Values["Url"]);

               response.Success = true;
           }
           catch (Exception ex)
           {
               response.Success = false;
               response.Message = ex.Message;
               response.StackTrace = ex.ToString();
           }

           return response;
       }
   }
}

Код класса PingWatcher:

Скрыть   копию кода

using System.Net.NetworkInformation;
using System.Threading.Tasks;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor.Common
{
   public class PingWatcher : IWatcher
   {
       public string ActionName
           => "Ping";

       public async Task<WatchResponse> WatchAsync(WatcherParameter parameter)
       {
           var ping = new Ping();

           var reply = await ping.SendPingAsync(parameter.Values["Address"]);

           return new WatchResponse
           {
               Success = reply.Status == IPStatus.Success ? true : false
           };
       }
   }
}

ServiceMonitor.WebAPI

Этот проект представляет RESTful API для службы мониторинга, поэтому у нас будет два контроллера: DashboardController и AdministrationController. Панель инструментов содержит все операции, связанные с результатами конечного пользователя, а Администрирование содержит все операции, связанные с сохранением информации (создание, редактирование и удаление).

Панель инструментов

DashboardController код класса:

Скрыть   код   копии

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ServiceMonitor.Core.BusinessLayer.Contracts;
using ServiceMonitor.WebAPI.Responses;

namespace ServiceMonitor.WebAPI.Controllers
{
#pragma warning disable CS1591
   [Route("api/v1/[controller]")]
   [ApiController]
   public class DashboardController : ControllerBase
   {
       protected readonly ILogger Logger;
       protected readonly IDashboardService Service;

       public DashboardController(ILogger<DashboardController> logger, IDashboardService service)
       {
           Logger = logger;
           Service = service;
       }
#pragma warning restore CS1591

       /// <summary>
       /// Gets service watcher items (registered services to watch with service monitor)
       /// </summary>
       /// <returns>A sequence of services to watch</returns>
       /// <response code="200"></response>
       /// <response code="500"></response>
       [HttpGet("ServiceWatcherItem")]
       [ProducesResponseType(200)]
       [ProducesResponseType(500)]
       public async Task<IActionResult> GetServiceWatcherItemsAsync()
       {
           Logger?.LogDebug("'{0}' has been invoked", nameof(GetServiceWatcherItemsAsync));

           var response = await Service.GetActiveServiceWatcherItemsAsync();

           return response.ToHttpResponse();
       }
   }
}

Администрирование

Код класса AdministrationController:

Скрыть   код   копии

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ServiceMonitor.Core.BusinessLayer.Contracts;
using ServiceMonitor.WebAPI.Responses;

namespace ServiceMonitor.WebAPI.Controllers
{
#pragma warning disable CS1591
   [Route("api/v1/[controller]")]
   [ApiController]
   public class DashboardController : ControllerBase
   {
       protected readonly ILogger Logger;
       protected readonly IDashboardService Service;

       public DashboardController(ILogger<DashboardController> logger, IDashboardService service)
       {
           Logger = logger;
           Service = service;
       }
#pragma warning restore CS1591

       /// <summary>
       /// Gets service watcher items (registered services to watch with service monitor)
       /// </summary>
       /// <returns>A sequence of services to watch</returns>
       /// <response code="200"></response>
       /// <response code="500"></response>
       [HttpGet("ServiceWatcherItem")]
       [ProducesResponseType(200)]
       [ProducesResponseType(500)]
       public async Task<IActionResult> GetServiceWatcherItemsAsync()
       {
           Logger?.LogDebug("'{0}' has been invoked", nameof(GetServiceWatcherItemsAsync));

           var response = await Service.GetActiveServiceWatcherItemsAsync();

           return response.ToHttpResponse();
       }
   }
}

 

ServiceMonitor

Этот проект содержит все объекты для Service Monitor Client, в этом проекте мы добавили пакет Newtonsoft.Json для сериализации JSON, в ServiceMonitor.Common есть интерфейс с именем, ISerializer и так как мы не хотим заставлять использовать определенный сериализатор, вы можете изменить это на этом уровне. :)

Код класса ServiceMonitorSerializer:

using Newtonsoft.Json;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor
{
   public class ServiceMonitorSerializer : ISerializer
   {
       public string Serialize<T>(T obj)
           => JsonConvert.SerializeObject(obj);

       public T Deserialze<T>(string source)
           => JsonConvert.DeserializeObject<T>(source);
   }
}

Далее мы будем работать над лассом MonitorControllerк, в этом классе мы будем выполнять все операции наблюдения и сохранять все результаты в базе данных через AdministrationController в API-интерфейсе Service Monitor.

Код класса MonitorController:

Скрыть   код   копии

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using ServiceMonitor.Clients;
using ServiceMonitor.Clients.Models;
using ServiceMonitor.Common;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor
{
   public class MonitorController
   {
       public MonitorController(ILogger logger, IWatcher watcher, IServiceMonitorWebAPIClient client, AppSettings appSettings)
       {
           Logger = logger;
           Watcher = watcher;
           Client = client;
           AppSettings = appSettings;
       }

       public ILogger Logger { get; }

       public IWatcher Watcher { get; }

       public IServiceMonitorWebAPIClient Client { get; }

       public AppSettings AppSettings { get; }

       public async Task ProcessAsync(ServiceWatchItem item)
       {
           while (true)
           {
               try
               {
                   Logger?.LogTrace("{0} - Watching '{1}' for '{2}' environment", DateTime.Now, item.ServiceName, item.Environment);

                   var watchResponse = await Watcher.WatchAsync(new WatcherParameter(item.ToDictionary()));

                   if (watchResponse.Success)
                       Logger?.LogInformation(" Success watch for '{0}' in '{1}' environment", item.ServiceName, item.Environment);
                   else
                       Logger?.LogError(" Failed watch for '{0}' in '{1}' environment", item.ServiceName, item.Environment);

                   var serviceStatusLog = new ServiceStatusLogRequest
                   {
                       ServiceID = item.ServiceID,
                       ServiceEnvironmentID = item.ServiceEnvironmentID,
                       Target = item.ServiceName,
                       ActionName = Watcher.ActionName,
                       Success = watchResponse.Success,
                       Message = watchResponse.Message,
                       StackTrace = watchResponse.StackTrace
                   };

                   try
                   {
                       await Client.PostServiceEnvironmentStatusLog(serviceStatusLog);
                   }
                   catch (Exception ex)
                   {
                       Logger?.LogCritical(" Error on saving watch response ({0}): '{1}'", item.ServiceName, ex.Message);
                   }
               }
               catch (Exception ex)
               {
                   Logger?.LogCritical(" Error watching service: '{0}': '{1}'", item.ServiceName, ex.Message);
               }

               Thread.Sleep(item.Interval ?? AppSettings.DelayTime);
           }
       }
   }
}

Перед запуском консольного приложения убедитесь в следующих аспектах:

  1. База данных ServiceMonitor доступна
  2. База данных ServiceMonitor содержит информацию для категорий услуг, сервисов, сервис-наблюдателей и пользователей.
  3. API ServiceMonitor доступен

Мы можем проверить возвращаемое значение для URL api/v1/Dashboard/ServiceWatcherItems :

{  
 "message":null,
 "didError":false,
 "errorMessage":null,
 "model":[  
   {
     "serviceID":1,
     "serviceEnvironmentID":1,
     "environment":"Development",
     "serviceName":"Northwind Database",
     "interval":15000,
     "url":null,
     "address":null,
     "connectionString":"server=(local);database=Northwind;user id=johnd;password=SqlServer2017$",
     "typeName":"ServiceMonitor.Common.DatabaseWatcher, ServiceMonitor.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
   },
   {
     "serviceID":2,
     "serviceEnvironmentID":3,
     "environment":"Development",
     "serviceName":"DNS",
     "interval":3000,
     "url":null,
     "address":"192.168.1.1",
     "connectionString":null,
     "typeName":"ServiceMonitor.Common.PingWatcher, ServiceMonitor.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
   },
   {
     "serviceID":3,
     "serviceEnvironmentID":4,
     "environment":"Development",
     "serviceName":"Sample API",
     "interval":5000,
     "url":"http://localhost:5612/api/values",
     "address":null,
     "connectionString":null,
     "typeName":"ServiceMonitor.Common.HttpWebRequestWatcher, ServiceMonitor.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
   }
 ]
}

Как мы видим, API возвращает все службы DefaultUser, пожалуйста помните о концепции, согласно которой один пользователь может подписать несколько служб для просмотра, очевидно, в этом примере наш пользователь по умолчанию привязан ко всем службам, но мы можем изменить эту ссылку в таблице ServiceUser.

Код класса Program:

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using ServiceMonitor.Clients;
using ServiceMonitor.Clients.Models;
using ServiceMonitor.Common;
using ServiceMonitor.Common.Contracts;

namespace ServiceMonitor
{
   class Program
   {
       private static ILogger Logger;
       private static readonly AppSettings AppSettings;

       static Program()
       {
           Logger = LoggingHelper.GetLogger<Program>();

           var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");

           var configuration = builder.Build();

           AppSettings = new AppSettings();

           configuration.GetSection("appSettings").Bind(AppSettings);
       }

       static void Main(string[] args)
       {
           StartAsync(args).GetAwaiter().GetResult();

           Console.ReadLine();
       }

       static async Task StartAsync(string[] args)
       {
           Logger.LogDebug("Starting service monitor...");

           var client = new ServiceMonitorWebAPIClient();

           var serviceWatcherItemsResponse = default(ServiceWatchResponse);

           try
           {
               serviceWatcherItemsResponse = await client.GetServiceWatcherItemsAsync();
           }
           catch (Exception ex)
           {
               Logger.LogError("Error on retrieve watch items: {0}", ex);
               return;
           }

           foreach (var item in serviceWatcherItemsResponse.Model)
           {
               var watcherType = Type.GetType(item.TypeName, true);

               var watcherInstance = Activator.CreateInstance(watcherType) as IWatcher;

               await Task.Factory.StartNew(async () =>
               {
                   var controller = new MonitorController(Logger, watcherInstance, client, AppSettings);

                   await controller.ProcessAsync(item);
               });
           }
       }
   }
}

Как только мы проверили предыдущие аспекты, теперь мы переходим к включению консольного приложения, и получили следующий вывод консоли:

dbug: ServiceMonitor.Program[0]
     Starting application
sr trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:30 - Watching 'Sample API' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:30 - Watching 'Northwind Database' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:30 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:35 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:37 - Watching 'Sample API' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:39 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:42 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:43 - Watching 'Sample API' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:45 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:47 - Watching 'Northwind Database' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:48 - Watching 'Sample API' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:48 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:51 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:53 - Watching 'Sample API' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:54 - Watching 'DNS' for 'Development' environment
trce: ServiceMonitor.Program[0]
     06/20/2017 23:09:57 - Watching 'DNS' for 'Development' environment

Теперь мы приступаем к проверке сохраненных данных в базе данных, пожалуйста, проверьте таблицу ServiceEnvironmentStatus, вы должны получить следующий результат:

Скрыть   копию кода

ServiceEnvironmentStatusID ServiceEnvironmentID Success WatchCount  LastWatch
-------------------------- -------------------- ------- ----------- -----------------------
1                          4 1  212 2018-11-22 23:11:34.113
2                          1 1  78 2018-11-22 23:11:33.370
3                          3 1  366 2018-11-22 23:11:34.620

(3 row(s) affected)

Как это все вместе работает? Консольное приложение берет все сервисы для наблюдения из API, а затем бесконечно запускает одну задачу на элемент наблюдения, MonitorController. Для каждой задачи есть время задержки, этот интервал задается в определении сервиса, но если нет определенного значения для интервала интервал берется из AppSettings; поэтому после выполнения действия Watch результат сохраняется в базе данных через API, и процесс повторяется. Если вы хотите выполнить операцию watch для других типов, вы можете создать свой собственный класс Watcher.

Точки интереса

  • DatabaseWatcher работает с SQL Server, так как вы подключаетесь к MySQL, PostgreSQL, Oracle и другим СУБД? Создайте свой класс Watcher для конкретной СУБД, реализации интерфейса IWatcher и напишите код для подключения к целевой базе данных.
  • Можем ли мы разместить сервисный монитор на платформах не Windows? Да, поскольку .NET Core является кроссплатформенным, мы можем разместить этот проект на Windows, Mac OS и Linux.
  • Насколько нам известно, в .NET Core нет встроенной поддержки ASMX, но мы можем отслеживать оба вида сервисов, просто добавляя строки в таблицу Service, ASMX заканчивается на .asmx .
  • Почему консольный клиент и API не являются одним проектом? Чтобы избежать распространенных проблем при публикации, лучше иметь два разных проекта, потому что в этом случае мы можем запустить сервисный монитор на одном сервере и разместить API на другом сервере.
  • В этой первоначальной версии нет никаких настроек безопасности, потому что лучше добавить эту реализацию в соответствии с вашим сценарием: вы можете заставить этот проект работать с Аутентификацией Windows, пользовательской Аутентификацией или добавить внешний сервис для аутентификации.

Улучшения кода

  • Добавьте Identity Server
  • Добавьте уведомления администраторам о критических ошибках при просмотре сервисов (электронная почта, смс и т. д.)
  • Лучше иметь TypeName в ServiceCategory вместо ServiceWatcher
  • Добавьте проект пользовательского интерфейса, чтобы наглядно показать состояние сервисов для конечных пользователей, используя некоторые интерфейсные среды, такие как Angular

No Comments

Add a Comment