架構搭建----基於DDD領域驅動設計的WCF+EF+WPF分層框架(2)


寫在最前面:轉載請注明出處

目錄置頂:

架構搭建

架構是基於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, this.GetType().Assembly.GetName().Name, this.GetType().FullName, isThrowOut);

            return returnValue;
        }

        public byte[] ErrorLogRecode(Exception ex,string funcName=null)
        {
           HandleException(ex);
           LoginPacket backPacket = new LoginPacket();
           backPacket.ResultMsg = "操作失敗";

           LogHelper.WriteErrorLog(this.GetType().FullName, "ErrorLogRecode", ex);

           bool recordResult= LogRecordServiceImpl.Instance.Add(ex.Message, funcName);
           if (!recordResult)
           {
               backPacket.ResultMsg = "網絡異常,請稍后再試";
           }
           return Packet<LoginPacket>.PacketData(backPacket, SystemConfig.Packet_Key);
        }
    }
        /// <summary>
        /// 艾克仕網絡雲OA企業名片
        /// </summary>
        public byte[] GetFirmCard(byte[] bytData)
        {
            try
            {
                return SettingServiceImpl.Instance.GetFirmCard(bytData);
            }
            catch (Exception ex)
            {
                return ErrorLogRecode(ex);
            }
        }

這段代碼大家可以看到其實真正的數據處理還不是這里,這里僅僅進行了一個異常處理,對外的接口如有異常會返回一個通用的錯誤信息。

 SettingServiceImpl.Instance.GetFirmCard(bytData);從這行代碼就知道我們需要去Application看了。

 


ACS.OA.Application

 1     public class SettingServiceImpl
 2     {
 3         #region <<Singleton>>
 4         private static object obj_lock = new object();
 5         private static SettingServiceImpl _instance = default(SettingServiceImpl);
 6 
 7         public static SettingServiceImpl Instance
 8         {
 9             get
10             {
11                 if (_instance == null)
12                 {
13                     lock (obj_lock)
14                     {
15                         if (_instance == null)
16                         {
17                             _instance = Activator.CreateInstance<SettingServiceImpl>();
18                         }
19                     }
20                 }
21                 return _instance;
22             }
23         }
24 
25         #endregion
26 
27     private FirmCardDbContext firmCardDbContext;
28         private IFirmCardRepository firmCardRepository;
29         
30         /// <summary>
31         /// 艾克仕網絡雲OA企業名片列表
32         /// </summary>
33         public byte[] GetFirmCard(byte[] bytData)
34         {
35             FirmCardPacket backPacket = new FirmCardPacket();
36             //byte轉化實體
37             FirmCardPacket packet = Packet<FirmCardPacket>.DePacketData(bytData, SystemConfig.Packet_Key);
38             string connStr = CommonServiceImpl.Instance.GetServerSourceByFirmRegNo(packet.FirmRegNo);
39             if (string.IsNullOrEmpty(connStr))
40             {
41                 packet.ResultMsg = "獲取連接參數異常,請登陸后重試";
42                 return Packet<FirmCardPacket>.PacketData(backPacket, SystemConfig.Packet_Key);
43             }
44             firmCardDbContext = new FirmCardDbContext(connStr);
45 
46             using (IRepositoryContext recontext = new EFRepositoryContext(firmCardDbContext))
47             {
48                 firmCardRepository = new FirmCardRepository(recontext);
49 
50                 List<FirmCardEntity> ents = new List<FirmCardEntity>(firmCardRepository.GetAll());
51                 if (ents != null && ents.Count > 0)
52                 {
53                     backPacket.FirmCardList = new FirmCardEntityDTO().ConvertFirmCardToInfoByEntityList(ents);
54                 }  
55             }
56             backPacket.ResultCode = ResultCodeType.CODE_SUCCESS;
57             return Packet<FirmCardPacket>.PacketData(backPacket, SystemConfig.Packet_Key);
58         }
59  }
60 }

熟悉設計模式的都知道Instance 是單例模式,這里把Application設計成單例模式我的理由是這里是服務端,這里客戶端訪問的頻率會很高,這個類在加載之時就實例化存於內存之中,不用每次訪問都去實例化然后再垃圾回收再實例再回收會增加服務器壓力。所以用的單例模式。

private FirmCardDbContext firmCardDbContext;

private IFirmCardRepository firmCardRepository;

這兩個是先聲明數據上下文和倉儲庫。在每一次請求都去實例化,請求結束立即釋放。為了防止數據庫被獨占。里面具體的方法實現后續會做詳細介紹。

 


ACS.OA.Domain 和 ACS.OA.Repositories

 在這里我不想過多介紹Domain和Repositories,我就截圖看一下結構。在后面具體實例中從頭走到尾。

    

WPF UI層 ACS.OA.UIClient

 

我這個艾克仕網絡雲OA的UI層有5個項目 ACS.OA.WCFClient、ACS.ClientBase、ACS.Launcher、ACS.UpdateClient、ACS.OA.MainClient

ACS.Launcher、ACS.UpdateClient 這兩個是做檢測和更新的,這個不做介紹。

ACS.ClientBase

