Admin-ka: ASP.Net Core GUI
[csharp
|
rest
|
asp.net-core
|
gui
]
Abstract
Очень простая и лёгкая админка на ASP.Net Core.
Выглядит как-то так:
Introduction
Есть проект, состоящий из нескольких модулей. Каждый из них периодически пишет какие-то свои метрики в лог, в случае проблем логи анализировались мной в ручную.
Мне же хотелось окинуть одним взглядом всю систему и оценить текущий статус, нагрузку, возможные проблемы. А также я давно хотел пощупать ASP.Net Core.
Methods
Вообще я не очень люблю очень не люблю писать интерфейсы. Но иногда приходится. Так родилась Admin-ka.
Backend
Все модули построены на одной архитектуре, потому имеют обобщённый механизм сбора метрик, которые пишутся в лог. Добавляем новый endpoint, который по запросу отдаёт тоже самое, только в виде json.
[ServiceContract]
public interface IStatService
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "stats", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
IReadOnlyDictionary<string, StatContract> GetStats();
}
[DataContract]
public class StatContract
{
[DataMember]
public string Name { get; set; }
[DataMember]
public long SpeedIns { get; set; }
[DataMember]
public long SpeedAvg { get; set; }
[DataMember]
public long CountAll { get; set; }
[DataMember]
public long CountInQ { get; set; }
[DataMember]
public bool IsSpeed { get; set; }
}
что превращается в такой json (пример того, что отдаёт сервис)
{
"QueueIn": {
"Name": "Receiving",
"SpeedIns": 120,
"SpeedAvg": 10874,
"CountAll": 0,
"CountInQ": 0,
"IsSpeed": true
},
"QueueProc 1": {
"Name": "Processing 1",
"SpeedIns": 0,
"SpeedAvg": 0,
"CountAll": 3434,
"CountInQ": 0,
"IsSpeed": false
},
"QueueProc 2": {
"Name": "Processing 2",
"SpeedIns": 0,
"SpeedAvg": 0,
"CountAll": 3434,
"CountInQ": 0,
"IsSpeed": false
},
"QueueProc 3": {
"Name": "Processing 3",
"SpeedIns": 0,
"SpeedAvg": 0,
"CountAll": 3434,
"CountInQ": 0,
"IsSpeed": false
},
"QueueOut": {
"Name": "Sending",
"SpeedIns": 0,
"SpeedAvg": 0,
"CountAll": 3430,
"CountInQ": 0,
"IsSpeed": false
}
}
Mock
Поскольку я хотел в первую очередь показать интерфейс, конкретный бэкенд особой роли не играет, поэтому в качестве заглушечного демо я наваял простейший веб-сервис на Node.js, который просто отдаёт эти json-файлы с диска.
Frontend
С другой стороны мы имеем ASP.Net Core приложение.
В конфиге задаём словарь адресов сервисов, которые будем опрашивать, с названием модуля в качестве ключа. Там же задаются пороговые значения метрик — это очень важный момент — при превышении (или наоборот) соответствующие им ячейки интерфейса будут выделены.
При обращении в корень сервиса (указан в hosting.json
), контроллер пинает сервис, который собирает данные со всех сервисов из конфига, и рисуется красивая (или не очень) табличка с метриками.
Tips & Tricks #1. Автообновление
Из интересного. Я хотел сделать автообновление данных, думал как правильно это реализовать. Думал про поллинг (server-side и client-side), про серверные пуши, про SignalR. Хотел сделать максимально быстро и просто, но правильно.
В итоге всё решилось одной строчкой в контроллере:
Response.Headers.Add("Refresh", _config.RefreshInterval.TotalSeconds.ToString(CultureInfo.InvariantCulture));
И всё! По сути это встроенное обновление по таймеру.
Tips & Tricks #2. Standalone
Потом я захотел собрать сервис как standalone aka self-contained aka portable aka .EXE, чтобы запускать на машине без IIS’а. Мда.
По идее это должно делаться командой dotnet publish
, однако чтобы это сработало мне пришлось помучиться. Я просмотрел кучу статей, FAQ’ов и постов, MS и SO, кучу всего. Куча мануалов, гайдов и всякого материала, но все приведённые примеры файлов проекта приводили к одному из двух исходов: либо проект нормально открывался в студии, но не работал publish, либо наоборот, работал publish, но при открытии в студии, она не видела зависимостей (стандартной библиотеки), т.е. проект билдился, но не работала подсветка, интеллисенс, ничего. Так жить нельзя.
В интернетах описаны кучи разных конфигураций, все нерабочие, под разные таргеты, разных версий Core с разными настройками.
И такое ощущение, что никто реально не понимает, как оно устроено. Сплошное шаманство. А в VS 2017RC вообще снова csproj
вместо json
файл проекта, и все dotnet-команды не работают.
В итоге я заставил это работать. Я проверил на нескольких доступных мне машинах, что всё работает на текущих версиях, а это VS2015, .Net Core 1.1, .Net Command Line Tools 1.0.0-preview2-1-003177.
Я не уверен, что при следующем обновлении Core SDK, студии или тулинга опять всё не сломается. Точнее, я уверен в обратном. Но пока работает и это хорошо.
Results
На выходе мы имеем самодостаточное, гибко настраиваемое приложение, с помощью которого можно быстро оценить статус системы.
Благодаря REST’у в основе, оно не зависит от бэкенда, благодаря Core — от платформы. В случае необходимости можно быстро подправить формат данных или отображение или ещё что.
Плюс я немного полюбился познакомился с Core и фронтендом (node, npm, bower, bootstrap). Доволен, как слон.
Проект на гитхабе.