zoukankan      html  css  js  c++  java
  • 3层模式下长时间调用的进度条提示方案

    Winform + WCF  +IIS 方式

    任务执行时间在几分钟,需要在客户端显示进度条,与提示

    原理:客户端发出任务调用请求后,服务启用一个独立线程来执行,将执行过程与结果写入一个指定内存(消息存储桶)

    客户端轮询服务端的消息存储桶,来获取进度或得到结果

    客户端主要代码

    进度控制参数类

        public class LongInvokeControl
        {
            public LongInvokeControl()
            {
                ShowPercent = true;
                LoopInterval = 1;
            }
            public LongInvokeControl(Object service, string sName, string lName):this()
            {
                this.Service = service;
                this.StartMethodName = sName;
                this.LoopMethodName = lName;
            }
            public String StartMethodName { get; set; }
            public String LoopMethodName { get; set; }
            public int LoopInterval { get; set; }
            public object Service { get; set; }
            public bool ShowPercent { get; set; }
        }
    View Code

    客户端调用代码,反射+泛型方法

     public OutT LongInvoke<InT, OutT>(InT inParam, LongInvokeControl ctl)
            where OutT : class
            {
                try
                {
                    using (var frm = new frmLongInvokeMonitor())
                    {
                        var type = ctl.Service.GetType();
                        var methodStart = type.GetMethod(ctl.StartMethodName);
                        var r1 = methodStart.Invoke(ctl.Service, new object[] { inParam }) as LongInvokeBucketInfo;
    
                        var methodLoop = type.GetMethod(ctl.LoopMethodName);
                        var loopResponse = methodLoop.Invoke(ctl.Service, new object[] { r1 }) as LongInvokeResponse<OutT>;
    
                        ThreadPool.QueueUserWorkItem(o => {
    
                            while (loopResponse.Status == LongInvokeStatus.Running)
                            {
                                #region 设置显示属性
                                SyncContext.Send(obj =>
                                {
                                    frm.progressBar1.Value = loopResponse.Percent ;
                                    frm.txtTips.Text = loopResponse.Tips;
                                }, null);
                                #endregion
                                loopResponse = methodLoop.Invoke(ctl.Service, new object[] { r1 }) as LongInvokeResponse<OutT>;
                                Console.WriteLine(loopResponse.Tips);
                                Thread.Sleep(1000 * ctl.LoopInterval);
                            }
                            #region 关闭窗口
                            SyncContext.Send(obj =>
                            {
                                frm.Close();
                            }, null);
                            #endregion
                        },null);
                        //是否连续进度条
                        if (!ctl.ShowPercent)
                        {
                            frm.progressBar1.Style = ProgressBarStyle.Marquee;
                        }
                        frm.ShowDialog();
    
                        if (loopResponse.Status == LongInvokeStatus.Finish_Success)
                        {
                            Console.WriteLine("完成了!");
                            Console.WriteLine(loopResponse.Model);
                        }
                        else if (loopResponse.Status == LongInvokeStatus.Finish_Fail)
                        {
                            Console.WriteLine(loopResponse.Msg);
                        }
                        else
                        {
                            Console.WriteLine("状态异常!");
                        }
                        if (loopResponse.Status != LongInvokeStatus.Finish_Success)
                        {
                            throw new Exception(loopResponse.Msg);
                        }
                        return loopResponse.Model as OutT;
    
                    }
    
     
    
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        throw ex.InnerException;
                    }
                    else
                    {
                        throw;
                    }
                }
            }
    View Code

    使用代码

      barButtonItem1.ItemClick += (s, e) =>
                {
                    var item = MainBindingSource.Current as LongInvokeBucketInfo;
                    if (item == null) return;
                    try
                    {
                        var service=Fetch<ILongInvokeService>();
                        var ret = LongInvoke<List<int>, List<String>>(new List<int>() { 11, 2, 3 }, new LongInvokeControl(service, "TestTaskStartInvoke", "TestTaskLoopInvoke") { LoopInterval = 2,ShowPercent=false });
                        InfoMsg("任务执行完成" + ret[0]);
                    }
                    catch (Exception ex)
                    {
                        ErrMsg(ex.Message);
                    }
               
                    return;
                };
                barButtonItem2.ItemClick += (s, e) =>
                {
                    var item = MainBindingSource.Current as LongInvokeBucketInfo;
                    if (item == null) return;
                    try
                    {
                        var service = Fetch<ILongInvokeService>();
                        var  ret = LongInvoke<List<int>, List<String>>(new List<int>() { 11, 2, 3 }, new LongInvokeControl(service,"TestTaskStartInvoke","TestTaskLoopInvoke") {LoopInterval=1 });
                        InfoMsg("任务执行完成" + ret[0]);
                    }
                    catch (Exception ex)
                    {
                        ErrMsg(ex.Message);
                    }
    
                    return;
                };
                barButtonItem3.ItemClick += (s, e) =>
                {
                    var item = MainBindingSource.Current as LongInvokeBucketInfo;
                    if (item == null) return;
                    try
                    {
                        var service = Fetch<ILongInvokeService>();
                        var ret = LongInvoke<List<int>, List<String>>(new List<int>() { 101, 2, 3 }, new LongInvokeControl() { Service = service, StartMethodName = "TestTaskStartInvoke", LoopMethodName= "TestTaskLoopInvoke",ShowPercent= true });
                        InfoMsg("任务执行完成" + ret[0]);
                    }
                    catch (Exception ex)
                    {
                        ErrMsg(ex.Message);
                    }
    
                    return;
                };
    View Code

    服务端主代码:

    消息存储桶,调用任务控制块,控制消息桶数量,也就控制了整个系统允许并发执行的总任务书

    另外该类提供2个模板方法供WCF服务调用

    一个WCF服务实现类,注意为完成进度跟踪需要实现2个方法

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.Concurrent;
    using F.Studio.Prime.EFModel;
    using System.Threading;
    
    namespace F.Studio.Prime.Service
    {
        public class LongInvokeBucketMgr:IDisposable
        {
            private const int C_MaxSink = 50;
            private readonly static LongInvokeBucketMgr _Instance = new LongInvokeBucketMgr();       
            public List<LongInvokeBucket> BucketList = new List<LongInvokeBucket>();
            private Object lockObj = new object();
            public static LongInvokeBucketMgr Instance
            {
                get
                {
                    return _Instance;
                }
            }
            private LongInvokeBucketMgr() 
            {
                InitMgr();
            }
    
            private void InitMgr()
            {
                for (int i = 0; i < C_MaxSink; i++)
                {
                    var bucket=new LongInvokeBucket();
                    bucket.Id=i;
                    bucket.Model = null;
                    bucket.Percent = -1;
                    bucket.Status = LongInvokeStatus.Init;
                    bucket.Tips = "";
                    bucket.Msg = "";
                    bucket.Code = -1;
                    bucket.Guid = "";
                    bucket.IsFree = true;
                    BucketList.Add(bucket);
                }
            }
    
            public LongInvokeBucket Allocate()
            {
                lock (lockObj)
                {
                    var it = BucketList.FirstOrDefault(ent => ent.IsFree == true);
                    if (it == null) throw new Exception("没有可分配的消息存储桶!");
                    it.IsFree = false;
                    it.Guid = Guid.NewGuid().ToString();
                    it.Status = LongInvokeStatus.Running;
                    it.BTime = DateTime.Now;
                    it.ETime = null;
                    it.Code = 0;
                    it.Percent = 0;
                    it.Tips = "";
                    it.Msg = "";
                    it.Data = "";
                    it.TaskName = "";
                    it.Model = null;
                    return it;
                }
            }
            public void Free(int id)
            {
                lock (lockObj)
                {
                    var it = BucketList.FirstOrDefault(ent => ent.Id == id);
                    if (it == null) throw new Exception(string.Format("指定的消息存储桶编号不存在{0}", id));
                    it.IsFree = true;
                    it.Model = null;
                }
            }
            public List<LongInvokeBucketInfo> GetList()
            {
               
                    var list = new List<LongInvokeBucketInfo>();
                    foreach (var item in BucketList)
                    {
                        var info = new LongInvokeBucketInfo();
                        SetInfo(item, info);
                       
                        list.Add(info);
                    }
                    return list;
                
            }
    
            private static void SetInfo(LongInvokeBucket item, LongInvokeBucketInfo info)
            {
                info.BTime = item.BTime;
                info.ETime = item.ETime;
                info.Code = item.Code;
                info.Guid = item.Guid;
                info.Id = item.Id;
                info.IsFree = item.IsFree;
                info.Msg = item.Msg;
                info.Percent = item.Percent;
                info.Status = item.Status;
                info.TaskName = item.TaskName;
                info.Tips = item.Tips;
            }
            public static LongInvokeBucketInfo ConvertToInfo(LongInvokeBucket from)
            {
                LongInvokeBucketInfo info = new LongInvokeBucketInfo();
                SetInfo(from, info);
                return info;
            }
            public LongInvokeBucket QueryBucket(string guid)
            {
                var it= BucketList.FirstOrDefault(ent => ent.Guid == guid);
                if (it == null) throw new Exception("未找到指定的消息存储桶(运行控制块)!");
                return it;
            }
    
            public void Stop()
            {
                BucketList.Clear();
            }
            #region 执行与轮询模板代码
            /// <summary>
            /// 模板代码
            /// 需要提供Func方法实现,该方法输入LongInvokeBucket,返回ReturnT类型
            /// </summary>
            /// <typeparam name="ReturnT"></typeparam>
            /// <param name="func"></param>
            /// <returns></returns>
            public static LongInvokeBucketInfo StartInvoke<ReturnT>(Func<LongInvokeBucket, ReturnT> func)
            {
                var bucket = LongInvokeBucketMgr.Instance.Allocate();
                var taskInfo = LongInvokeBucketMgr.ConvertToInfo(bucket);
                var oldGuid = bucket.Guid;
                ThreadPool.QueueUserWorkItem(o =>
                {
    
                    try
                    {
                        bucket.Tips = "任务启动...";
                        var model = func(bucket);
                        bucket.Tips = "完成";
                        bucket.Percent = 100;
                        bucket.Code = 0;
                        bucket.Model = model;
                        bucket.Status = LongInvokeStatus.Finish_Success;
    
                    }
                    catch (Exception ex)
                    {
                        bucket.Tips = "执行错误";
                        bucket.Msg = ex.Message;
                        bucket.Code = 2;
                        bucket.Status = LongInvokeStatus.Finish_Fail;
                    }
                    finally
                    {
                        bucket.ETime = DateTime.Now;
                        Thread.Sleep(1000 * 10);
                        //10秒后世界依旧如故,那么就释放吧
                        if (bucket.Guid == oldGuid)
                        {
                            LongInvokeBucketMgr.Instance.Free(bucket.Id);
                        }
                    }
    
                });
                return taskInfo;
    
            }
            public static LongInvokeResponse<ReturnT> LoopInvoke<ReturnT>(LongInvokeBucketInfo request)
            where ReturnT : class
            {
                var response = new LongInvokeResponse<ReturnT>();
                try
                {
                    var bucket = LongInvokeBucketMgr.Instance.QueryBucket(request.Guid);
    
                    if (bucket.IsFree) throw new Exception("已经释放了消息存储桶!");
    
    
                    response.Tips = bucket.Tips;
                    response.Status = bucket.Status;
                    response.Percent = bucket.Percent;
                    response.Code = bucket.Code;
                    response.Msg = bucket.Msg;
                    //立即释放
                    if (bucket.Status == LongInvokeStatus.Finish_Success)
                    {
                        response.Model = bucket.Model as ReturnT;
                        LongInvokeBucketMgr.Instance.Free(request.Id);
                    }
                    else if (bucket.Status == LongInvokeStatus.Finish_Fail)
                    {
                        LongInvokeBucketMgr.Instance.Free(request.Id);
                    }
    
                }
                catch (Exception ex)
                {
                    response.Status = LongInvokeStatus.Finish_Fail;
                    response.Code = 2;
                    response.Msg = ex.Message;
                    response.Tips = ex.Message;
                }
                return response;
            }
    
            /// <summary>
            /// 轮询调用,注意客户端检测到任务完成后,
            /// 请不要再发起调用
            /// </summary>
            /// <typeparam name="ReturnT"></typeparam>
            /// <typeparam name="InT"></typeparam>
            /// <param name="request"></param>
            /// <param name="act"></param>
            /// <returns></returns>
            public static LongInvokeResponse<ReturnT> LoopInvoke<ReturnT, InT>(LongInvokeRequest<InT> request, Action<LongInvokeBucket> act)
                where ReturnT : class
            {
                var response = new LongInvokeResponse<ReturnT>();
                try
                {
                    var bucket = LongInvokeBucketMgr.Instance.QueryBucket(request.Guid);
    
                    if (bucket.IsFree) throw new Exception("已经释放了消息存储桶!");
                    if (act != null)
                    {
                        act(bucket);
                    }
    
                    response.Tips = bucket.Tips;
                    response.Status = bucket.Status;
                    response.Percent = bucket.Percent;
                    response.Code = bucket.Code;
                    response.Msg = bucket.Msg;
                    //立即释放
                    if (bucket.Status == LongInvokeStatus.Finish_Success)
                    {
                        response.Model = bucket.Model as ReturnT;
                        LongInvokeBucketMgr.Instance.Free(request.Id);
                    }
                    else if (bucket.Status == LongInvokeStatus.Finish_Fail)
                    {
                        LongInvokeBucketMgr.Instance.Free(request.Id);
                    }
    
                }
                catch (Exception ex)
                {
                    response.Status = LongInvokeStatus.Finish_Fail;
                    response.Code = 2;
                    response.Msg = ex.Message;
                    response.Tips = ex.Message;
                }
                return response;
    
            }
            #endregion
            #region IDisposable Members
            private bool disposed = false;
            /// <summary>
            /// Performs application-defined tasks associated with freeing, 
            /// releasing, or resetting unmanaged resources.
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            /// <summary>
            /// Releases unmanaged and - optionally - managed resources
            /// </summary>
            /// <param name="disposing"><c>true</c> to release both managed 
            /// and unmanaged resources; <c>false</c> 
            /// to release only unmanaged resources.
            /// </param>
            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        try
                        {
                            Stop();
                        }
                        catch
                        {
    
                        }
                    }
    
                    disposed = true;
                }
            }
    
    
            #endregion
        }
    }
    View Code

    注意下面func方法返回值是异步调用最终的返回值(看成同步调用时)

    异步调用使用了ThreadPool线程,

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using F.Studio.Prime.IService;
    using F.Studio.Prime.EFModel;
    using System.Threading;
    using System.ServiceModel.Activation;
    using System.ServiceModel;
    
    namespace F.Studio.Prime.Service
    {
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
        [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple, MaxItemsInObjectGraph = 999999999, IgnoreExtensionDataObject = true, UseSynchronizationContext = false)]
        public class LongInvokeService : ILongInvokeService
        {
    
    
            public List<LongInvokeBucketInfo> GetBucketList()
            {
                return LongInvokeBucketMgr.Instance.GetList();
            }
    
            public int Free(int id)
            {
                LongInvokeBucketMgr.Instance.Free(id);
                return 0;
            }
            
            public LongInvokeBucketInfo TestTaskStartInvoke(List<int> list)
            {
               Func<LongInvokeBucket, List<String>> func=(bucket)=>{
                  #region
                  // bucket.TaskName = "Long Invoke Test";
                  // for (int i = 0; i < 10; i++)
                  // {
                  //     bucket.Tips = "执行" + i + "项操作...";
                  //     bucket.Percent = bucket.Percent + 5;
                  //     Thread.Sleep(1000 * 1);
                  //     if (i > 5 && list[0] == 101) throw new Exception("碰到错误了,Func!");
    
                  // }
                  // bucket.Tips = "执行数据保存操作...";
                  // bucket.Percent = 99;
                  // Thread.Sleep(1000 * 3);
                  // bucket.Tips = "任务执行完成";
                   //return new List<String>() {"123","abc","ABC" };
    
                  #endregion
                   var actor= new TaskActor(bucket, list);
                   actor.Do();
                   return actor.Resulte;
               };
               return  LongInvokeBucketMgr.StartInvoke(func);
                
            }
            public LongInvokeResponse<List<String>> TestTaskLoopInvoke(LongInvokeBucketInfo request)
            {
                var response = LongInvokeBucketMgr.LoopInvoke<List<String>>(request);
                return response;
            }
            public LongInvokeResponse<List<string>> LoopTestTask(LongInvokeRequest<List<int>> request)
            {
                Action<LongInvokeBucket> act = (b) => 
                {
                    if (request.Model.Count > 0)
                    {
                        if (request.Model[0] == 101)
                        {
                            throw new Exception("Test:第一个元素是101");
                        }
                    }
                };
    
    
                var response = LongInvokeBucketMgr.LoopInvoke<List<String>, List<int>>(request, act);
                return response;
    
            }
            public class TaskActor
            {
                private LongInvokeBucket _Bucket;
                private List<int> _List;
                public List<String> Resulte;
                public TaskActor(LongInvokeBucket bucket,List<int> list)
                {
                    _Bucket = bucket;
                    _List = list;
                }
                public void Do()
                {
                    _Bucket.TaskName = "Long Invoke Test";
                    for (int i = 0; i < 10; i++)
                    {
                        _Bucket.Tips = "执行" + i + "项操作...";
                        _Bucket.Percent = _Bucket.Percent + 5;
                        Thread.Sleep(1000 * 1);
                        if (i > 5 && _List[0] == 101) throw new Exception("碰到错误了,Func!");
    
                    }
                    _Bucket.Tips = "执行数据保存操作...";
                    _Bucket.Percent = 99;
                    Thread.Sleep(1000 * 3);
                    _Bucket.Tips = "任务执行完成";
                    Resulte = new List<String>() { "123", "abc", "ABC","EFG" };
                }
    
            }
        }
    }
    View Code
        public class LongInvokeBucket:LongInvokeBucketInfo
        {
            public LongInvokeBucket()
            {
                IsFree = true;
            }
            public void P(String tips)
            {
                this.Tips = tips;
            }
            public void P(String tips, int percent)
            {
                this.Tips = tips;
                this.Percent = percent;
            }
            public void P(int percent)
            {
                this.Percent = percent;
            }
                
        }
    
        public enum LongInvokeStatus { Init=-1,Running = 1, Finish_Success = 0, Finish_Fail = 2 }
    
        public class LongInvokeBucketInfo
        {
            public int Id { get; set; }
            public String TaskName { get; set; }
            public String Tips { get; set; }
            public int Percent { get; set; }
            /// <summary>
            /// 结束_失败
            /// 结束_成功
            /// 执行中
            /// </summary>
            public LongInvokeStatus Status { get; set; }
            public Object Model { get; set; }
            public String Guid { get; set; }
            public DateTime? BTime { get; set; }
            public DateTime? ETime { get; set; }
            /// <summary>
            /// 结果状态 
            /// 0:成功
            /// 其他执行失败
            /// </summary>
            public int Code { get; set; }
            public String Msg { get; set; }
            public bool IsFree { get; set; }
            public String Data { get; set; }
        }
    View Code
  • 相关阅读:
    java Future模式的使用
    Objects源码解析
    VUE优秀的组件库总结
    数据库的一致性读,赃读,多线程与赃读,ACID,UNDO
    线程基础,多线程架构,高并发,线程安全基础知识
    程序员必备的开发利器
    spring security 实现登录验证码及记住我
    springboot 集成 spring security 自定义登录
    ELK整合SpringBoot日志收集
    ElasticSearch整合SpringBoot的API操作
  • 原文地址:https://www.cnblogs.com/wdfrog/p/9875314.html
Copyright © 2011-2022 走看看