Apply SOA Design Patterns with WCF (5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)

本文介绍如何利用WCF技术实现一个强大的ASP.NET数据源控件,该控件能够简化数据库CRUD操作,尤其针对复杂的分页排序场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Original (原创) by Teddy’s Knowledge Base

Content (目录)

(1) WCF Configuration Centralization (WCF配置集中管理)

(2) WCF Automatic Deployment (WCF自动化部署)

(3) WCF Automatic Service Locating (WCF自动化服务定位)

(4) WCF Database Paging & Sorting (WCF数据库分页和排序)

(5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)

(6) 1 + 2 + 3 + 4 + 5 = ?

English Version

摘要

本文介绍如何实现一个基于WCF的ASP.NET数据源控件,从而使得跨WCF通信的数据库CRUD,尤其是复杂的分页排序更简单。

正文

我们需要基于WCF的ASP.NET数据源控件吗?

ASP.NET的数据源设计是的 ASP.NET页面上的数据绑定十分简单,但是.NET Framework到目前为止内置提供的DataSource控件,对WCF的支持都不是很方便。SqlDataSource和LinqDataSource暴露了太多SQL的细节,仅支持SQL Server数据库,并且完全不支持WCF;ObjectDataSOource则太通用了,以至于仅仅为了实现一个很简单的数据库分页排序功能也需要写很多代码。因此,如果我们基于WCF和ASP.NET来实现SOA,那么,一个基于WCF的ASP.NET数据源控件绝对值得去设计。

我们手头都有哪些武器了?
实现

首先,我们可以定义一个为所有的查询共享的WCF服务契约。下面的代码是IQueryService服务契约:

 1      [ServiceContract]
 2       public   interface  IQueryService
 3      {
 4          [OperationContract]
 5          DataTable Select(Criteria criteria);
 6          [OperationContract]
 7           int  SelectCount(Criteria criteria);
 8          [OperationContract]
 9           int  Update(Criteria criteria, DataTable modifiedTable, ConflictOption conflictDetection);
10      }

然后,我们可以为上面这个服务契约,定义一个基于查询对象的默认的实现:

 1       public   sealed   class  QueryService : IQueryService
 2      {
 3           public  DataTable Select(Criteria criteria)
 4          {
 5               if  (criteria  ==   null )
 6                   throw   new  ArgumentNullException( " criteria " );
 7 
 8               using  (var adapter  =   new  QueryCommandFactory(criteria).GetQueryDataAdapter())
 9              {
10                  var connection  =  adapter.SelectCommand.Connection;
11                   try
12                  {
13                       if  (connection.State  !=  ConnectionState.Open)
14                          connection.Open();
15                      var table  =   new  DataTable(criteria._tableName);
16                      adapter.Fill(table);
17                       return  table;
18                  }
19                   finally
20                  {
21                       if  (connection.State  !=  ConnectionState.Closed)
22                          connection.Close();
23                      connection.Dispose();
24                  }
25              }
26          }
27 
28           public   int  SelectCount(Criteria criteria)
29          {
30               if  (criteria  ==   null )
31                   throw   new  ArgumentNullException( " criteria " );
32 
33               using  (var cmd  =   new  QueryCommandFactory(criteria).GetCountCommand())
34              {
35                  var connection  =  cmd.Connection;
36                   try
37                  {
38                       if  (connection.State  !=  ConnectionState.Open)
39                          connection.Open();
40                       return  Convert.ToInt32(cmd.ExecuteScalar());
41                  }
42                   finally
43                  {
44                       if  (connection.State  !=  ConnectionState.Closed)
45                          connection.Close();
46                      connection.Dispose();
47                  }
48              }
49          }
50 
51           public   int  Update(Criteria criteria, DataTable modifiedTable, ConflictOption conflictDetection)
52          {
53               if  (criteria  ==   null )
54                   throw   new  ArgumentNullException( " criteria " );
55 
56               using  (var adapter  =   new  QueryCommandFactory(criteria).GetUpdatableQueryDataAdapter(conflictDetection))
57              {
58                  var connection  =  adapter.SelectCommand.Connection;
59                   try
60                  {
61                       if  (connection.State  !=  ConnectionState.Open)
62                          connection.Open();
63                       return  adapter.Update(modifiedTable);
64                  }
65                   finally
66                  {
67                       if  (connection.State  !=  ConnectionState.Closed)
68                          connection.Close();
69                      connection.Dispose();
70                  }
71              }
72          }
73      }

