使用SignalR技术实现监控刷新功能

我是CHARSET,转载请保留全文本。

  1. 建立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; }
    }
    
  2. 建立能发送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();
    }
    
  3. 实现接口

    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);
      }
    }
    
  4. 关于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);
        }
      }
    }
    
  5. 注册服务

    services.AddSingleton<ICacheObjectSerivce<SampleEvent>, CacheObjectService<SampleEvent>>();
    
  6. 编写Razor页面(页面组件使用AntDesign Blazor)

    @inject ICacheObjectService<SampleEvent> Sample
    //...
    <Card Title="Sample" Style="width:300px">
      <Extra>@Sample.EmitTime</Extra>
      <Body>
      	<Badge Count=@Sample.Success ShowZero Style="background-color:limegreen" />
        <Badge Count=@Sample.Fail ShowZero Style="background-color:orangered" />
      </Body>
    </Card>
    //...
    
  7. 在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;
      });
    }
    
posted @ 2022-11-25 16:38  charset  阅读(199)  评论(0编辑  收藏  举报