十九、【.Net开源】EFW框架核心类库之WCF控制器
EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U
EFW框架实例源代码下载:http://pan.baidu.com/s/1o6MAKCa
只有当你需要开发三层架构的系统并利用WCF作为系统的中间件,那么就需要使用WCF控制器。EFW框架中的Wcf控制器分为两个部分WcfClientController和WcfController,两者利用Wcf服务进行通讯,其中WcfClientController的功能与上章中的WinController控制器是一样的,而WcfController控制器就与WebController控制器类似实现客户端与后台逻辑的交互;WcfClientController是放在客户端中的与界面代码一个项目,而WcfController是放在后台WCF中间件中,这点我们一定要搞清楚,虽然安装包可以把所有程序集只打成一个,但是在程序运行的过程中客户端是不会执行后台的程序,而中间件也不会执行前台的程序,但是实体除外;实体在客户段只是作为一个数据结构使用,而在中间件除了可以当做数据结构,还能使用ORM中的相关操作;
本章主要内容通过解读框架源代码来学习WCF控制器是怎么实现的,以及学习控制器这种模式;还有就是框架中对于WCF服务使用仅仅只是为了实现客户端与服务端的通讯,并不会赞成把业务功能做成一个个服务提供给外部调用;然后把WCF通讯模块封装成了一个简单的WCF中间件程序;并且WCF中间件实现了路由器功能与负载均衡功能;
本文要点:
1.如何使用WCF控制器
2.WCF控制器的设计思路
3.控制器基类的BaseWCFClientController和BaseWCFController的实现
4.基于Json格式传递数据的JsonWCFController类的实现
5.自定义标签WCFControllerAttribute和WCFMethodAttribute的配置
6.客户端与服务端通讯WCF服务WCFHandlerService类的实现
WCF控制器源代码目录:
EFW框架控制器设计图:
1.如何使用WCF控制器
如上图,Book.Winform项目里包括界面文件frmBookManager.cs和WCF客户端控制器文件bookwcfclientController.cs,Books项目包括WCF控制器文件bookWcfController.cs,bookwcfclientController类继承框架中的BaseWCFClientController基类,bookWcfController类继承框架中的JsonWCFController基类。Books.Winform项目相当于WCF的客户端,Books项目就是WCF的服务端。
如上图,展示了bookwcfclientController客户端控制器与bookWcfController服务端控制器之间的调用关系;客户端执行保存书籍操作,通过InvokeWCFService方法访问服务端控制器,参数指定服务端控制器的名称bookWcfController和控制器的方法名称SaveBook,程序进入到服务端的bookWcfController对象并指定SaveBook方法中的逻辑代码保存数据到数据库;同样执行客户端获取书籍目录GetBook也是一样的过程,服务端GetBook返回的DataTable数据结构要转换为Json格式字符串传递到客户端,客户端接收Json数据再转换为DataTable绑定到界面上显示。
2.WCF控制器的设计思路
当初利用WCF技术设计三层架构的系统时,没想到是在控制器这层着手,想过在数据访问层做文章,把数据库操作对象oleDb封装成wcf服务,但是这样的话逻辑层代码等于要界面层代码一起,没有达到三层架构的目的,至少得逻辑层是在中间件上运行的;那么只得把把逻辑层封装成wcf服务,那必须把所有业务逻辑都进行一层包裹,开发的工作量不少,而且wcf服务多了部署起来又麻烦;后来想着WCF服务不能太多,一个就够了,而且逻辑层代码和界面层代码最好不需要更改,想着想着发现在控制器这层比较合适;把以前Winform版的控制器拆成两个部分客户端控制器和服务端控制器,客户端控制器的功能拥有Winform版控制器一样操作界面的职责,但不能调用逻辑层的代码的通过wcf服务访问服务端控制器,WCFHosting服务主机支撑着wcf服务端控制器的运行,对比web版系统WCFHosting服务主机相当于IIS,而wcf控制器相当于WebController控制器;所以这样一分析WCF系统就像Web版和Winform版的结合体,这样就让三种开发模式的各层代码达到最大化的重用,对比Winform版只需要改造一下控制器代码就由原来的二层架构变成了有中间件的三层模式;
Wcf客户端控制器必须继承框架中的BaseWCFClientController基类,wcf服务端控制器要继承JsonWCFController基类,而JsonWCFController又继承BaseWCFController基类;还有wcf服务器控制器类上需要指定自定义标签WCFControllerAttribute和WCFMethodAttribute;JsonWCFController类实现wcf服务利用Json格式进行数据传递,如果你觉得Json不适合可以自己扩展XMLWCFController或其他;WCFControllerAttribute和WCFMethodAttribute自定义标签标出系统中那些wcf控制器对象,这样客户端才能很方便的只要根据控制器名和方法名就可以访问控制器;
3.控制器基类的BaseWCFClientController和BaseWCFController的实现
框架中的源代码BaseWCFClientController基类的实现
BaseWCFClientController文件
1 /// <summary> 2 /// WCF控制器客户端基类 3 /// </summary> 4 public class BaseWCFClientController 5 { 6 private static readonly string myNamespace = "http://www.3yxx.com/"; 7 /// <summary> 8 /// 客户端标识 9 /// </summary> 10 public string ClientID 11 { 12 get 13 { 14 return EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFClientID").ToString(); 15 } 16 } 17 /// <summary> 18 /// wcf服务对象 19 /// </summary> 20 public IapiWCFHandlerService WCFService 21 { 22 get 23 { 24 IapiWCFHandlerService _wcfService= EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService; 25 if (WCFHeartbeat(_wcfService)==false)//|| ((System.ServiceModel.ClientBase<IapiWCFHandlerService>)(_wcfService)).State == CommunicationState.Faulted || ((System.ServiceModel.ClientBase<IapiWCFHandlerService>)(_wcfService)).State == CommunicationState.Closed) 26 { 27 //CreateWCFService(AppGlobal.cache.GetData("ClientService") as IClientService); 28 ReConnectionWCFService(AppGlobal.cache.GetData("ClientService") as IClientService); 29 _wcfService = EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService; 30 } 31 return _wcfService; 32 } 33 } 34 35 /// <summary> 36 /// 创建wcf服务 37 /// </summary> 38 /// <param name="mainfrm"></param> 39 public static void CreateWCFService(IClientService mainfrm) 40 { 41 try 42 { 43 NetTcpBinding binding = new NetTcpBinding("NetTcpBinding_WCFHandlerService"); 44 //binding.OpenTimeout = TimeSpan.FromSeconds(10); 45 //binding.TransferMode = TransferMode.Buffered; 46 DuplexChannelFactory<IapiWCFHandlerService> mChannelFactory = new DuplexChannelFactory<IapiWCFHandlerService>(mainfrm, binding, System.Configuration.ConfigurationSettings.AppSettings["WCF_endpoint"]); 47 IapiWCFHandlerService wcfHandlerService = mChannelFactory.CreateChannel(); 48 49 string routerID; 50 string mProxyID; 51 using (var scope = new OperationContextScope(wcfHandlerService as IContextChannel)) 52 { 53 // 注意namespace必须和ServiceContract中定义的namespace保持一致,默认是:http://tempuri.org 54 //var myNamespace = "http://www.3yxx.com/"; 55 // 注意Header的名字中不能出现空格,因为要作为Xml节点名。 56 routerID = Guid.NewGuid().ToString(); 57 var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, routerID); 58 OperationContext.Current.OutgoingMessageHeaders.Add(router); 59 mProxyID = wcfHandlerService.CreateDomain(GetLocalIPAddress()); 60 } 61 62 63 if (AppGlobal.cache.Contains("WCFClientID")) AppGlobal.cache.Remove("WCFClientID"); 64 if (AppGlobal.cache.Contains("WCFService")) AppGlobal.cache.Remove("WCFService"); 65 if (AppGlobal.cache.Contains("ClientService")) AppGlobal.cache.Remove("ClientService"); 66 if (AppGlobal.cache.Contains("routerID")) AppGlobal.cache.Remove("routerID"); 67 68 AppGlobal.cache.Add("WCFClientID", mProxyID); 69 AppGlobal.cache.Add("WCFService", wcfHandlerService); 70 AppGlobal.cache.Add("ClientService", mainfrm); 71 AppGlobal.cache.Add("routerID", routerID); 72 73 //开启发送心跳 74 if (timer == null) 75 StartSendWCFHeartbeat(); 76 else 77 timer.Start(); 78 } 79 catch (Exception err) 80 { 81 throw new Exception(err.Message); 82 } 83 } 84 /// <summary> 85 /// 重新连接wcf服务 86 /// </summary> 87 /// <param name="mainfrm"></param> 88 public static void ReConnectionWCFService(IClientService mainfrm) 89 { 90 try 91 { 92 NetTcpBinding binding = new NetTcpBinding("NetTcpBinding_WCFHandlerService"); 93 //binding.OpenTimeout = TimeSpan.FromSeconds(10); 94 //binding.TransferMode = TransferMode.Buffered; 95 DuplexChannelFactory<IapiWCFHandlerService> mChannelFactory = new DuplexChannelFactory<IapiWCFHandlerService>(mainfrm, binding, System.Configuration.ConfigurationSettings.AppSettings["WCF_endpoint"]); 96 IapiWCFHandlerService wcfHandlerService = mChannelFactory.CreateChannel(); 97 98 using (var scope = new OperationContextScope(wcfHandlerService as IContextChannel)) 99 { 100 var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString()); 101 OperationContext.Current.OutgoingMessageHeaders.Add(router); 102 wcfHandlerService.ReConnection(AppGlobal.cache.GetData("WCFClientID").ToString()); 103 } 104 105 if (AppGlobal.cache.Contains("WCFService")) AppGlobal.cache.Remove("WCFService"); 106 AppGlobal.cache.Add("WCFService", wcfHandlerService); 107 108 //开启发送心跳 109 if (timer == null) 110 StartSendWCFHeartbeat(); 111 else 112 timer.Start(); 113 } 114 catch (Exception err) 115 { 116 return; 117 } 118 } 119 120 //向服务端发送心跳,间隔时间为5s 121 static System.Timers.Timer timer; 122 static void StartSendWCFHeartbeat() 123 { 124 timer = new System.Timers.Timer(); 125 timer.Interval = 5000; 126 timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); 127 timer.Start(); 128 } 129 static Object syncObj = new Object();////定义一个静态对象用于线程部份代码块的锁定,用于lock操作 130 static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 131 { 132 lock (syncObj) 133 { 134 try 135 { 136 IapiWCFHandlerService _wcfService = EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService; 137 if (WCFHeartbeat(_wcfService) == false) 138 { 139 //CreateWCFService(AppGlobal.cache.GetData("ClientService") as IClientService); 140 ReConnectionWCFService(AppGlobal.cache.GetData("ClientService") as IClientService); 141 } 142 } 143 catch (Exception err) 144 { 145 146 throw new Exception(err.Message); 147 } 148 } 149 } 150 static bool WCFHeartbeat(IapiWCFHandlerService _wcfService) 151 { 152 try 153 { 154 using (var scope = new OperationContextScope(_wcfService as IContextChannel)) 155 { 156 var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString()); 157 OperationContext.Current.OutgoingMessageHeaders.Add(router); 158 return _wcfService.Heartbeat(AppGlobal.cache.GetData("WCFClientID").ToString()); 159 } 160 } 161 catch (Exception err) 162 { 163 timer.Stop(); 164 return false; 165 } 166 } 167 static string GetLocalIPAddress() 168 { 169 IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName()); 170 string myip = ""; 171 foreach (IPAddress ip in IpEntry.AddressList) 172 { 173 if (Regex.IsMatch(ip.ToString(), @"\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}")) 174 { 175 myip = ip.ToString(); 176 break; 177 } 178 } 179 return myip; 180 } 181 182 /// <summary> 183 /// 获取登录用户信息 184 /// </summary> 185 public SysLoginRight GetSysLoginRight 186 { 187 get 188 { 189 if (EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser") != null) 190 { 191 return (SysLoginRight)EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser"); 192 } 193 else 194 { 195 return new SysLoginRight(); 196 } 197 } 198 } 199 200 internal IBaseView _defaultView; 201 public IBaseView DefaultView 202 { 203 get { return _defaultView; } 204 } 205 206 private Dictionary<string, IBaseView> _iBaseView; 207 public Dictionary<string, IBaseView> iBaseView 208 { 209 get { return _iBaseView; } 210 set 211 { 212 _iBaseView = value; 213 foreach (KeyValuePair<string, IBaseView> val in _iBaseView) 214 { 215 //val.Value.ControllerEvent += new ControllerEventHandler(UI_ControllerEvent); 216 val.Value.InvokeController = new ControllerEventHandler(UI_ControllerEvent); 217 } 218 } 219 } 220 221 public CloseTab closeTab; 222 223 /// <summary> 224 /// 创建BaseWCFClientController的实例 225 /// </summary> 226 public BaseWCFClientController() 227 { 228 229 } 230 /// <summary> 231 /// 界面控制事件 232 /// </summary> 233 /// <param name="eventname">事件名称</param> 234 /// <param name="objs">参数数组</param> 235 /// <returns></returns> 236 public virtual object UI_ControllerEvent(string eventname, params object[] objs) 237 { 238 239 240 MethodInfo meth= this.GetType().GetMethod(eventname); 241 if (meth != null) 242 { 243 244 return meth.Invoke(this, objs); 245 } 246 247 switch (eventname) 248 { 249 case "Close": 250 if (closeTab != null) 251 closeTab(); 252 break; 253 case "this": 254 return this; 255 default: 256 break; 257 } 258 259 return null; 260 } 261 262 /// <summary> 263 /// 初始化全局web服务参数对象 264 /// </summary> 265 public virtual void Init() { } 266 267 public virtual IBaseView GetView(string frmName) 268 { 269 return iBaseView[frmName]; 270 } 271 272 public virtual Object InvokeWCFService(string controller, string method, string jsondata) 273 { 274 275 string retJson; 276 using (var scope = new OperationContextScope(WCFService as IContextChannel)) 277 { 278 var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString()); 279 OperationContext.Current.OutgoingMessageHeaders.Add(router); 280 retJson = WCFService.ProcessRequest(ClientID, controller, method, jsondata); 281 } 282 object Result = JavaScriptConvert.DeserializeObject(retJson); 283 int ret = Convert.ToInt32(((Newtonsoft.Json.JavaScriptObject)(Result))["flag"]); 284 string msg = ((Newtonsoft.Json.JavaScriptObject)(Result))["msg"].ToString(); 285 if (ret == 1) 286 { 287 throw new Exception(msg); 288 } 289 else 290 { 291 return ((Newtonsoft.Json.JavaScriptObject)(Result))["data"]; 292 } 293 } 294 295 public virtual Object InvokeWCFService(string controller, string method, params object[] data) 296 { 297 // 298 string jsondata = JavaScriptConvert.SerializeObject(data, new AspNetDateTimeConverter()); 299 return InvokeWCFService(controller, method, jsondata); 300 } 301 302 303 private object convertVal(Type t, object data) 304 { 305 object val = null; 306 if (t == typeof(Int32)) 307 val = Convert.ToInt32(data); 308 else if (t == typeof(DateTime)) 309 val = Convert.ToDateTime(data); 310 else if (t == typeof(Decimal)) 311 val = Convert.ToDecimal(data); 312 else if (t == typeof(Boolean)) 313 val = Convert.ToBoolean(data); 314 else if (t == typeof(String)) 315 val = Convert.ToString(data).Trim(); 316 else if (t == typeof(Guid)) 317 val = new Guid(data.ToString()); 318 else 319 val = data; 320 return val; 321 } 322 323 public object[] ToArray(object data) 324 { 325 return (data as Newtonsoft.Json.JavaScriptArray).ToArray(); 326 } 327 public List<T> ToListObj<T>(object data) 328 { 329 if (data is JavaScriptArray) 330 { 331 PropertyInfo[] pros = typeof(T).GetProperties(); 332 List<T> list = new List<T>(); 333 for (int i = 0; i < (data as JavaScriptArray).Count; i++) 334 { 335 T obj = (T)Activator.CreateInstance(typeof(T)); 336 object _data = (data as JavaScriptArray)[i]; 337 for (int k = 0; k < pros.Length; k++) 338 { 339 object val = convertVal(pros[k].PropertyType, (_data as JavaScriptObject)[pros[k].Name]); 340 pros[k].SetValue(obj, val, null); 341 } 342 list.Add(obj); 343 } 344 return list; 345 } 346 347 return null; 348 } 349 public DataTable ToDataTable(object data) 350 { 351 if (data is JavaScriptArray && (data as JavaScriptArray).Count>0) 352 { 353 JavaScriptObject _data = (data as JavaScriptArray)[0] as JavaScriptObject; 354 DataTable dt=new DataTable(); 355 foreach (var name in _data.Keys) 356 { 357 dt.Columns.Add(name, _data[name].GetType()); 358 } 359 360 for (int i = 0; i < (data as JavaScriptArray).Count; i++) 361 { 362 object _jsarray = (data as JavaScriptArray)[i]; 363 DataRow dr= dt.NewRow(); 364 for (int k = 0; k < dt.Columns.Count; k++) 365 { 366 dr[k] = convertVal(dt.Columns[k].DataType, (_jsarray as JavaScriptObject)[dt.Columns[k].ColumnName]); 367 } 368 dt.Rows.Add(dr); 369 } 370 371 return dt; 372 } 373 return null; 374 } 375 public T ToObject<T>(object data) 376 { 377 T obj = (T)Activator.CreateInstance(typeof(T)); 378 PropertyInfo[] pros = typeof(T).GetProperties(); 379 for (int k = 0; k < pros.Length; k++) 380 { 381 object val = convertVal(pros[k].PropertyType, (data as JavaScriptObject)[pros[k].Name]); 382 pros[k].SetValue(obj, val, null); 383 } 384 385 return obj; 386 } 387 388 }
框架中的源代码BaseWCFController基类的实现
BaseWCFController文件
1 /// <summary> 2 /// WCF控制器服务端基类 3 /// </summary> 4 public class BaseWCFController : AbstractBusines 5 { 6 /// <summary> 7 /// 数据库操作对象 8 /// </summary> 9 public AbstractDatabase oleDb 10 { 11 get 12 { 13 return _oleDb; 14 } 15 } 16 /// <summary> 17 /// 当前客户端信息 18 /// </summary> 19 public WCFClientInfo ClientInfo 20 { 21 get; 22 set; 23 } 24 /// <summary> 25 /// 当前登录用户信息 26 /// </summary> 27 public SysLoginRight GetSysLoginRight 28 { 29 get 30 { 31 if (ClientInfo != null && ClientInfo.LoginRight != null) 32 return ClientInfo.LoginRight; 33 return new SysLoginRight(); 34 } 35 } 36 37 //public ViewEventHandler ViewHandler 38 //{ 39 // get { return RemoteLoaderController.ViewHandler; } 40 //} 41 42 /// <summary> 43 /// 客户端传递的参数 44 /// </summary> 45 public string ParamJsonData 46 { 47 get; 48 set; 49 } 50 51 /// <summary> 52 /// 创建BaseWCFController的实例 53 /// </summary> 54 public BaseWCFController() 55 { 56 57 } 58 59 /// <summary> 60 /// 初始化全局web服务参数对象 61 /// </summary> 62 public virtual void Init() { } 63 }
BaseWCFClientController基类封装的功能包括:
1)WCF服务对象,利用InvokeWCFService方法就可以调用服务端控制器
2)系统登录后的用户信息GetSysLoginRight,这样客户端控制器中就可以很方便的获取登录用户信息;
3)与Winform版控制器类似的对界面操作的iBaseView
4)将Json字符串转换为对象的方法
BaseWCFController基类封装的功能包括:
1)数据库操作对象oleDb
2)系统的当前登录用户信息GetSysLoginRight
4.基于Json格式传递数据的JsonWCFController类的实现
框架中的源代码JsonWCFController基类,实现数据结构转换为Json格式的字符串;用Json格式主要是觉得它是一种轻量级的数据交换格式,还有就是和web版的保持一致;
JsonWCFController文件
1 /// <summary> 2 /// 基于Json格式的WCF服务基类 3 /// </summary> 4 public class JsonWCFController : BaseWCFController, IToJson, EFWCoreLib.WCFHandler.IJsonToObject 5 { 6 #region 值转换 7 private object convertVal(Type t, object data) 8 { 9 object val = null; 10 if (t == typeof(Int32)) 11 val = Convert.ToInt32(data); 12 else if (t == typeof(DateTime)) 13 val = Convert.ToDateTime(data); 14 else if (t == typeof(Decimal)) 15 val = Convert.ToDecimal(data); 16 else if (t == typeof(Boolean)) 17 val = Convert.ToBoolean(data); 18 else if (t == typeof(String)) 19 val = Convert.ToString(data).Trim(); 20 else if (t == typeof(Guid)) 21 val = new Guid(data.ToString()); 22 else 23 val = data; 24 return val; 25 } 26 #endregion 27 28 #region IToJson 成员 29 30 public string ToJson(object model) 31 { 32 string value = JavaScriptConvert.SerializeObject(model, new AspNetDateTimeConverter()); 33 return value; 34 } 35 36 public string ToJson(System.Data.DataTable dt) 37 { 38 string value = JavaScriptConvert.SerializeObject(dt); 39 return value; 40 } 41 42 public string ToJson(params object[] data) 43 { 44 string value = JavaScriptConvert.SerializeObject(data, new AspNetDateTimeConverter()); 45 return value; 46 } 47 48 #endregion 49 50 #region IJsonToObject成员 51 public T ToObject<T>(string json) 52 { 53 return JavaScriptConvert.DeserializeObject<T>(json); 54 } 55 56 public object ToObject(string json) 57 { 58 return JavaScriptConvert.DeserializeObject(json); 59 } 60 61 public object[] ToArray(object data) 62 { 63 return (data as Newtonsoft.Json.JavaScriptArray).ToArray(); 64 } 65 66 public List<T> ToListObj<T>(object data) 67 { 68 if (data is JavaScriptArray) 69 { 70 PropertyInfo[] pros = typeof(T).GetProperties(); 71 List<T> list = new List<T>(); 72 for (int i = 0; i < (data as JavaScriptArray).Count; i++) 73 { 74 T obj = (T)Activator.CreateInstance(typeof(T)); 75 object _data = (data as JavaScriptArray)[i]; 76 for (int k = 0; k < pros.Length; k++) 77 { 78 object val = convertVal(pros[k].PropertyType, (_data as JavaScriptObject)[pros[k].Name]); 79 pros[k].SetValue(obj, val, null); 80 } 81 list.Add(obj); 82 } 83 return list; 84 } 85 86 return null; 87 } 88 89 public DataTable ToDataTable(object data) 90 { 91 if (data is JavaScriptArray && (data as JavaScriptArray).Count > 0) 92 { 93 JavaScriptObject _data = (data as JavaScriptArray)[0] as JavaScriptObject; 94 DataTable dt = new DataTable(); 95 foreach (var name in _data.Keys) 96 { 97 dt.Columns.Add(name, _data[name].GetType()); 98 } 99 100 for (int i = 0; i < (data as JavaScriptArray).Count; i++) 101 { 102 object _jsarray = (data as JavaScriptArray)[i]; 103 DataRow dr = dt.NewRow(); 104 for (int k = 0; k < dt.Columns.Count; k++) 105 { 106 dr[k] = convertVal(dt.Columns[k].DataType, (_jsarray as JavaScriptObject)[dt.Columns[k].ColumnName]); 107 } 108 dt.Rows.Add(dr); 109 } 110 111 return dt; 112 } 113 return null; 114 } 115 116 public T ToObject<T>(object data) 117 { 118 T obj = (T)Activator.CreateInstance(typeof(T)); 119 PropertyInfo[] pros = typeof(T).GetProperties(); 120 for (int k = 0; k < pros.Length; k++) 121 { 122 object val = convertVal(pros[k].PropertyType, (data as JavaScriptObject)[pros[k].Name]); 123 pros[k].SetValue(obj, val, null); 124 } 125 126 return obj; 127 } 128 #endregion 129 }
5.自定义标签WCFControllerAttribute和WCFMethodAttribute的配置
配置WCFControllerAttribute和WCFMethodAttribute标签的目的就是减少暴露给客户端的对象,只有指定了标签的对象才能被客户端所调用;而且让客户端调用的方式更简单,只需指定控制器的名称和方法名就行了;所以后台代码不能有相同名称的控制器对象,如果指定相同的控制器名称那么识别不了;
WCFControllerAttribute文件
1 /// <summary> 2 /// WCF服务对象自定义标签 3 /// </summary> 4 [AttributeUsageAttribute(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] 5 public class WCFControllerAttribute : Attribute 6 { 7 string _memo; 8 public string Memo 9 { 10 get { return _memo; } 11 set { _memo = value; } 12 } 13 }
WCFMethodAttribute文件
1 [AttributeUsageAttribute(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 2 public class WCFMethodAttribute : Attribute 3 { 4 private string _openDBNames; 5 /// <summary> 6 /// 打开数据库,中间用,号隔开 7 /// </summary> 8 public string OpenDBKeys 9 { 10 get { return _openDBNames; } 11 set { _openDBNames = value; } 12 } 13 private string _memo; 14 public string Memo 15 { 16 get { return _memo; } 17 set { _memo = value; } 18 } 19 }
6.客户端与服务端通讯WCF服务WCFHandlerService类的实现
客户端与服务端是利用wcf服务进行通信的,而WCFHandlerService类就是实现的WCF服务对象,WCFHandlerService对象实现调用wcf服务端控制器的操作契约就是ProcessRequest方法,本章先讲解一下此核心方法,其他的功能在后面讲WcfHosting服务主机的时候会详细讲解;
WCFHandlerService文件
1 public string ProcessRequest(string mProxyID, string controller, string method, string jsondata) 2 { 3 try 4 { 5 if (Convert.ToInt32(HostSettingConfig.GetValue("debug")) == 1) 6 Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]正在执行:" + controller + "." + method + "(" + jsondata + ")"); 7 string retJson = Loader.ProcessRequest(mProxyID, controller, method, jsondata); 8 return "{\"flag\":0,\"msg\":" + "\"\"" + ",\"data\":" + retJson + "}"; 9 } 10 catch (Exception err) 11 { 12 if (err.InnerException == null) 13 { 14 Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.Message); 15 return "{\"flag\":1,\"msg\":" + "\"" + err.Message + "\"" + "}"; 16 } 17 else 18 { 19 Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.InnerException.Message); 20 return "{\"flag\":1,\"msg\":" + "\"" + err.InnerException.Message + "\"" + "}"; 21 } 22 } 23 }