WF是什么,许多对NET技术有了解的人能说出一点,但又说不清楚
不论你认为WF是什么,但不要与Jbpm ,Shark ,Biztalk,SharePoint 这些产品做比效,这些产品有共同的特点就是面向企业业务流程应用的产品,WF不是,WF面向的开发人员
WF是一个使用XML描述,具有IOC、AOP功能的面向流程控制的开发平台.
我从事工作流开发有8年了,学习WF已经有5年了,在博客园写关于WF的主题博客也快4年了,自从接触WF后我一直在解释WF与传统工作流之间的区别,以下是这方面的一些文章
WF不是工作流 2007-05-17
WF不是工作流(后续) 2007-05-18
再谈WF 2007-07-20
WF与Windows操作系统的对比 2008-06-14
我们为什么需要WF 2009-02-20
可能是我即从事工作流开发,从学习WF,同时又用WF开发工作流,所以使很多看我博客的人误认为WF就是象Jbpm ,Shark ,Biztalk,SharePoint 这些产品一样专门用来开发企业业务流程的.
上面列出的文章标上了写作日期,可以证明我一直在向大家说明这个问题,但现在看来是不够的.所以我决定再写一个系列,用一些具体应用来全面介绍一下WF
(以前写过的内容我就不再重复了,想了解WF的朋友可以看一下上面列出的文章
如果是开发COM+的朋友,看了今天的例子,会发现这个例子的思路与用COM+构建数据逻辑层非常像.
其实WF3.X + WCF 就是一种替代COM+ 的方案, 但到了WF4.0 有些变化,MS提供了独立的服务用于发布WCF与WF,这种方式比WF3.X + WCF更象COM+了,这些内容我以后再写一个系列,下面看本文的例子
本文例子下载:
http://files.cnblogs.com/foundation/WFWCF.rar
项目说明
数据库,在WFWCF.rar文件中
一般在构建企业应用时,会构建一个[数据逻辑层].通常的结构如下
本例将用一个简单的例子讲解一下基于WF与WCF构建[数据逻辑层]
这是一个简单的数据库,但这个结构基本上是所用企业应用数据的初级模型
对数据操从本质上讲就是对表的[增,查,删,改],其实对一个单表的[增,查,删,改]是很简单的,
我通常将传统SQL[增,查,删,改]方式操作一个表的工作量定为 ( 1 * 表的字段个数)
如果有10无关系张表,工作量就为 ( 1 * 表1的字段个数) + ( 1 * 表2的字段个数) ...( 1 * 表10的字段个数)
这种工作是简单的,其实如果真的是这样的结构,我就不构建[数据逻辑层]了,直接UI 到 数据库,一个页面对一张表.
然而事实上表与表之间存在一个叫(关系/约束)的东西,现在问题复杂了
假设
[表A.ID] 约束 [表B.ID]
那处理表[表A]时,要考虑[表B] ,处理表[表B]时,要考虑[表A] ,最大的问题是当添加[表A.ID] 约束 [表C.ID]时,之前为处理表[表A]的业务逻辑还要加入处理 [表C]的.
很多时候,真正处理数据的代码很简单,大量的时间都浪费在(关系/约束)的判断上
在本例将,我将对数据库的操作变为独立的单表[增,查,删,改]操作,将(关系/约束)的判断交给WF去做
TabB表的类结构
[DataContract()] public class TableB { [DataMember()] public string RowID { set; get; }
[DataMember()] public string ID { set; get; }
[DataMember()] public string Value { set; get; } } |
以下是几个方法
public static class dbManage { static string connectionString = "Data Source=.;Initial Catalog=testDB;Integrated Security=True";
//表[TabA]中是否存在[ID]的记? public static bool checkIDinTabA(string ID) { using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(connectionString)) { con.Open(); var command = con.CreateCommand(); command.CommandText = string.Format("select ID from TableA where ID='{0}'", ID); object obj = command.ExecuteScalar(); con.Close(); if (obj==null) { return false; } else { return true; } }
} //表[TabB]中是否存在指定[RowID]的记录
public static bool checkRowIDinTabB(string RowID) { using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(connectionString)) { con.Open(); var command = con.CreateCommand(); command.CommandText = string.Format("select RowID from TableB where RowID='{0}'", RowID); object obj = command.ExecuteScalar(); con.Close(); if (obj == null) { return false; } else { return true; } } }
//向表[TabB]中添加记录 public static void insertTabB(TableB row) {
using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(connectionString)) { con.Open(); var command = con.CreateCommand(); command.CommandText = string.Format("insert into TableB (RowID,ID,Value) values ('{0}','{1}','{2}')", row.RowID, row.ID, row.Value); command.ExecuteNonQuery(); con.Close(); } } } |
(看了这段代码,可能有人会说对数据库操作不加异常捕获,不加事务,不加锁定吗,因为是例子,所以省略了吗.答案是异常捕获,事务,锁定都在WF中设计)
只有上面的代码,是无法直接使用insertTabB(TableB row),因为RowID,与ID可能存在潜在的键冲突
所以[向表[TabB]中添加记录]我们要做如下业务逻辑判断
添加以下变量
添加一个流程图
流程设计参照[向表[TabB]中添加记录]我们要做的业务逻辑判断
可以使用ASP.NET , Winform ,WPF ,silverlight , 本例中使用WPF
在WPF客户端添加对上面WCF服务的引用
UI设计
代码
private void button1_Click(object sender, RoutedEventArgs e) { wcfServer.ServiceClient ser = new wcfServer.ServiceClient();
wcfServer.TableB row = new wcfServer.TableB(); row.ID = ID.Text;
row.RowID = RowID.Text;
row.Value = Value.Text;
string message= ser.insertData(row);
MessageBox.Show(message);
} |
关于异常捕获,事务,锁定
WF提供了这些容器,具体的使用可参考我写的[WF4.0 基础篇]这个系列
本例只是在[flowChar]的最外层添加了一个异常捕获,