zoukankan      html  css  js  c++  java
  • Apply SOA Design Patterns with WCF (5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)

    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 { getset; }
     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/

    //我是结尾符,待续…

  • 相关阅读:
    DevExpress XtraReport报表预览时可编辑的功能
    vim编辑器的常用命令
    git 的一些常用命令
    ASP.NET MVC过滤器粗略总结
    违法占耕辅助处理软件
    三调管理信息系统
    java学习随笔源码day01
    Java学习笔记Day01-004之static关键字
    人事工资信息管理系统(核心代码实现、操作视频)
    人事工资信息管理系统之数据库设计
  • 原文地址:https://www.cnblogs.com/teddyma/p/1424710.html
Copyright © 2011-2022 走看看