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
  • 相关阅读:
    CQUOJ 10819 MUH and House of Cards
    CQUOJ 9920 Ladder
    CQUOJ 9906 Little Girl and Maximum XOR
    CQUOJ 10672 Kolya and Tandem Repeat
    CQUOJ 9711 Primes on Interval
    指针试水
    Another test
    Test
    二分图匹配的重要概念以及匈牙利算法
    二分图最大匹配
  • 原文地址:https://www.cnblogs.com/wdfrog/p/9875314.html
Copyright © 2011-2022 走看看