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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)