FineUICore利用TaskCompletionSource实现同步Confirm

196 阅读3分钟

FineUICore利用TaskCompletionSource实现同步Confirm

导言

非异步的asp.net后台很难做到同步前台的confirm确认框,造成后台逻辑的割裂,引用异步处理后该问题可以得到解决

1.引出问题

现在有一个设计需求,

  1. 前台处理数据,回发;
  2. 后台接收数据,首先验证;
  3. 如果验证成功,提示用户是否确认XXX;
  4. 用户在前台点击确认后再执行后续逻辑;

第三步骤是用户确认的过程,在这期间系统是断开的,后台需要抛出确认框,等待用户确认,再继续执行逻辑,一般情况下会这么写:

这里出现的问题就是后台业务逻辑中出现了断裂,无法向winfrom程序一样在方法中等待用户的选择,

理想中的写法应该是这样

void doWork(stirng id)
{
    //验证数据
    var xxx = Checkxxx(id);
    //提示确认框
    var confirm = UserConfirm(xxx);
    //如果选择了确定
    if(confirm.OK){
        ...
    }    
    //如果选择了否或取消
    else{
        ...
    }
}

2.技术选择

在.net core 异步开发时,可以实现该功能。

2.1 Task的状态

首先要知道 TaskCompletionSource 允许自己控制Task的状态,使用如下:

//创建 接收Task的返回类型
var TCS = new TaskCompletionSource<T>();
//尝试改变Task状态 返回t
TCS?.TrySetResult(t);
//释放
TCS?.Task?.Dispose();

解决思路就是,我们可以先创建一个TaskCompletionSource 放在缓存中,前台用户确认后再从缓存中拿到该TaskCompletionSource并执行TrySetResult传入用户选择的按钮,然后释放清除缓存;

这里要注意的是需要加入超时机制,如果用户长时间不选择,则需要超时返回默认值并释放,清除缓存;

2.2 缓存

这里的缓存我们使用.net core自带的MemoryCache 也可以根据环境使用Redis或其他,在提示时可以使用Guid作为key,传到前台,再传回来,后台有一个基础方法接收传回来的key和选择的按钮,拼接结果并从缓存拿到Task执行TrySetResult;

2.3 超时类

超时类使用ManualResetEvent,核心方法:

var mre = new ManualResetEvent();
//重置
mre.Reset();
//如果超时就...
if(mre.WaitOne(timeoutMillis)){...}

2.4 通知前台的方法

还要注意的是不能等待第一次回发(Task)管道处理完才执行前台的Confirm,应该再执行一半时通知前台并挂起等待,通知前台的方法 直接使用SignalR即可;

2.5 前台

前台选型无所谓,可以是element ui 或其他前端,这里使用与后台更贴合的FineUICore(我们开发人员少没有进行前后台分离);

3.具体实现

这个代码量还是比较多的,由于篇幅限制,这里还是给出简图和部分代码截图,

首先准备一个异步帮助类,该类主要负责实现 TaskCompletionSource 的创建,缓存,取出,和超时及释放

这是一个接口 实现触发前台的Confirm窗口

代码文件

代码文件

实际的使用

接收前台的返回结果 该方法在 BaseController 中

图片.png