• 架构搭建----基于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尽量使用代理类,不要去右键添加服务引用 添加的服务引用不管是管理还是发布都挺麻烦的。

    行了,架构搭建就讲到这里,请关注后续博客。也请拍砖,轻点拍

  • 相关阅读:
    .NET开发人员如何开始使用ML.NET
    微软开源 Try .NET
    在kubernetes 集群内访问k8s API服务
    微软发布ML.NET 1.0
    现代“十二要素应用”与 Kubernetes
    .NET和Docker ,比翼双飞
    .NET Core 时代已经到了,你准备好了吗
    一份.NET 容器化的调查小结
    容器化时代我们应当选择Kubernetes
    机器学习 ML.NET 发布 1.0 RC
  • 原文地址:https://www.cnblogs.com/acssoft/p/5370388.html
Copyright © 2020-2023  润新知