diff --git a/src/BootstrapBlazor.Server/Components/Pages/Online.razor b/src/BootstrapBlazor.Server/Components/Pages/Online.razor index 52bf67c4d7b..67736fe90d1 100644 --- a/src/BootstrapBlazor.Server/Components/Pages/Online.razor +++ b/src/BootstrapBlazor.Server/Components/Pages/Online.razor @@ -1,9 +1,91 @@ -@page "/online" +@page "/online" @layout MainLayout @inject IStringLocalizer Localizer

@Localizer["SubTitle"]:@ConnectionService.Connections.Count

-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/BootstrapBlazor.Server/Components/Pages/Online.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Online.razor.cs index 0d073bfb809..13306be9e40 100644 --- a/src/BootstrapBlazor.Server/Components/Pages/Online.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Pages/Online.razor.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using System.Data; - namespace BootstrapBlazor.Server.Components.Pages; /// @@ -16,17 +14,10 @@ public partial class Online : IDisposable [NotNull] private IConnectionService? ConnectionService { get; set; } - [Inject] - [NotNull] - private WebClientService? WebClientService { get; set; } - - private DynamicObjectContext? DataTableDynamicContext { get; set; } - - private readonly DataTable _table = new(); - + private readonly List _items = []; + private static readonly Comparison ConnectionComparer = static (x, y) => x.ConnectionTime.CompareTo(y.ConnectionTime); private CancellationTokenSource? _cancellationTokenSource; - - private string? _clientId; + private Task? _refreshTask; /// /// @@ -35,8 +26,6 @@ protected override void OnInitialized() { base.OnInitialized(); - CreateTable(); - BuildContext(); } @@ -44,135 +33,43 @@ protected override void OnInitialized() /// /// /// - protected override void OnAfterRender(bool firstRender) + protected override async Task OnAfterRenderAsync(bool firstRender) { - base.OnAfterRender(firstRender); + await base.OnAfterRenderAsync(firstRender); - if (firstRender) + if (firstRender && _refreshTask == null) { - Task.Run(async () => - { - var client = await WebClientService.GetClientInfo(); - _clientId = client.Id; - _cancellationTokenSource ??= new CancellationTokenSource(); - while (_cancellationTokenSource is { IsCancellationRequested: false }) - { - try - { - BuildContext(); - await InvokeAsync(StateHasChanged); - await Task.Delay(10000, _cancellationTokenSource.Token); - } - catch - { - // ignored - } - } - }); + _cancellationTokenSource ??= new CancellationTokenSource(); + _refreshTask = RefreshAsync(_cancellationTokenSource.Token); } } - private void CreateTable() - { - _table.Columns.Add("Id", typeof(string)); - _table.Columns.Add("ConnectionTime", typeof(DateTimeOffset)); - _table.Columns.Add("LastBeatTime", typeof(DateTimeOffset)); - _table.Columns.Add("Dur", typeof(TimeSpan)); - _table.Columns.Add("Ip", typeof(string)); - _table.Columns.Add("City", typeof(string)); - _table.Columns.Add("OS", typeof(string)); - _table.Columns.Add("Device", typeof(string)); - _table.Columns.Add("Browser", typeof(string)); - _table.Columns.Add("Language", typeof(string)); - _table.Columns.Add("Engine", typeof(string)); - _table.Columns.Add("RequestUrl", typeof(string)); - } - - private void BuildContext() + private async Task RefreshAsync(CancellationToken cancellationToken) { - _table.Rows.Clear(); - var rows = ConnectionService.Connections.Sort(["ConnectionTime"]); - foreach (var item in rows) - { - _table.Rows.Add( - item.Id, - item.ConnectionTime, - item.LastBeatTime, - item.LastBeatTime - item.ConnectionTime, - item.ClientInfo?.Ip ?? "", - item.ClientInfo?.City ?? "", - item.ClientInfo?.OS ?? "", - item.ClientInfo?.Device.ToString() ?? "", - item.ClientInfo?.Browser ?? "", - item.ClientInfo?.Language ?? "", - item.ClientInfo?.Engine ?? "", - item.ClientInfo?.RequestUrl ?? "" - ); - } - _table.AcceptChanges(); + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(10)); - //table - DataTableDynamicContext = new DataTableDynamicContext(_table, (context, col) => + try { - col.Text = Localizer[col.GetFieldName()]; - if (col.GetFieldName() == "Id") + while (await timer.WaitForNextTickAsync(cancellationToken)) { - col.Ignore = true; + BuildContext(); + await InvokeAsync(StateHasChanged); } - else if (col.GetFieldName() == "ConnectionTime") - { - col.FormatString = "yyyy/MM/dd HH:mm:ss"; - col.Width = 118; - } - else if (col.GetFieldName() == "LastBeatTime") - { - col.FormatString = "yyyy/MM/dd HH:mm:ss"; - col.Width = 118; - } - else if (col.GetFieldName() == "Dur") - { - col.FormatString = @"dd\.hh\:mm\:ss"; - col.Width = 54; - } - else if (col.GetFieldName() == "Ip") - { - col.Template = v => builder => builder.AddContent(0, FormatIp(v)); - } - else if (col.GetFieldName() == "RequestUrl") - { - col.Template = v => builder => - { - if (v is IDynamicObject val) - { - var url = val.GetValue("RequestUrl")?.ToString(); - if (!string.IsNullOrEmpty(url)) - { - builder.AddContent(0, new MarkupString($"{url}")); - } - } - }; - } - }); + } + catch (OperationCanceledException) { } } - private static string FormatIp(object v) + private void BuildContext() { - var ret = ""; - if (v is IDynamicObject val) - { - var ip = val.GetValue("Ip")?.ToString(); - if (!string.IsNullOrEmpty(ip)) - { - ret = ip.MaskIpString(); - } - } - return ret; + _items.Clear(); + _items.AddRange(ConnectionService.Connections); + _items.Sort(ConnectionComparer); } - private string? SetRowClassFormatter(DynamicObject context) + private static string GetDurString(ConnectionItem item) { - var id = context.GetValue("id")?.ToString(); - return _clientId == id ? "active" : null; + var dur = item.LastBeatTime - item.ConnectionTime; + return dur.ToString("dd\\.hh\\:mm\\:ss"); } private void Dispose(bool disposing) @@ -185,6 +82,7 @@ private void Dispose(bool disposing) _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; } + _refreshTask = null; } }