寫在最前面:轉載請註明出處 目錄置頂: 關於項目 基於DDD領域驅動設計的WCF+EF+WPF分層框架(1) 架構搭建 基於DDD領域驅動設計的WCF+EF+WPF分層框架(2) WCF服務端具體實現 基於DDD領域驅動設計的WCF+EF+WPF分層框架(3) WCF客戶端配置以及代理 基於DDD領 ...
目錄置頂:
- 關於項目--------------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(1)
- 架構搭建--------------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(2)
- WCF服務端具體實現---------基於DDD領域驅動設計的WCF+EF+WPF分層框架(3)
- WCF客戶端配置以及代理-----基於DDD領域驅動設計的WCF+EF+WPF分層框架(4)
- Domain具體實現------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(5)
- WPF的UI層-----------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(6)
- 組織架構--------------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(7)
- 即時通訊--------------------基於DDD領域驅動設計的WCF+EF+WPF分層框架(8)
- 我的網站
架構搭建
架構是基於DDD領域驅動模型的,DDD的思想我就不介紹了,園裡有挺多的介紹了,另外在下麵的架構圖裡面也會有體現,架構圖本應該用UML圖展示一下的,我覺得麻煩,我直接把我的項目截一個圖介紹一下:
項目我分了四個解決方案文件夾:ACS.OA.Common、ACS.OA.UIClient、ACS.OA.WCFServer、ACS.OA.WebSite(這個本次博客不打算介紹,直接忽略)。
基礎設施層 ACS.OA.Common
這個文件夾裡面我建了Base、Global、Model、WCFContract四個項目,這四個項目大家看名稱就知道作用了。
Base的內部結構我也截一張圖吧
這個重點在CS文件夾裡面,Cache緩存類,Communication通訊類,CustomException 異常處理類,Lib幫助集合(比較多,我把截圖放旁邊了),Log日誌類(Log4Net)
我重點講一下通訊類Pactet數據包
1 /// <summary> 2 /// 打包、解包 3 /// </summary> 4 /// <typeparam name="T">數據類型 object</typeparam> 5 public abstract class Packet<T> 6 { 7 /// <summary> 8 /// 打包數據 9 /// </summary> 10 /// <param name="t"></param> 11 /// <param name="strKey">加密Key</param> 12 /// <returns></returns> 13 public static byte[] PacketData(T t, string strKey) 14 { 15 var jSetting = new JsonSerializerSettings(); 16 jSetting.NullValueHandling = NullValueHandling.Ignore; //忽略為NULL的值 17 18 byte[] bytContent; 19 string strJson = JsonConvert.SerializeObject(t, jSetting); //T轉Json 20 strJson = DESHelper.Encrypt(strJson, strKey); //加密 21 bytContent = SerializeHelper.Serialize(strJson); //壓縮轉byte[] 22 23 Init(bytContent); 24 return bytContent; 25 } 26 27 /// <summary> 28 /// 解包數據 29 /// </summary> 30 /// <param name="bytContent"></param> 31 /// <param name="strKey">解密Key</param> 32 /// <returns></returns> 33 public static T DePacketData(byte[] bytContent, string strKey) 34 { 35 var jSetting = new JsonSerializerSettings(); 36 jSetting.NullValueHandling = NullValueHandling.Ignore; //忽略為NULL的值 37 38 T t; 39 string strJson = SerializeHelper.Deserialize(bytContent).ToString(); //解壓縮轉string 40 strJson = DESHelper.Decrypt(strJson, strKey); //解密 41 t = (T)JsonConvert.DeserializeObject(strJson, typeof(T), jSetting); //Json轉T 42 return t; 43 } 44 45 }View Code
裡面的DESHelper的加密解密方法用的是TripleDESCryptoServiceProvider,需要的話自己引用一下就可以自己寫了,這個實例比較多,我就不貼代碼了。
我說一下我為何這麼做的原因
打包步驟:
我先把實體類轉為Json字元串目的為統一傳輸規則,這樣做不用考慮發送方和接收方是什麼語言開發的,接收方收到json解析就行了。
我又把Json串加密,這是為了安全考慮,數據傳輸用明文不安全吧。
轉byte[] 壓縮一下,文件會小很多,考慮的是傳輸效率。
解包步驟 就是打包的逆向了,不解釋了啊。
Lib幫助類集合裡面,我講一下WCFHandler類,先貼代碼
1 public class WCFHandler 2 { 3 public static T CreateHttpServiceClient<T>(string webAddress, string serviceName) 4 { 5 T t = default(T); 6 object obj = Activator.CreateInstance(typeof(T), new object[] 7 { 8 GetHttpBinding(), 9 GetEndpoint(webAddress, serviceName) 10 }); 11 t = (T)(obj); 12 return t; 13 } 14 15 public static T CreateTcpServiceClient<T>(string webAddress, string serviceName, bool isStream=false) 16 { 17 T t = default(T); 18 object obj; 19 if (isStream) //流傳輸 20 { 21 obj = Activator.CreateInstance(typeof(T), new object[] 22 { 23 GetFileTcpBinding(), 24 GetEndpoint(webAddress, serviceName) 25 }); 26 } 27 else //緩存傳輸 28 { 29 obj = Activator.CreateInstance(typeof(T), new object[] 30 { 31 GetTcpBinding(), 32 GetEndpoint(webAddress, serviceName) 33 }); 34 } 35 t = (T)(obj); 36 return t; 37 } 38 39 public static NetTcpBinding GetTcpBinding() 40 { 41 return new NetTcpBinding 42 { 43 MaxBufferPoolSize = 2147483646L, 44 MaxReceivedMessageSize = 2147483646L, 45 CloseTimeout = new TimeSpan(0, 0, 10), 46 OpenTimeout = new TimeSpan(0, 0, 10), 47 ReceiveTimeout = TimeSpan.MaxValue, 48 SendTimeout = new TimeSpan(0, 20, 0), 49 ReaderQuotas = 50 { 51 MaxDepth=64, 52 MaxStringContentLength=2147483646, 53 MaxArrayLength=2147483646, 54 MaxBytesPerRead=2147483646, 55 MaxNameTableCharCount=2147483646 56 }, 57 ReliableSession = 58 { 59 Enabled = true, 60 Ordered = true, 61 InactivityTimeout = new TimeSpan(0, 0, 10) 62 }, 63 Security = 64 { 65 Mode=SecurityMode.None, 66 Message = 67 { 68 ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows 69 }, 70 Transport = 71 { 72 ClientCredentialType = TcpClientCredentialType.Windows 73 } 74 }, 75 76 }; 77 } 78 79 80 /// <summary> 81 /// TCP大文件斷點續傳 82 /// </summary> 83 /// <returns></returns> 84 public static NetTcpBinding GetFileTcpBinding() 85 { 86 return new NetTcpBinding 87 { 88 MaxBufferPoolSize = 2147483646L, 89 MaxReceivedMessageSize = 2147483646L, 90 CloseTimeout = new TimeSpan(0, 0, 10), 91 OpenTimeout = new TimeSpan(0, 0, 10), 92 ReceiveTimeout = TimeSpan.MaxValue, 93 SendTimeout = new TimeSpan(0, 20, 0), 94 TransferMode=TransferMode.Streamed, 95 ReaderQuotas = 96 { 97 MaxDepth=64, 98 MaxStringContentLength=2147483646, 99 MaxArrayLength=2147483646, 100 MaxBytesPerRead=2147483646, 101 MaxNameTableCharCount=2147483646 102 }, 103 //ReliableSession = 104 //{ 105 // Enabled = true, 106 // Ordered = true, 107 // InactivityTimeout = new TimeSpan(1, 0, 0) 108 //}, 109 //Security = 110 //{ 111 // Mode=SecurityMode.None, 112 // Message = 113 // { 114 // ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows 115 // }, 116 // Transport = 117 // { 118 // ClientCredentialType = TcpClientCredentialType.Windows 119 // } 120 //}, 121 122 }; 123 } 124 125 public static WSHttpBinding GetHttpBinding() 126 { 127 return new WSHttpBinding 128 { 129 MaxBufferPoolSize = 2147483646L, 130 MaxReceivedMessageSize = 2147483646L, 131 CloseTimeout = new TimeSpan(0, 0, 10), 132 OpenTimeout = new TimeSpan(0, 0, 10), 133 ReceiveTimeout = new TimeSpan(0, 20, 0), 134 SendTimeout = new TimeSpan(0, 20, 0), 135 ReliableSession = 136 { 137 Enabled = true, 138 Ordered = true, 139 InactivityTimeout = new TimeSpan(0, 0, 10) 140 }, 141 UseDefaultWebProxy = false, 142 Security = 143 { 144 Mode = SecurityMode.None, 145 Message = 146 { 147 ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows 148 }, 149 Transport = 150 { 151 ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows 152 } 153 }, 154 }; 155 } 156 public static EndpointAddress GetEndpoint(string webAddress, string serviceName) 157 { 158 Uri uri = new Uri(webAddress + "/" + serviceName + ".svc"); 159 return new EndpointAddress(uri, new AddressHeader[0]); 160 } 161 162 public static EndpointAddress GetIMEndpoint(string webAddress, string serviceName) 163 { 164 Uri uri = new Uri(webAddress + "/" + serviceName + ".svc"); 165 return new EndpointAddress(uri, new AddressHeader[0]); 166 } 167 }View Code
這個裡面是NET.TCP 和WSHttp 的WCF配置,這個類主要用於客戶端的 需要傳入兩個參數“webAddress”,“serviceName”
webaddress我的做法是配置在客戶端的App.Config讀取。
serviceName我是根據每一個不同方法手工寫入的
我再貼一下用法實例
1 /// <summary> 2 /// 艾克仕網路雲OA企業名片 3 /// </summary> 4 public FirmCardPacket GetFirmCard(FirmCardPacket packet) 5 { 6 using (SettingServiceClient client = CreateTcpServiceClient<SettingServiceClient>(Caches.GolbalCache.WCFAddressCache, "MainClient/SettingService")) 7 { 8 client.Open(); 9 byte[] bt = null; 10 bt = Packet<FirmCardPacket>.PacketData(packet, strKey); 11 bt = client.GetFirmCard(bt); 12 packet = Packet<FirmCardPacket>.DePacketData(bt, strKey); 13 client.Close(); 14 } 15 return packet; 16 }
這個現在就展示一下用法,到我把WCF代理講完,在UI裡面我詳細講。
Base主要的是這些了,下麵講Global
先貼圖
Global項目就是它的字面意思,全局的信息或者配置就放在這裡。這個不用多講了,大家如果使用我這套架構的話,如何劃分全局還得靠自己,每個項目一般都不一樣的。
下麵是Model
Model我的文件夾分類規則是一個客戶端項目對應一個Model文件夾,多個客戶端公用的在Common文件夾,Base文件夾是基類舉一個例子說明基類的用法
WPF需要實時刷新界面數據的話,我的實體如IMinfo就會繼承Notify。IMpacket是具體的數據包需要繼承PacketModel。
PacketModel裡面是一些公共屬性,LoginId,FirmId,ResultCode,ResultMsg 這些信息。
我貼一下Notify的代碼
1 public abstract class Notify : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 5 protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) 6 { 7 if (object.Equals(storage, value)) return false; 8 9 storage = value; 10 this.OnPropertyChanged(propertyName); 11 12 return true; 13 } 14 15 protected void OnPropertyChanged(string propertyName) 16 { 17 var eventHandler = this.PropertyChanged; 18 if (eventHandler != null) 19 { 20 eventHandler(this, new PropertyChangedEventArgs(propertyName)); 21 } 22 } 23 }
這個代碼不解釋了,做WPF的都知道。
ACS.OA.WCFContract
WCF契約,我為何要寫在這裡呢?是因為我是使用SvcUtil生成的WCF代理類,這個代理類和WCF服務庫都公用這個契約,代理類和服務庫的代碼就會很簡潔了,而且可以保證代理類和服務庫的方法一致。
契約不用貼圖,WCF有明確規定的,等到即時通訊需要雙工的地方我會貼特定的契約介面。
到此,ACS.OA.Common解決方案文件夾講完,下麵講ACS.OA.WCFServer,不要走開,精彩還在後面
DDD WCF 服務層 ACS.OA.WCFServer
這個文件夾裡面我建了ACS.OA.Application、Domain、Repositories、WCFService、WCFServiceLib 五個項目。
這部分我將DDD和WCF整合統一放在WCFServer解決方案文件夾下。
我講一下數據處理過程:UI層通過WCF服務通信到WCFService由WCFServiceLib-->Application-->Domain-->Repositories。
WCFService 項目裡面只有SVC和Web.Config
契約如前面寫的我已經單獨新建項目放在ACS.OA.Common文件夾中,這裡引用就可以了。svc.cs文件我也刪掉放在WCFServiceLib中,這裡也是引用。
我貼一下Web.config配置給大家做一個參考
1 <system.serviceModel> 2 <bindings> 3 <netTcpBinding> 4 <binding name="OATcpBinding" closeTimeout="00:00:10" openTimeout="00:00:10" 5 receiveTimeout="00:30:00" sendTimeout="00:30:00" transactionFlow="true" 6 transferMode="Buffered" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646" 7 portSharingEnabled="true"> 8 <readerQuotas maxDepth="64" maxStringContentLength="2147483646" 9 maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" /> 10 <reliableSession ordered="true" inactivityTimeout="00:00:10" 11 enabled="true" /> 12 <security mode="None" /> 13 </binding> 14 </netTcpBinding> 15 16 <wsHttpBinding> 17 <binding name="OAHttpBinding" closeTimeout="00:05:00" openTimeout="00:05:00" 18 receiveTimeout="00:05:00" sendTimeout="00:05:00" transactionFlow="true" 19 maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646" 20 messageEncoding="Text"> 21 <readerQuotas maxDepth="64" maxStringContentLength="2147483646" 22 maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" /> 23 <reliableSession ordered="true" inactivityTimeout="01:00:00" 24 enabled="true" /> 25 <security mode="None" /> 26 </binding> 27 </wsHttpBinding> 28 </bindings> 29 <services> 30 31 <!--即時通訊Begin--> 32 <service behaviorConfiguration="OATcpBehavior" name="ACS.OA.WCFServiceLib.MainClient.IMService"> 33 <endpoint binding="netTcpBinding" bindingConfiguration="OATcpBinding" name="IMService" contract="ACS.OA.WCFContract.MainClient.IIMService"> 34 <identity> 35 <dns value="OAMainClient"/> 36 </identity> 37 </endpoint> 38 <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> 39 </service> 40 <!--即時通訊End--> 41 42 <!--文件斷點續傳Begin--> 43 <service behaviorConfiguration="OATcpBehavior" name="ACS.OA.WCFServiceLib.Common.ACSFileService"> 44 <endpoint binding="netTcpBinding" bindingConfiguration="OATcpBinding" name="ACSFileService" contract="ACS.OA.WCFContract.Common.IACSFileService"> 45 <identity> 46 <dns value="OAMainClient"/> 47 </identity> 48 </endpoint> 49 <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> 50 </service> 51 <!--文件斷點續傳End--> 52 53 </services> 54 <behaviors> 55 <serviceBehaviors> 56 <behavior> 57 <!-- 為避免泄漏元數據信息,請在部署前將以下值設置為 false --> 58 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> 59 <!-- 要接收故障異常詳細信息以進行調試,請將以下值設置為 true。在部署前設置為 false 以避免泄漏異常信息 --> 60 <serviceDebug includeExceptionDetailInFaults="false"/> 61 </behavior> 62 <behavior name="OATcpBehavior"> 63 <serviceMetadata httpGetEnabled="false"/> 64 <serviceDebug includeExceptionDetailInFaults="true"/> 65 <dataContractSerializer maxItemsInObjectGraph="2147483646"/> 66 <serviceTimeouts transactionTimeout="00:05:00"/> 67 <!--會話最大數量--> 68 <serviceThrottling maxConcurrentSessions="10000" maxConcurrentCalls="10000" maxConcurrentInstances="10000"/> 69 </behavior> 70 71 <behavior name="OAHttpBehavior"> 72 <serviceMetadata httpGetEnabled="true"/> 73 <serviceDebug includeExceptionDetailInFaults="true"/> 74 <dataContractSerializer maxItemsInObjectGraph="2147483646"/> 75 <serviceTimeouts transactionTimeout="00:05:00"/> 76 <!--會話最大數量--> 77 <serviceThrottling maxConcurrentSessions="10000" maxConcurrentCalls="10000" maxConcurrentInstances="10000"/> 78 </behavior> 79 </serviceBehaviors> 80 <endpointBehaviors> 81 <behavior name="DuplexendpointBehaviors"> 82 <dataContractSerializer maxItemsInObjectGraph="2147483646"/> 83 </behavior> 84 </endpointBehaviors> 85 </behaviors> 86 <protocolMapping> 87 <add binding="basicHttpsBinding" scheme="https"/> 88 </protocolMapping> 89 <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/> 90 </system.serviceModel>Web.config View Code
ACS.OA.WCFServiceLib
這裡我貼一下WCFServiceLibBase和其中一個服務的代碼
public class WCFServiceLibBase { public string HandleException(Exception ex, bool isThrowOut = false) { var myExceptionManager = ExceptionManager.GetInstance(); string returnValue = myExceptionManager.HandleException(ex, th