前言:首先声明,此文题目算是标题党的一种,是本人为了完成与widows服务通信编程学习幻想出来的一个模型(并不是真的缓存数据库),并且会作为本人以后加深多线程、设计模式、非关系型数据库等方面学习的一个模型实例,毕竟有一个实际的模型更容易加深理解。
完成这部分模型,大概会做一下几件事情:
1、 创建一个Windows服务(用来寄存这个“缓存数据库”)
2、 创建一个WCF服务,寄宿在windows服务中(用于跟客户端通信,对“缓存数据库”进行增删查操作)
3、 创建客户端进行测试
第1步:WCF服务的创建及对缓存对象增删查的实现
WCF服务创建的过程及其Endpoint节点相关基础在这里不作累述,网上很多资料,这里直接贴Contract及其实现的代码,保存表数据的数据结构是Dictionary<string,DataTable>,其中key存放是表名,DataTable存放是数据。
1 using System; 2 3 using System.Collections.Generic; 4 5 using System.Data; 6 7 using System.Linq; 8 9 using System.Runtime.Serialization;10 11 using System.ServiceModel;12 13 using System.ServiceModel.Web;14 15 using System.Text;16 17 18 19 namespace SelfWcfService20 21 {22 23 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。24 25 [ServiceContract]26 27 public interface ISelfSQLData28 29 {30 31 [OperationContract]32 33 ExcuteResult CreateTable(string tableName, DataTable colNames);34 35 36 37 [OperationContract]38 39 ExcuteResult Insert(string tableName, SelfDataRow dr);40 41 42 43 [OperationContract]44 45 ExcuteResult Delete(string tableName, SelfDataRow dr);46 47 48 49 [OperationContract]50 51 ExcuteResult DropTable(string tableName);52 53 54 55 [OperationContract]56 57 Dictionary<string, DataTable> GetData(); 58 59 }60 61 62 63 [DataContract]64 65 public class SQLData66 67 {68 69 [DataMember]70 71 public Dictionary<string, DataTable> DataTables { get; set; } 72 73 }74 75 76 77 [DataContract]78 79 public class SelfDataRow80 81 {82 83 [DataMember]84 85 public DataTable DataTable { get; set; }86 87 }88 89 }
接口实现部分:
1 using System; 2 3 using System.Collections.Generic; 4 5 using System.Data; 6 7 using System.Linq; 8 9 using System.Runtime.Serialization; 10 11 using System.ServiceModel; 12 13 using System.ServiceModel.Web; 14 15 using System.Text; 16 17 18 19 namespace SelfWcfService 20 21 { 22 23 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。 24 25 // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。 26 27 public class SelfSQLData : ISelfSQLData 28 29 { 30 31 private static SQLData _sqlData; 32 33 public static SQLData SqlData 34 35 { 36 37 get 38 39 { 40 41 if (_sqlData == null) 42 43 { 44 45 _sqlData = new SQLData(); 46 47 } 48 49 if (_sqlData.DataTables == null) 50 51 { 52 53 _sqlData.DataTables = new Dictionary<string, System.Data.DataTable>(); 54 55 } 56 57 return _sqlData; 58 59 } 60 61 set 62 63 { 64 65 _sqlData = value; 66 67 } 68 69 } 70 71 72 73 private void InitalSqlData() 74 75 { 76 77 if (_sqlData == null) 78 79 { 80 81 _sqlData = new SQLData(); 82 83 } 84 85 if (_sqlData.DataTables == null) 86 87 { 88 89 _sqlData.DataTables = new Dictionary<string, System.Data.DataTable>(); 90 91 } 92 93 } 94 95 96 97 public ExcuteResult CreateTable(string tableName, DataTable colNames) 98 99 {100 101 if (string.IsNullOrWhiteSpace(tableName))102 103 {104 105 return new ExcuteResult(1, "表名不能为空!");106 107 }108 109 if (colNames == null || colNames.Columns.Count < 1)110 111 {112 113 return new ExcuteResult(1, "表字段不能为空!");114 115 }116 117 InitalSqlData();118 119 if (!_sqlData.DataTables.ContainsKey(tableName))120 121 {122 123 try124 125 {126 127 _sqlData.DataTables.Add(tableName, colNames);128 129 }130 131 catch (Exception ex)132 133 {134 135 return new ExcuteResult(1, ex.Message);136 137 }138 139 return new ExcuteResult(0, "表" + tableName + "创建成功!");140 141 }142 143 else144 145 {146 147 return new ExcuteResult(1, "已存在名为'" + tableName + "'的表");148 149 }150 151 }152 153 154 155 public ExcuteResult Insert(string tableName, SelfDataRow dr)156 157 {158 159 if (string.IsNullOrWhiteSpace(tableName))160 161 {162 163 return new ExcuteResult(1, "表名不能为空!");164 165 }166 167 if (dr == null)168 169 {170 171 return new ExcuteResult(1, "不能插入空的数据行!");172 173 }174 175 InitalSqlData();176 177 if (!_sqlData.DataTables.ContainsKey(tableName))178 179 {180 181 try182 183 {184 185 _sqlData.DataTables[tableName].Rows.Add(dr.DataTable.Rows[0]);186 187 }188 189 catch (Exception ex)190 191 {192 193 return new ExcuteResult(1, ex.Message);194 195 }196 197 return new ExcuteResult(0, "数据新增成功!");198 199 }200 201 else202 203 {204 205 return new ExcuteResult(1, "表'" + tableName + "'不存在!");206 207 }208 209 }210 211 212 213 public ExcuteResult Delete(string tableName, SelfDataRow dr)214 215 {216 217 if (string.IsNullOrWhiteSpace(tableName))218 219 {220 221 return new ExcuteResult(1, "表名不能为空!");222 223 }224 225 if (dr == null)226 227 {228 229 return new ExcuteResult(1, "请指定删除对象!");230 231 }232 233 InitalSqlData();234 235 if (!_sqlData.DataTables.ContainsKey(tableName))236 237 {238 239 try240 241 {242 243 _sqlData.DataTables[tableName].Rows.Remove(dr.DataTable.Rows[0]);244 245 }246 247 catch (Exception ex)248 249 {250 251 return new ExcuteResult(1, ex.Message);252 253 }254 255 return new ExcuteResult(0, "数据删除成功!");256 257 }258 259 else260 261 {262 263 return new ExcuteResult(1, "表'" + tableName + "'不存在!");264 265 }266 267 }268 269 270 271 public ExcuteResult DropTable(string tableName)272 273 {274 275 if (string.IsNullOrWhiteSpace(tableName))276 277 {278 279 return new ExcuteResult(1, "表名不能为空!");280 281 }282 283 InitalSqlData();284 285 if (!_sqlData.DataTables.ContainsKey(tableName))286 287 {288 289 try290 291 {292 293 _sqlData.DataTables.Remove(tableName);294 295 }296 297 catch (Exception ex)298 299 {300 301 return new ExcuteResult(1, ex.Message);302 303 }304 305 return new ExcuteResult(0, "表" + tableName + "删除成功!");306 307 }308 309 else310 311 {312 313 return new ExcuteResult(1, "表'" + tableName + "'不存在!");314 315 }316 317 }318 319 320 321 public Dictionary<string, DataTable> GetData()322 323 {324 325 return SqlData.DataTables;326 327 }328 329 }330 331 }
整个WCF实现的逻辑都在上面了,web配置文件不需要改,因为它不以web的形式发布寄宿在IIS中,而是windows服务中。
第2步:将WCF寄宿在Windows服务中
Windows服务的创建、安装、启动在这里也不作累述,跟WCF一样,网上资料也很多。这里重点介绍一下将WCF寄宿在Windows服务中。
(1) 将wcf项目的dll引用到windows服务项目中
(2) 在app.config文件中配置WCF终结点
1 <system.serviceModel> 2 3 <services> 4 5 <service behaviorConfiguration="BasicServiceBehavior" 6 7 name="SelfWcfService.SelfSQLData"> 8 9 <endpoint address="" binding="netTcpBinding" bindingConfiguration=""10 11 contract="SelfWcfService.ISelfSQLData">12 13 <!--<identity>14 15 <dns value="192.168.1.4" />16 17 </identity>-->18 19 </endpoint>20 21 <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""22 23 contract="IMetadataExchange" />24 25 <host>26 27 <baseAddresses>28 29 <add baseAddress="net.tcp://localhost:9000/SelfSQLData.svc"/>30 31 <add baseAddress="http://localhost:9001/SelfSQLData.svc"/>32 33 </baseAddresses>34 35 </host>36 37 </service>38 39 </services>40 41 <behaviors>42 43 <serviceBehaviors>44 45 <behavior name="BasicServiceBehavior">46 47 <serviceMetadata httpGetEnabled="true" />48 49 <serviceDebug includeExceptionDetailInFaults="true" />50 51 </behavior>52 53 </serviceBehaviors>54 55 </behaviors>56 57 <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0" />58 59 <bindings>60 61 <netTcpBinding>62 63 <binding name="defaultBinding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">64 65 <security mode="None">66 67 <message clientCredentialType="None"/>68 69 <transport clientCredentialType="None"></transport>70 71 </security>72 73 <readerQuotas />74 75 </binding>76 77 </netTcpBinding>78 79 </bindings>80 81 </system.serviceModel>
(3) 在windows服务启动的时候启动WCF服务
1 using SelfHelper; 2 3 using System; 4 5 using System.Collections.Generic; 6 7 using System.ComponentModel; 8 9 using System.Data;10 11 using System.Diagnostics;12 13 using System.Linq;14 15 using System.ServiceProcess;16 17 using System.Text;18 19 using System.ServiceModel;20 21 22 23 namespace SelfSQL24 25 {26 27 public partial class SelfSQLServer : ServiceBase28 29 {30 31 public SelfSQLServer()32 33 {34 35 InitializeComponent();36 37 }38 39 40 41 ServiceHost host = new ServiceHost(typeof(SelfWcfService.SelfSQLData));42 43 protected override void OnStart(string[] args)44 45 {46 47 LogWriter.WriteLog("服务已启动!");48 49 try50 51 {52 53 host.Open();54 55 LogWriter.WriteLog("WCF启动成功");56 57 }58 59 catch (Exception ex)60 61 {62 63 LogWriter.WriteLog("WCF启动异常:" + ex.ToString());64 65 }66 67 68 69 }70 71 72 73 protected override void OnStop()74 75 {76 77 LogWriter.WriteLog("服务已停止!");78 79 }80 81 }82 83 }
(4) 启动windows服务进行测试
第3步:创建客户端进行测试
首先在控制台程序中添加服务引用
然后就可以调用客户端对象进行测试了。
测试代码:
1 using System; 2 3 using System.Collections.Generic; 4 5 using System.Data; 6 7 using System.Linq; 8 9 using System.Text; 10 11 12 13 namespace SelfSQLClient 14 15 { 16 17 class Program 18 19 { 20 21 static void Main(string[] args) 22 23 { 24 25 SelfSQLServiceCilent.SelfSQLDataClient client = new SelfSQLServiceCilent.SelfSQLDataClient(); 26 27 DataTable dt1 = new DataTable(); 28 29 30 31 DataColumn idColumn = new DataColumn(); 32 33 idColumn.DataType = System.Type.GetType("System.Int32"); 34 35 idColumn.ColumnName = "t1"; 36 37 idColumn.AutoIncrement = true; 38 39 dt1.Columns.Add(idColumn); 40 41 42 43 DataColumn aColumn = new DataColumn(); 44 45 aColumn.DataType = System.Type.GetType("System.Int32"); 46 47 aColumn.ColumnName = "t2"; 48 49 aColumn.AutoIncrement = false; 50 51 dt1.Columns.Add(aColumn); 52 53 54 55 DataColumn bColumn = new DataColumn(); 56 57 bColumn.DataType = System.Type.GetType("System.DateTime"); 58 59 bColumn.ColumnName = "t3"; 60 61 bColumn.AutoIncrement = false; 62 63 dt1.Columns.Add(bColumn); 64 65 66 67 for (int i = 0; i < 3; i++) 68 69 { 70 71 DataRow dr = dt1.NewRow(); 72 73 dr[0] = i; 74 75 dr[1] = i + 1; 76 77 dr[2] = DateTime.Now; 78 79 dt1.Rows.Add(dr); 80 81 } 82 83 dt1.TableName = "FirstTable"; 84 85 client.CreateTable("FirstTable", dt1); 86 87 88 89 Dictionary<string, DataTable> dts = client.GetData(); 90 91 foreach (var dt in dts) 92 93 { 94 95 Console.WriteLine("表名:" + dt.Key); 96 97 string colNames = string.Empty; 98 99 foreach (var col in dt.Value.Columns)100 101 {102 103 colNames += col.ToString() + "--";104 105 }106 107 Console.WriteLine("字段:" + colNames); 108 109 foreach (DataRow val in dt.Value.Rows)110 111 {112 113 string vals = string.Empty;114 115 for (int i = 0; i < dt.Value.Columns.Count; i++)116 117 {118 119 vals += val[i] + "--";120 121 }122 123 Console.WriteLine("数据:" + vals);124 125 }126 127 }128 129 }130 131 }132 133 }
输出结果:
添加SecondTable表:
输出结果:
总结:
到这里相信大家都知道了,所谓的“缓存数据库”不过是个数据结构为Dictionary<string,DataTable>的静态变量而已,有人可能要问,直接定义在应用程序中不就完事了吗?还有必要又是创建WCF服务,又是创建Windows服务的吗?当然,在这里像玩具一般的“缓存数据库”确实没必要这么大费周章,它并不友好,要新增数据需要大量初始化DataTable对象的代码,它也承载不了太大的数据量,毕竟内存依旧在CLR托管堆中,它的稳定性与安全性更是无从谈起,因为毫无并发量较高的逻辑处理,但是,我做这件事情的初衷,并不是要写一个可以匹敌类似于redis一样的数据库,而是如前言所说,正因为这个“玩具”它存在这么多的缺陷,那么对这些缺陷进行一定程度完善的过程,也是加深对多线程、设计模式、非关系型数据库等方面学习的一个过程。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。