You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForms与.NET API共享全局Manager类实例问题求助

问题分析

你当前的RoundManager单例实现是进程内唯一——每台机器上的WinForms客户端都是独立的Windows进程,进程间内存完全隔离,所以不同机器的客户端会各自创建独立的RoundManager实例,自然无法共享状态。要实现跨机器的状态共享,必须借助跨进程/跨机器的状态中转方案,而非本地内存单例。

可行解决方案

以下是两种无需数据库的实现方案,按轻量化和实时性排序:

方案1:以.NET API为状态中心(推荐)

将RoundManager的实例托管在API端作为全局单例,所有客户端通过API接口读写状态,同时用SignalR实现状态变化的实时推送。

API端修改

  1. 把RoundManager注册为API的单例服务:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 注册RoundManager为全局单例
builder.Services.AddSingleton<RoundManager>();
// 添加SignalR服务
builder.Services.AddSignalR();

// ...其他配置

var app = builder.Build();
// 挂载SignalR Hub
app.MapHub<RoundHub>("/roundHub");
app.MapControllers();

app.Run();
  1. 编写API控制器暴露状态操作接口:
[ApiController]
[Route("api/round")]
public class RoundController : ControllerBase
{
    private readonly RoundManager _manager;
    private readonly IHubContext<RoundHub> _hubContext;

    public RoundController(RoundManager manager, IHubContext<RoundHub> hubContext)
    {
        _manager = manager;
        _hubContext = hubContext;
    }

    // 获取ObjectA状态
    [HttpGet("objectA")]
    public IActionResult GetObjectA()
    {
        return Ok(_manager.ObjectA);
    }

    // 更新ObjectA状态并通知所有客户端
    [HttpPost("objectA")]
    public async Task<IActionResult> UpdateObjectA([FromBody] ObjectA updatedObj)
    {
        _manager.ObjectA = updatedObj;
        // 推送给所有在线客户端
        await _hubContext.Clients.All.SendAsync("ObjectAUpdated", updatedObj);
        return Ok();
    }
}
  1. 实现SignalR Hub:
public class RoundHub : Hub { }

WinForms客户端修改

  1. 移除本地的RoundManager单例逻辑,通过HTTP请求调用API接口:
// 客户端获取最新ObjectA
private async Task<ObjectA> FetchObjectA()
{
    using var httpClient = new HttpClient();
    var response = await httpClient.GetAsync("http://你的API地址/api/round/objectA");
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadFromJsonAsync<ObjectA>();
}

// 客户端更新ObjectA
private async Task UpdateObjectA(ObjectA newObj)
{
    using var httpClient = new HttpClient();
    var content = JsonContent.Create(newObj);
    var response = await httpClient.PostAsync("http://你的API地址/api/round/objectA", content);
    response.EnsureSuccessStatusCode();
}
  1. 集成SignalR客户端监听状态变化:
private HubConnection _hubConnection;

// 窗体初始化时启动SignalR连接
private async void Ranked_Load(object sender, EventArgs e)
{
    _hubConnection = new HubConnectionBuilder()
        .WithUrl("http://你的API地址/roundHub")
        .Build();

    // 监听API推送的状态更新
    _hubConnection.On<ObjectA>("ObjectAUpdated", (updatedObj) =>
    {
        // 跨线程更新UI
        this.Invoke((Action)(() =>
        {
            // 示例:更新界面控件显示
            lblObjectAStatus.Text = updatedObj.ToString();
        }));
    });

    await _hubConnection.StartAsync();
}

// 窗体关闭时断开连接
private async void Ranked_FormClosed(object sender, FormClosedEventArgs e)
{
    if (_hubConnection != null)
    {
        await _hubConnection.StopAsync();
        await _hubConnection.DisposeAsync();
    }
}

方案2:用分布式缓存(如Redis)共享状态

将ObjectA序列化后存储在Redis中,客户端直接读写Redis,同时利用Redis的发布订阅功能实现状态变化通知。这种方案适合高并发场景,且支持状态持久化(可配置)。

核心逻辑示例

  1. 客户端读取状态:
private async Task<ObjectA> GetObjectAFromRedis()
{
    var redis = ConnectionMultiplexer.Connect("你的Redis地址");
    var db = redis.GetDatabase();
    var json = await db.StringGetAsync("ObjectA");
    return JsonSerializer.Deserialize<ObjectA>(json);
}
  1. 客户端更新状态并发布通知:
private async Task UpdateObjectAInRedis(ObjectA newObj)
{
    var redis = ConnectionMultiplexer.Connect("你的Redis地址");
    var db = redis.GetDatabase();
    var json = JsonSerializer.Serialize(newObj);
    await db.StringSetAsync("ObjectA", json);
    // 发布更新通知
    await redis.GetSubscriber().PublishAsync("ObjectAUpdated", json);
}
  1. 客户端订阅Redis通知:
private void SubscribeToRedisUpdates()
{
    var redis = ConnectionMultiplexer.Connect("你的Redis地址");
    redis.GetSubscriber().Subscribe("ObjectAUpdated", (channel, message) =>
    {
        var updatedObj = JsonSerializer.Deserialize<ObjectA>(message);
        this.Invoke((Action)(() =>
        {
            lblObjectAStatus.Text = updatedObj.ToString();
        }));
    });
}
关键注意点
  • API内存存储的状态会在API重启后丢失,若需要临时持久化,可定期将状态写入本地文件;Redis方案可通过配置实现持久化。
  • SignalR/Redis发布订阅是实现实时同步的核心,若不需要强实时性,也可让客户端定时轮询API/Redis获取最新状态。

内容的提问来源于stack exchange,提问作者repinSlun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:10:32