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

C# Web及Android应用登录系统在线状态实现方案咨询

C# Web与Android登录系统在线状态最优实现方案

一、C# Web端(基于.NET Authentication + SQL Server)

1. 在线状态维持

  • 首先在SQL Server中新增UserOnlineStatus表,字段建议包含:
    • UserId(与用户表关联,主键+外键)
    • LastActiveTime(UTC时间,记录最后活跃时刻)
    • IsOnline(bit类型,标识在线状态)
    • SessionId(可选,关联ASP.NET Session,用于区分同用户多会话)
  • 实现请求中间件,拦截用户的有效请求(排除静态资源、心跳接口等),每次请求时更新当前登录用户的LastActiveTime为当前UTC时间,并将IsOnline设为true。

中间件代码示例:

public class OnlineStatusMiddleware
{
    private readonly RequestDelegate _next;

    public OnlineStatusMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, AppDbContext dbContext)
    {
        if (context.User.Identity.IsAuthenticated)
        {
            var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (!string.IsNullOrWhiteSpace(userId))
            {
                var status = await dbContext.UserOnlineStatus
                    .FirstOrDefaultAsync(s => s.UserId == userId);
                
                if (status == null)
                {
                    status = new UserOnlineStatus
                    {
                        UserId = userId,
                        LastActiveTime = DateTime.UtcNow,
                        IsOnline = true
                    };
                    dbContext.UserOnlineStatus.Add(status);
                }
                else
                {
                    status.LastActiveTime = DateTime.UtcNow;
                    status.IsOnline = true;
                }
                await dbContext.SaveChangesAsync();
            }
        }
        await _next(context);
    }
}

// Program.cs中注册中间件(放在身份认证中间件之后)
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<OnlineStatusMiddleware>();

2. 异常退出(死机、关窗)的离线处理

  • 定时清理机制:实现.NET后台托管服务,每隔固定时间(比如5分钟)扫描UserOnlineStatus表,将LastActiveTime超过阈值(比如10分钟,需大于中间件更新间隔)的用户IsOnline设为false。
  • Session联动(可选):如果使用InProc模式的Session,可在Session_End事件中直接标记用户离线;若用StateServer/SQL Server Session,仍需依赖定时任务,因为Session_End不会触发。

后台清理服务代码示例:

public class OnlineStatusCleanupService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;
    // 离线判定阈值:10分钟未活跃则标记为离线
    private readonly TimeSpan _inactiveThreshold = TimeSpan.FromMinutes(10);

    public OnlineStatusCleanupService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = _scopeFactory.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();

            var inactiveUsers = await dbContext.UserOnlineStatus
                .Where(s => s.LastActiveTime < DateTime.UtcNow - _inactiveThreshold && s.IsOnline)
                .ToListAsync(stoppingToken);

            foreach (var user in inactiveUsers)
            {
                user.IsOnline = false;
            }

            await dbContext.SaveChangesAsync(stoppingToken);
            // 每5分钟执行一次清理
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

// Program.cs中注册服务
builder.Services.AddHostedService<OnlineStatusCleanupService>();

二、Android端在线状态实现

1. 在线状态维持

  • 登录成功后,调用后端接口更新UserOnlineStatus表,标记用户为在线,并可额外记录DeviceType(Android)、DeviceId(用于区分多设备)。
  • 心跳机制:使用WorkManager实现周期性心跳任务,每隔3-5分钟向后端发送轻量请求(比如POST /api/user/heartbeat),后端收到后更新该用户的LastActiveTime。

Android心跳任务代码示例(Kotlin):

class HeartbeatWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        return try {
            val token = getSavedAuthToken() // 从SharedPreferences读取登录token
            if (!token.isNullOrEmpty()) {
                val apiService = RetrofitClient.create(ApiService::class.java)
                val response = apiService.sendHeartbeat(token)
                if (response.isSuccessful) Result.success() else Result.retry()
            } else {
                Result.success() // 未登录,终止心跳任务
            }
        } catch (e: Exception) {
            Result.retry() // 网络异常,重试
        }
    }

    companion object {
        fun start(context: Context) {
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build()

            val request = PeriodicWorkRequestBuilder<HeartbeatWorker>(3, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build()

            WorkManager.getInstance(context).enqueueUniquePeriodicWork(
                "HeartbeatWorker",
                ExistingPeriodicWorkPolicy.KEEP,
                request
            )
        }

        fun stop(context: Context) {
            WorkManager.getInstance(context).cancelUniqueWork("HeartbeatWorker")
        }
    }
}

// 登录成功后启动心跳:HeartbeatWorker.start(applicationContext)
// 主动退出时停止心跳并调用离线接口:
// HeartbeatWorker.stop(applicationContext)
// apiService.logout(token)

2. 异常离线处理

  • 依赖后端的定时清理机制(和Web端共用),当Android端无心跳超过阈值时,自动标记为离线。
  • 可选优化:监听应用前后台切换、网络断开事件,在应用退到后台或网络断开时,若网络可用则主动发送离线请求;网络不可用时,待恢复后补传(或直接依赖后端超时)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:25:54