适合WebApi的简单的C#状态机实现
2014-07-28 08:58
369 查看
目标
采用了Restful WebApi的架构,再把业务逻辑状态转移放到后端就有点违背初衷了。实际上只要后端Api的权限设置的好,把状态转移放到前端也未尝不可。我考虑的结果是,一般如果变更这个状态本身就需要特定权限才可操作,比如xxx审批者,在前端处理状态逻辑问题不大,因为本身这个人就是有权限的,如果伪造请求破坏了数据也可以通过Log定位到个人,但是如果是面向大众的情况,比如团购下个订单什么的不对数据有特定权限要求的就需要在后端单独做动作类的WebApi了,欢迎讨论。相关传送门:Restful WebApi开发实践
先来看下最后的请求效果:(插件服务总线用的是服务定位器设计模式)
var result = BundleServiceBus.Current.GetInstance<IEventHandleService>() .EventTrigger<ExamEvent>(new ExamEvent { RootDataId = Id, Type = ET, }); if (result.IsSuccess) { Dispatcher.Invoke(() => MessageBox.Show("提交成功")); UpdateStudentInfo(ThisStudentInfo.Id); return; }
实现
这里我们将用到 C#对WebApi数据操作 里的方案来解决数据操作环节。首先定义状态基类:
abstract class StatusBase<RootDataType> { public ReturnHTTPData ReturnHttpData { get; set; } public abstract string Name { get; } public virtual bool Entry(BaseEvent arg) { return true; } public virtual bool Exit() { return true; } public abstract List<BaseTransferModel> TransferList { get; } public IModelDataService MDS = BundleServiceBus.Current.GetInstance<IModelDataService>(); public RootDataType RootData { get; set; } }
这里需要根据具体数据类型自定义一个业务状态基类,比如:
abstract class XXXStatusBase : StatusBase<StudentInfoModel> { public LoginUserInfoModel CurrentLoginUser { get { return MDS.GetDataByModel<LoginUserInfoModel, string>(DataParameter.Empty).Data.SingleOrDefault(); } } public bool ChangeRootDataStatus(string TargetStatus) { RootData.Status = TargetStatus; return ChangeRootDataInfo(RootData); } public bool ChangeRootDataInfo(StudentInfoModel model) { var result = MDS.PutDataByModel(new DataParameter<Guid> { TenantId = CurrentLoginUser.GetDataParameter().TenantId, AggregationId = CurrentLoginUser.GetDataParameter().AggregationId, SiteId = CurrentLoginUser.GetDataParameter().SiteId, DataId = model.Id, CMD = CurrentLoginUser.GetDataParameter().CMD }, model); //ReturnHttpData = new ReturnHTTPData { Content = result.Message }; return result.IsSuccess; } public bool AddBusinessLog(BusinessLogModel model) { //TODO 提交队列 var result = MDS.PostDataByModel<BusinessLogModel, Guid>(CurrentLoginUser.GetDataParameter(), model); //ReturnHttpData = new ReturnHTTPData { Content = result.Message }; return result.IsSuccess; } }
接下来定义一下状态转移模型基类:
abstract class BaseTransferModel { public string Target { get; set; } public abstract bool Condition(BaseEvent arg); public abstract bool Action(string target, BaseEvent arg); }
实现一个基于事件的状态转移模型:
class TransferModel<TEvent> : BaseTransferModel where TEvent : BaseEvent { public override bool Condition(BaseEvent arg) { var carg = arg as TEvent; return carg != null && ConditionFunc(carg); } public override bool Action(string target, BaseEvent arg) { var carg = arg as TEvent; return carg != null && ActionFunc(target, carg); } public Func<TEvent, bool> ConditionFunc { private get; set; } public Func<string, TEvent, bool> ActionFunc { private get; set; } }
剩下的就是状态机主体了,通过反射添加状态,并检查状态转移关系:
class StatusManager { public List<string> LostStatus { get; set; } private Dictionary<string, XXXStatusBase> StatusData = new Dictionary<string, XXXStatusBase>(); private IModelDataService MDS = BundleServiceBus.Current.GetInstance<IModelDataService>(); LoginUserInfoModel CurrentLoginUser { get { return MDS.GetDataByModel<LoginUserInfoModel, string>(DataParameter.Empty).Data.SingleOrDefault(); } } public StatusManager() { LostStatus = new List<string>(); var data = Assembly.GetExecutingAssembly().DefinedTypes.Where(s => s.BaseType == typeof(XXXStatusBase)); foreach (var typeInfo in data) { var status = Activator.CreateInstance(typeInfo) as XXXStatusBase; try { StatusData.Add(status.Name, status); } catch (Exception) { LostStatus.Add("AddError " + status.Name); } } //自检 foreach (var st in StatusData.Values) { foreach (var tr in st.TransferList) { if (StatusData.All(s => s.Key != tr.Target)) { LostStatus.Add(st.Name + " [To] " + tr.Target); } } } if (LostStatus.Count > 0) { Debug.WriteLine("Status has Errors!"); } } public List<Type> GetCurrentCanUseEvent(string Status) { var data = new List<Type>(); if (StatusData.Keys.All(s => s != Status)) return data; foreach (var transfer in StatusData[Status].TransferList) { data.AddRange(transfer.GetType().GenericTypeArguments); } return data; } public EventResult Trigger(BaseEvent arg) { //准备状态转移主体 var RootData = new StudentInfoModel { Status = "" }; if (arg.RootDataId != Guid.Empty) { var data = MDS.GetDataByModel<StudentInfoModel, Guid>(new DataParameter<Guid> { TenantId = CurrentLoginUser.GetDataParameter().TenantId, SiteId = CurrentLoginUser.GetDataParameter().SiteId, DataId = arg.RootDataId, }); if (!data.IsSuccess) { return new EventResult { IsSuccess = false, Result = data.Message }; } RootData = data.Data.SingleOrDefault(); } //状态转移引擎 if (StatusData.Keys.All(s => s != RootData.Status)) return new EventResult { IsSuccess = false, Result = "状态[" + RootData.Status + "]不存在" }; var status = StatusData[RootData.Status]; if (status == null) { return new EventResult { IsSuccess = false, Result = "NotFoundStatus" }; } status.RootData = RootData; foreach (var transfer in status.TransferList) { if (!transfer.Condition(arg)) continue; status.Exit(); if (!transfer.Action(transfer.Target, arg)) { if (status.ReturnHttpData == null) { status.ReturnHttpData = new ReturnHTTPData(); } return new EventResult { IsSuccess = false, Result = status.ReturnHttpData.Content, }; } if (StatusData.Keys.All(s => s != RootData.Status)) { if (status.ReturnHttpData == null) { status.ReturnHttpData = new ReturnHTTPData(); } return new EventResult { IsSuccess = true, Result = status.ReturnHttpData.Content, }; } if (StatusData[transfer.Target].Entry(arg)) { if (status.ReturnHttpData == null) { status.ReturnHttpData = new ReturnHTTPData(); } return new EventResult { IsSuccess = true, Result = status.ReturnHttpData.Content, }; } if (status.ReturnHttpData == null) { status.ReturnHttpData = new ReturnHTTPData(); } return new EventResult { IsSuccess = false, Result = status.ReturnHttpData.Content, }; } return new EventResult { IsSuccess = false, Result = "[" + arg.GetType() + "]操作不被允许" }; } }
具体添加一个状态:
class Status_XXX : XXXStatusBase { public override string Name { get { return "状态一"; } } public override List<BaseTransferModel> TransferList { get { var data = new List<BaseTransferModel>(); data.Add( new TransferModel<TargetEvent> { Target = "状态二", ConditionFunc = arg => arg.Type == CommitType.Final, ActionFunc = (target, model) => { if (model != null) { //变更状态 if (!ChangeRootDataStatus(target)) return false; //日志 return true; } return false; } }); return data; } } }
相关文章推荐
- Command模式的C#简单实现
- [C#]简单XP菜单的实现(一)
- 一个简单的AJAX实现,基于C#的ASP.Net,包括服务器端的程序代码
- 如何用C#在winform中实现简单的查找功能
- 用C#实现简单的控件数组
- 内容分页简单实现代码及祥解(C#)
- xmlHTTP xmlDOC 与 C#中DataSet的结合 实现AJAX简单示例
- 在C#中实现托盘是多么简单
- C#的附件上传的简单实现
- 自定义线程池-c#的简单实现
- c# 中实现 winxp 风格的控件(超简单-zz)
- 用C#实现简单下载 (原创)
- C#2.0 - Object Pool 简单实现
- 一个简单的AJAX实现,基于C#的ASP.Net,包括服务器端的程序代码
- 用C#简单实现主表与子表的联动关系
- 用C#实现的简单PL0 to C 编译器
- C#实现简单WEB服务器
- 用C#实现简单的字幕动态叠加效果
- 一个C#实现的最简单的委托例子
- xmlHTTP xmlDOC 与 C#中DataSet的结合 实现AJAX简单示例