最后,只要通过能和第三方服务定位器整合的ServiceManager类,参见文章(3),如果我们能实现一个带一个Criteria属性作为查询的输入的数据源控件,我们就能很容易的基于能自动化的定位的IQueryService服务的实现CRUD。要实现一个自定义的自定义的数据源控件,可以参考.NET Framework中的SqlDataSource控件的实现,下面的代码是这个基于WCF的QueryDataSource控件的实现摘要:

  1       public   sealed   class  QueryDataSource : DataSourceControl
  2      {
  3           #region  Private Fields
  4 
  5           //
  6 
  7           #endregion
  8 
  9           #region  Protected Methods
 10 
 11           protected   override  DataSourceView GetView( string  viewName)
 12          {
 13               if  (_view  ==   null )
 14                  _view  =   new  QueryDataSourceView( this );
 15               return  _view;
 16          }
 17 
 18           protected   override   void  OnInit(System.EventArgs e)
 19          {
 20               base .OnInit(e);
 21 
 22               if  (HttpContext.Current  ==   null )
 23                   return ;
 24               if  ( ! UseLocalQueryService)
 25              {
 26                  _locator  =  ServiceManager.GetServiceLocator( typeof (IQueryService));
 27                  _service  =  _locator.GetService < IQueryService > ();
 28              }
 29               else
 30              {
 31                  var serviceType  =  Type.GetType(_defaultQueryServiceImplType);
 32                  _service  =  (IQueryService)Activator.CreateInstance(serviceType);
 33                   if  (_service  ==   null )
 34                       throw   new  FileLoadException( " Could not load assembly - NIntegrate.Query.Command.dll. " );
 35              }
 36          }
 37 
 38           #endregion
 39 
 40           #region  Public Properties
 41 
 42          [Category( " Data " ), DefaultValue( false ), Description( " When the value of this property equals true, it always using NIntegrate.Query.Command.QueryService class as QueryService insteads of trying to get the IQueryService implementation instance from ServiceManager class. " )]
 43           public   bool  UseLocalQueryService {  get set ; }
 44 
 45          [Category( " Data " ), Description( " Specify the criteria. " )]
 46           public  Criteria Criteria
 47          {
 48               internal   get
 49              {
 50                   if  (_criteria  ==   null   &&  EnableViewState
 51                       &&  ViewState[ " Criteria " !=   null )
 52                  {
 53                      _criteria  =  QueryHelper.CriteriaDeserialize(
 54                          ( string )ViewState[ " Criteria " ]);
 55                  }
 56 
 57                   return  _criteria;
 58              }
 59               set
 60              {
 61                   if  (value  ==   null )
 62                       return ;
 63 
 64                  _criteria  =  value;
 65                   if  (EnableViewState)
 66                      ViewState[ " Criteria " =  QueryHelper.CriteriaSerialize(value.ToBaseCriteria());
 67              }
 68          }
 69 
 70           //
 71 
 72           #endregion
 73 
 74           #region  Events
 75 
 76           //
 77 
 78           #endregion
 79 
 80           #region  Dispose()
 81 
 82           public   override   void  Dispose()
 83          {
 84              Dispose( true );
 85              GC.SuppressFinalize( this );
 86          }
 87 
 88           private   bool  disposed;
 89 
 90           private   void  Dispose( bool  disposing)
 91          {
 92               if  (disposed)  return ;
 93               if  (disposing)
 94              {
 95                  var dispose  =  _service  as  IDisposable;
 96                   if  (dispose  !=   null )
 97                      dispose.Dispose();
 98                   if  (_locator  !=   null )
 99                      _locator.Dispose();
100              }
101 
102              disposed  =   true ;
103          }
104 
105           ~ QueryDataSource()
106          {
107              Dispose( false );
108          }
109 
110           #endregion
111      }
112 
113       internal   sealed   class  QueryDataSourceView : DataSourceView
114          {
115               #region  Private Membes
116 
117               //
118 
119               #endregion
120 
121               #region  Constructors
122 
123               internal  QueryDataSourceView(QueryDataSource owner)
124                  :  base (owner,  " Default " )
125              {
126                   if  (owner  ==   null )
127                       throw   new  ArgumentNullException( " owner " );
128 
129                  _owner  =  owner;
130              }
131 
132               #endregion
133 
134               #region  Public Properties
135 
136               public   override   bool  CanInsert
137              {
138                   get
139                  {
140                       return   true ;
141                  }
142              }
143 
144               public   override   bool  CanUpdate
145              {
146                   get
147                  {
148                       return   true ;
149                  }
150              }
151 
152               public   override   bool  CanDelete
153              {
154                   get
155                  {
156                       return   true ;
157                  }
158              }
159 
160               public   override   bool  CanRetrieveTotalRowCount
161              {
162                   get
163                  {
164                       return   true ;
165                  }
166              }
167 
168               public   override   bool  CanPage
169              {
170                   get
171                  {
172                       return   true ;
173                  }
174              }
175 
176               public   override   bool  CanSort
177              {
178                   get
179                  {
180                       return   true ;
181                  }
182              }
183 
184               #endregion
185 
186               #region  Protected Methods
187 
188               protected   override   int  ExecuteInsert(IDictionary values)
189              {
190                   //
191 
192                  var table  =  _owner._service.Select(criteria);
193                  var row  =  table.NewRow();
194                  var en  =  values.GetEnumerator();
195                   while  (en.MoveNext())
196                  {
197                       if  (table.Columns.Contains(en.Key.ToString()))
198                          row[en.Key.ToString()]  =  TransformType(table.Columns[en.Key.ToString()].DataType, en.Value);
199                  }
200                  table.Rows.Add(row);
201 
202                  var conflictDetection  =  ConflictOption.OverwriteChanges;
203                   if  (_owner.ConflictDetection  ==  ConflictOptions.CompareAllValues)
204                  {
205                      conflictDetection  =  ConflictOption.CompareAllSearchableValues;
206                  }
207 
208                  var affectedRows  =  _owner._service.Update(_owner.Criteria, table, conflictDetection);
209 
210                   //
211              }
212 
213               protected   override   int  ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues)
214              {
215                  //
216 
217                  var table  =  _owner._service.Select(criteria);
218                   if  (table  ==   null   ||  table.Rows.Count  ==   0 )
219                       throw   new  DataException( " No row is matching specified key values. " );
220                   if  (table.Rows.Count  >   1 )
221                       throw   new  DataException( " More than one rows are matching specified key values, please check the key columns setting. " );
222                  var row  =  table.Rows[ 0 ];
223                  var conflictDetection  =  ConflictOption.OverwriteChanges;
224                   if  (_owner.ConflictDetection  ==  ConflictOptions.CompareAllValues)
225                  {
226                      DetectDataRowConflicts(oldValues, row);
227                      conflictDetection  =  ConflictOption.CompareAllSearchableValues;
228                  }
229 
230                  var en  =  values.GetEnumerator();
231                   while  (en.MoveNext())
232                  {
233                       if  (table.Columns.Contains(en.Key.ToString()))
234                          row[en.Key.ToString()]  =  TransformType(table.Columns[en.Key.ToString()].DataType, en.Value);
235                  }
236 
237                  var affectedRows  =  _owner._service.Update(_owner.Criteria, table, conflictDetection);
238 
239                   //
240              }
241 
242               protected   override   int  ExecuteDelete(IDictionary keys, IDictionary oldValues)
243              {
244                   //
245 
246                  var table  =  _owner._service.Select(criteria);
247                   if  (table  ==   null   ||  table.Rows.Count  ==   0 )
248                       throw   new  DataException( " No row is matching specified key values. " );
249                   if  (table.Rows.Count  >   1 )
250                       throw   new  DataException( " More than one rows are matching specified key values, please check the key columns setting. " );
251 
252                  var row  =  table.Rows[ 0 ];
253                  var conflictDetection  =  ConflictOption.OverwriteChanges;
254                   if  (_owner.ConflictDetection  ==  ConflictOptions.CompareAllValues)
255                  {
256                      DetectDataRowConflicts(oldValues, row);
257                      conflictDetection  =  ConflictOption.CompareAllSearchableValues;
258                  }
259 
260                  row.Delete();
261 
262                  var affectedRows  =  _owner._service.Update(_owner.Criteria, table, conflictDetection);
263                   //
264              }
265 
266               protected   override  IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
267              {
268                   //
269 
270                   if  (arguments  !=   null   &&  arguments  !=  DataSourceSelectArguments.Empty)
271                  {
272                       // adjust criteria according to arguments
273                       if  (arguments.RetrieveTotalRowCount)
274                      {
275                          arguments.TotalRowCount  =  _owner._service.SelectCount(criteria);
276                          _owner.LastTotalCount  =  arguments.TotalRowCount;
277                      }
278                       if  (arguments.MaximumRows  >   0 )
279                          criteria.MaxResults(arguments.MaximumRows);
280                       if  (arguments.StartRowIndex  >   0 )
281                          criteria.SkipResults(arguments.StartRowIndex);
282                       if  ( ! string .IsNullOrEmpty(arguments.SortExpression))
283                      {
284                           if  (_owner.AlwaysAppendDefaultSortBysWhenSorting)
285                              InsertSortExpressinAtTopOfSortBys(arguments.SortExpression, criteria);
286                           else
287                          {
288                              criteria._sortBys.Clear();
289                              AppendSortExpression(criteria, arguments.SortExpression);
290                          }
291                      }
292                  }
293 
294                   return   new  DataView(_owner._service.Select(criteria));
295              }
296 
297               #endregion
298          }

参考

(1) SOA Design Pattern Catalog: http://www.soapatterns.org/

//我是结尾符,待续…

Tag标签: nintegrate soa
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值