最近作了一个软件,这个软件不是网站,可是与HTML,AJAX等技术密切相关,也不是只有单纯的数据库增删改查,还涉及到线程协调,比较复杂的文本处理……数据库
这样的软件,用OA,ERP的框架显然是不合适的,由于这种软件用不上权限管理,工做流这些技术。可是软件又要操做数据库。服务器
介于这些的特殊性,想来想去,仍是本身搭建一个轻量级的软件框架是比较好的。app
一:C/S与B/S的选择框架
1,我作的是一个购物网站的刷单软件,有以下几个方面的缘由,我选择了C/S程序异步
a,刷单软件须要长时间的运行,不定时,不间断的去访问购物网站。ide
b,有时候有多个线程的须要。工具
c,程序运行时,须要操做本地文件的权限,要把关键页面截图(如添加收藏,货比三家)保存到本地,而后上传到服务器。网站
d,C#的Httpresponse,HttpRequest对象运行在不一样的电脑上,有不一样的外网IP,若是作成网站,Httpresponse,HttpRequest永远只是在服务器上运行,外网IP只有一个。ui
2,在桌面运用程序方面,我感受用WPF要比用WinForm好。this
a,WPF的UI作出的产品确定要比WinForm专业,这一点是谁都不可否认的。
b,WPF技术运用了XAML语法,这个比WinForm好用。
c,WPF能够用到MVVM模式,这点WinForm是永远都作不到的,而且MVVM有比较成熟的产品(MVVMLight, Caliburn.Micro,Prism)等产品
在这儿选用的是Caliburn.Micro框架,优势在于有命名的自动匹配,发布/订阅的消息模式,IOC的解耦,我举两个例子说明一下吧:
例一,IOC建立对象
个人项目 Trade.WPFClient 要用到 Trade.WPFBusinessPart 的页面,正常状况下 Trade.WPFClient 要添加项目 Trade.WPFBusinessPart的引用。
可是用Caliburn.Micro是不用添加引用的。
只添要在引导程序中AppBootstrapper.cs中的配置加添加以下代码:
protected override void Configure() { foreach (var file in System.IO.Directory.GetFiles(System.IO.Directory.GetCurrentDirectory(), "Trade.*.dll")) { AssemblySource.Instance.Add(Assembly.LoadFile(file)); } var catalog = new AggregateCatalog( AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()); this.container = new CompositionContainer(catalog); var batch = new CompositionBatch(); batch.AddExportedValue<IWindowManager>(new WindowManager()); batch.AddExportedValue<IEventAggregator>(new EventAggregator()); batch.AddExportedValue(this.container); batch.AddExportedValue(catalog); this.container.Compose(batch); }
在使用的时候,用IOC的方式建立对象:
UserCenterViewModel userCenter = (UserCenterViewModel)IoC.Get<IUserCenter>(); bool? userCenterVal = IoC.Get<IWindowManager>().ShowDialog(userCenter);
根本就不用引用一个类库,而后new一个对象。作到了高内聚,低耦合的原则。
例二:发布/订阅模式编
先要定义一个接口,个人项目是以 Trade.BaseInterface 这个类库做为个人接口库类。
在发布页面:
方法一是同步UI发布事件,
方法二是新开一个Task来发布一个事件。也就是异步发布事件。
而后在另一个页面接收这个发布的事件:
这样就实现了两个类库之间互相不添加引用的状况下,把消息通知给另一个类库。
二:数据库的持久化操做
数据库持久化操做经历了不少阶段,
1,SqlHelper阶段
2,enterprise library阶段
3,Ibatis,Dapper阶段
4,Linq, Nhibernate, EntityFramework阶段。
这几种操做,我在实战项目中都使用过,犹其是EntityFramework,无论是Code Frist 模式,Mode First模式,仍是Data First模式,好几年前就用在项目中作过比较了。
可是我最承认的仍是Dapper。
来一段码:
/// <summary> /// 根据用户ID获取用户的相关信息 /// </summary> /// <param name="dContext"></param> /// <param name="userID"></param> /// <returns></returns> public TradeUserModel GetTradeUserByUserID(DataContextBase dContext, String userID) { TradeUserModel result = default(TradeUserModel); String querySql = @"select * from TradeUser where UserID = @UserID; select ROW_NUMBER() over (order by DoBindingDTime desc) as RowNo, * from Member where IsDelete = '0' and UserID = @UserID; select * from Member where IsDelete = '0' and IsCurrent = '1' and UserID = @UserID "; var multi = dContext.Connection.QueryMultiple(querySql, new { UserID = userID }, dContext.Transaction); result = multi.Read<TradeUserModel>().FirstOrDefault(); List<MemberModel> memberList = multi.Read<MemberModel>().ToList(); MemberModel currentMember = multi.Read<MemberModel>().FirstOrDefault(); result.MemberList = new ObservableCollection<MemberModel>(memberList); MoneyRepository moneyRepository = new MoneyRepository(); decimal totalMoneyIn = moneyRepository.GetBusinessMoneyByUserID(dContext, userID, "In", new string[] { "RechargeMoney", "" }); decimal totalMoneyOut = moneyRepository.GetBusinessMoneyByUserID(dContext, userID, "Out", new string[] { "TakeMoney", "TaskOut", }); decimal totalTransferMoneyIn = moneyRepository.GetBusinessMoneyByUserID(dContext, userID, "In", new string[] { "TransferMoneyIn", "" }); decimal totalTransferMoneyOut = moneyRepository.GetBusinessMoneyByUserID(dContext, userID, "Out", new string[] { "TransferMoneyOut", "" }); result.TotalEnableMoney = totalMoneyIn + totalMoneyOut; result.TotalNotEnableMoney = 0; result.TotalTransferMoney = totalTransferMoneyIn + totalTransferMoneyOut; result.CurrentMember = currentMember; // currentMember ?? new MemberModel(); return result; }
我一段Sql执行了三个查询,用QueryMultiple取得不一样的查询结果,最神奇的地方,是查询出来的字段,不用手动赋值,Dapper能够自动实现。好比
public List<InvitationModel> GetInvitationCollectionByOwner(DataContextBase dContext, InvitationModel invitationData) { List<InvitationModel> result = default(List<InvitationModel>); String querySql = @"select ROW_NUMBER() over (order by CreateDTime desc) as RowNo , tu1.UserName as OwnerInfoName, tu2.UserName as ComputerUniqueName, i.* from Invitation i left join TradeUser tu1 on i.OwnerInfo = tu1.UserID left join TradeUser tu2 on i.ComputerUnique = tu2.UserID where OwnerInfo = @OwnerInfo;"; result = dContext.Connection.Query<InvitationModel>(querySql, invitationData, dContext.Transaction).ToList(); return result; }
这样的我查询结果就直接 赋值给 InvitationModel 类了。
三:项目中实体对象的共用
理论上,应该要申明一个类与表的字段对应
若是是用WCF做为通讯传输,还得声明一个DataContract 数据契约类
若是是用的MVVM框,还得要有一个ViewModel类
三个类这间,要转换赋值,有相似 automapper 这样的工具,可是我仍是不建议转换去,转换来的。
我直接把这个三个不一样地方的类给共用起来。
好比个人实体类以下:
[DataContract] public class LogModel : NotifyPropertyChanged { private Guid _logID; [DataMember] public Guid LogID { get { return _logID; } set { _logID = value; OnPropertyChanged("LogID"); } } ……
1,能够运做WCF的数据契约传输,
2,还能够做为MVVM的ViewModel
3,还能够与数据库字段在ORM时相互映射
一箭三雕啊
结语:
这个项目还运用到了不少技术,如如线程的管理,解析网页(网页异步加载情下)是怎么处理的?
等下一篇博客再说。
若是对这个软件感受兴趣的,可看上一篇博客。谢谢!