ClientBase項目我的目的是定義一些公共的類,每一個客戶端都公用的。在Base文件夾里面有ModelBase、NotifyBase、ViewModelBase,這三個基類,在MainClient中每一個Model類,Notify類和ViewModel類都會繼承相對應的基類。下面我把三個基類的代碼貼出來:

 public class ModelBase
    {
        #region <<WCF Related Methods>>

        public T CreateTcpServiceClient<T>(string webAddress, string serviceName, bool isStream = false)
        {
            return WCFHandler.CreateTcpServiceClient<T>(webAddress, serviceName, isStream);
        }

        /// <summary>
        /// IM即時通訊專用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="callbackInstance"></param>
        /// <param name="webAddress"></param>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        public T CreateTcpServiceClient<T>(InstanceContext callbackInstance, string webAddress, string serviceName)
        {
            return WCFHandler.CreateTcpServiceClient<T>(callbackInstance, webAddress, serviceName);
        }

        #endregion
    }
 1 public class NotifyBase : 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     }
NotifyBase View Code
  1     /// <summary>
  2     /// ViewModelBase
  3     /// </summary>
  4     /// <typeparam name="T">Model</typeparam>
  5     public abstract class ViewModelBase<T> : BindableBase
  6     {
  7         private static object obj_lock = new object();
  8         private T _Model = default(T);
  9 
 10         public T Model
 11         {
 12             get
 13             {
 14                 if (_Model == null)
 15                 {
 16                     lock (obj_lock)
 17                     {
 18                         if (_Model == null)
 19                         {
 20                             _Model = Activator.CreateInstance<T>();
 21                         }
 22                     }
 23                 }
 24                 return _Model;
 25 
 26             }
 27         }
 28                 
 29         #region 異常
 30         public string HandleException(Exception ex, bool isThrowOut=false)
 31         {
 32             string returnValue = "";
 33             try
 34             {
 35                 LogHelper.WriteErrorLog(this.GetType().FullName, "ErrorLogRecode", ex);
 36                 var myExceptionManager = ExceptionManager.GetInstance();
 37                 //if (GlobalVariables.HxIsSendExceptionMail)
 38                 //{
 39                 //    handlerTypeList.Add(HandlerType.Mail);
 40                 //}
 41                 returnValue = myExceptionManager.HandleException(ex, this.GetType().Assembly.GetName().Name, this.GetType().FullName, isThrowOut);
 42             }
 43             catch
 44             { }
 45             return returnValue;
 46         }
 47         #endregion
 48 
 49         #region 消息
 50         /// <summary>
 51         /// 自定義消息窗口
 52         /// </summary>
 53         /// <param name="strMsg">消息</param>
 54         /// <param name="isAutoClose">是否自動關閉</param>
 55         public void MsgBoxShow(Enum.MsgType msgtype, string strMsg,bool isAutoClose=true)
 56         {
 57             Application.Current.Dispatcher.Invoke(new Action(() =>
 58             {
 59                 MsgBoxShowWindow win = new MsgBoxShowWindow(msgtype, strMsg, isAutoClose);
 60                 win.Owner = Application.Current.MainWindow;
 61                 win.Show();
 62             }));
 63         }
 64 
 65         /// <summary>
 66         /// 自定義消息窗口
 67         /// </summary>
 68         /// <param name="ex">錯誤消息</param>
 69         /// <param name="isAutoClose">是否自動關閉</param>
 70         public void MsgBoxShow(Exception ex, bool isAutoClose=true)
 71         {
 72             Application.Current.Dispatcher.Invoke(new Action(() =>
 73             {
 74                 MsgBoxShowWindow win = new MsgBoxShowWindow(ex, isAutoClose);
 75                 win.Owner = Application.Current.MainWindow;
 76                 win.Show();
 77             }));
 78         }
 79 
 80         /// <summary>
 81         /// 自定義消息窗口
 82         /// </summary>
 83         /// <param name="strMsg">消息</param>
 84         /// <param name="isAutoClose">是否自動關閉</param>
 85         public void MsgBoxShowDialog(Enum.MsgType msgtype, string strMsg, bool isAutoClose = false)
 86         {
 87             Application.Current.Dispatcher.Invoke(new Action(() =>
 88             {
 89                 MsgBoxShowWindow win = new MsgBoxShowWindow(msgtype, strMsg, isAutoClose);
 90                 win.Owner = Application.Current.MainWindow;
 91                 win.ShowDialog();
 92             }));
 93         }
 94 
 95 
 96         /// <summary>
 97         /// 自定義消息窗口
 98         /// </summary>
 99         /// <param name="ex">錯誤消息</param>
100         /// <param name="isAutoClose">是否自動關閉</param>
101         public void MsgBoxShowDialog(Exception ex, bool isAutoClose = false)
102         {
103             Application.Current.Dispatcher.Invoke(new Action(() =>
104             {
105                 MsgBoxShowWindow win = new MsgBoxShowWindow(ex, isAutoClose);
106                 win.Owner = Application.Current.MainWindow;
107                 win.ShowDialog();
108             }));
109         }
110 
111         #endregion
112 
113 
114         #region 日志
115 
116         #endregion
117     }
ViewModelBase View Code

具體的使用方法在后續介紹UI層會做展示

ACS.OA.WCFClient 是用SvcUtil工具生成的代理類。在這里我想提一點建議

我建議大家在搭建稍微大型一點的項目的時候如果使用WCF盡量使用代理類,不要去右鍵添加服務引用 添加的服務引用不管是管理還是發布都挺麻煩的。

 

行了,架構搭建就講到這里,請關注后續博客。也請拍磚,輕點拍

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM