我是CHARSET,转载请保留全文本。
-
建立POCO
public class Eventing : EventArgs { public DateTime EmitTime { get; set; } public string? Message { get; set; } } public class SampleEvent : Eventing { public int Success { get; set; } public int Fail { get; set; } }
-
建立能发送SignalR的服务接口
public interface ICacheQueueService<T> where T: EventArgs { Task AddThenSend(T t); List<T> Get(); } public interface ICacheObjectService<T> where T: EventArgs { Task UpdateThenSend(T t); T Get(); }
-
实现接口
public class CacheQueueService<T> : ICacheQueueService<T> where T: EventArgs { readonly ConcurrentQueue<T> events = new(); readonly IHubContext<Whisper> hubContext; readonly int queueDepth = 20; readonly string name = $"{nameof(CacheQueueService<T>)}<{typeof(T).Name}>"; //忽略DI过程 public async Task AddThenSend(T t) { events.Enqueue(t); while (events.Count > queuDepth) event.TryDequeue(out var _); await hubContext.Clients.All.SendAsync(name, t); } public List<T> Get() => events.ToList(); } public class CacheObjectService<T> : ICacheObjectService<T> where T: EventArgs { //同上 readonly string name = $"{nameof(CacheObjectService<T>)}<{typeof(T).Name}>"; readonly T _t = new(); readonly EmitCloneService clone; public async Task UpdateThenSend(T t) { clone.Clone(T, _t); await hubContext.Clients.All.SendAsync(name, t); } }
-
关于
EmitCloneService
public class EmitCloneService { readonly Dictionary<Type, Delegate> cachedIL = new(); public void Clone<T>(T source, T target) { if (source is null || target is null) return; var type = typeof(T); if (!cachedIL.TryGetValue(type, out var @delegate)) { var dynamicMethod = new DynamicMethod("Clone", null, new[] { type, type }); var il = dynamicMethod.GetILGenerator(); foreach(var property in type.GetProperties()) { if (property.CanRead && property.CanWrite && !property.GetAccessor(true)[0].IsStatic) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, property.GetMethod); il.Emit(OpCodes.Callvirt, property.SetMethod); } } il.Emit(OpCodes.Ret); var clone = (Action<T, T>)dynamicMethod.CreateDelegate(typeof(Action<T, T>)); cachedIL.Add(type, clone); clone(source, target); } else { ((Action<T, T>)@delegate)(source, target); } } }
-
注册服务
services.AddSingleton<ICacheObjectSerivce<SampleEvent>, CacheObjectService<SampleEvent>>();
-
编写Razor页面(页面组件使用AntDesign Blazor)
@inject ICacheObjectService<SampleEvent> Sample //... <Card Title="Sample" Style="width:300px"> <Extra>@Sample.EmitTime</Extra> <Body> <Badge [email protected] ShowZero Style="background-color:limegreen" /> <Badge [email protected] ShowZero Style="background-color:orangered" /> </Body> </Card> //...
-
在Razor页面的操作
readonly SampleEvent Sample = new(); protected override async Task OnInitializedAsync() { hubConnection = new HubConnectionBuilder().WithUrl(NavigationManager.ToAbsoluteUri("/whisper")).Build(); var sampleEventName = $"{nameof(CacheObjectService<T>)}<{nameof(SampleEvent)}>"; hubConnection.On<SampleEvent>(name, sample => { Sample.EmitTime = sample.EmitTime; Sample.Success = sample.Success; Sample.Fail = sample.Fail; }); }