DDD領域驅動設計初探(四):WCF搭建

前言:前面三篇分享了下DDD裏面的兩個主要特性:聚合和倉儲。領域層的搭建基本完成,固然還涉及到領域事件和領域服務的部分,後面再項目搭建的過程當中慢慢引入,博主的思路是先將整個架構走通,而後一步一步來添加相關元素,使架構慢慢變得豐滿。這篇打算分享下應用層的搭建。根據DDD的設計原則,應用層不包含任何領域邏輯,它主要的做用是協調任務,或者叫調度任務,維護應用程序狀態。根據博主的理解,應用層是用來隔離領域層的,假設沒有應用層,那麼咱們的界面層能夠直接調用領域層的邏輯,也就是說能夠直接訪問領域的model,這樣的壞處顯而易見:一是領域model不是純粹的數據model,它含有領域的行爲,直接將其傳到前臺會形成調用的混亂;二是倉儲是和數據持久化打交道了,界面直接調用倉儲,也就是界面直接和數據打交道,也不符合通常分層的原則。因此咱們引入應用層,本文應用層是一個以控制檯項目爲宿主的WCF服務。咱們來看代碼設計。html

DDD領域驅動設計初探系列文章:編程

1、WCF簡介

WCF(Windows Communication Foundation)是由微軟發展的一組數據通訊的應用程序開發接口,能夠翻譯爲Windows通信接口,它是.NET框架的一部分。由 .NET Framework 3.0 開始引入。WCF的最終目標是經過進程或不一樣的系統、經過本地網絡或是經過Internet收發客戶和服務之間的消息。關於WCF的理論知識,須要咱們瞭解的是經典的ABC。瀏覽器

  • Address: 每個WCF的Service都有一個惟一的地址。這個地址給出了Service的地址和傳輸協議(Transport Protocol)。
  • Binding:綁定製定了服務經過什麼形式訪問。只要類比傳輸協議, encoding (text, binary, etc) 以及 WS-* 協議,像transactional支持以及可信任的消息隊列。
  • Contract:Contract描述了Service能提供的各類服務。Contract有四種,包括Service Contract, Data Contract, Fault Contract和Message Contract。

關於WCF的理論在此就再也不展開,下面結合咱們的項目代碼咱們從零開始一步一步來搭建一個本身的WCF服務吧。網絡

2、WCF代碼示例

一、代碼結構圖 

項目按照模塊爲單位劃分服務,好比權限模塊,咱們就有一個權限的接口契約IPowerManageWCFService。IService文件夾裏面放了3個接口,分別對應系統3個模塊的接口契約,Service文件夾裏面分別對應了3個接口的實現。ServiceAttribute.cs裏面定義了兩個特性,表示接口是WCF的服務。咱們來看看具體的代碼。架構

二、代碼示例

2.1 ServiceAttribute.cs文件定義契約接口和實現的特性類:

複製代碼
namespace ESTM.WCF.Service
{
    //標記此特性的爲WCF服務接口
    public class ServiceInterfaceAttribute : Attribute
    {
    }

    //標記此特性的爲WCF服務接口實現類
    public class ServiceClassAttribute : Attribute
    {
    }
}
複製代碼

2.2 接口契約代碼:

複製代碼
    /// <summary>
    /// 工廠佈局模塊接口契約
    /// </summary>
    [ServiceInterface]
    [ServiceContract]
    public interface IFactoryLayoutWCFService
    {
        [OperationContract]
        List<DTO_TM_PLANT> GetAllPlant();
    }
複製代碼
複製代碼
    /// <summary>
    /// 權限管理模塊接口契約
    /// </summary>
    [ServiceContract]
    [ServiceInterface]
    public interface IPowerManageWCFService
    {
        [OperationContract]
        IList<DTO_TB_DEPARTMENT> GetAllDepartment();
    }
複製代碼
複製代碼
    /// <summary>
    /// 產品管理模塊接口契約
    /// </summary>
    [ServiceContract]
    [ServiceInterface]
    public interface IProductWCFService
    {
        [OperationContract]
        IList<DTO_TP_PRODUCT> GetAllProduct();
    }
複製代碼

接口契約[ServiceContract]表示該接口遵照接口契約協定,[OperationContract]操做契約,這兩個特性都是WCF內置的東西。[ServiceInterface]的用處咱們待會說。app

2.3 接口實現代碼

複製代碼
    [ServiceClass]
    public class FactoryLayoutWCFService : IFactoryLayoutWCFService
    {
        public List<DTO_TM_PLANT> GetAllPlant()
        {
            throw new NotImplementedException();
        }
    }
複製代碼
複製代碼
    [ServiceClass]
    public class ProductWCFService : IProductWCFService
    {
        public IList<DTO_TP_PRODUCT> GetAllProduct()
        {
            throw new NotImplementedException();
        }
    }
複製代碼
複製代碼
    [ServiceClass]
    public class PowerManageWCFService : IPowerManageWCFService
    {
        public IList<DTO_TB_DEPARTMENT> GetAllDepartment()
        {
            throw new NotImplementedException();
        }
    }
複製代碼

[ServiceClass]特性和接口上面的[ServiceInterface]特性對應,用於標記契約和實現。框架

2.4 Bootstrapper.cs裏面定義了服務的啓動方法

複製代碼
   public class Bootstrapper
    {
        private string strBaseServiceUrl = ConfigurationManager.AppSettings["ServiceUrl"].ToString();

        //啓動全部的服務
        public void StartServices()
        {
            //1.讀取此程序集裏面的有服務契約的接口和實現類
            var assembly = Assembly.Load(typeof(Bootstrapper).Namespace);
            var lstType = assembly.GetTypes();
            var lstTypeInterface = new List<Type>();
            var lstTypeClass = new List<Type>();
            foreach (var oType in lstType)
            {
                //2.經過接口上的特性取到須要的接口和實現類
                var lstCustomAttr = oType.CustomAttributes;
                if (lstCustomAttr.Count() <= 0)
                {
                    continue;
                }
                var oInterfaceServiceAttribute = lstCustomAttr.FirstOrDefault(x => x.AttributeType.Equals(typeof(ServiceInterfaceAttribute)));
                if (oInterfaceServiceAttribute != null)
                {
                    lstTypeInterface.Add(oType);
                    continue;
                }
                var oClassServiceAttribute = lstCustomAttr.FirstOrDefault(x => x.AttributeType.Equals(typeof(ServiceClassAttribute)));
                if (oClassServiceAttribute != null)
                {
                    lstTypeClass.Add(oType);
                }                
            }

            //3.啓動全部服務
            foreach (var oInterfaceType in lstTypeInterface)
            {
         //經過反射找到接口的實現類,找到配對而後啓動服務 var lstTypeClassTmp = lstTypeClass.Where(x => x.GetInterface(oInterfaceType.Name) != null).ToList(); if (lstTypeClassTmp.Count <= 0) { continue; } if(lstTypeClassTmp[0].GetInterface(oInterfaceType.Name).Equals(oInterfaceType)) { var oTask = Task.Factory.StartNew(() => { OpenService(strBaseServiceUrl + "/" + oInterfaceType.Name, oInterfaceType, lstTypeClassTmp[0]); }); } } } //經過服務接口類型和實現類型啓動WCF服務 private void OpenService(string strServiceUrl, Type typeInterface, Type typeclass) { Uri httpAddress = new Uri(strServiceUrl); using (ServiceHost host = new ServiceHost(typeclass)) { ///////////////////////////////////////添加服務節點/////////////////////////////////////////////////// host.AddServiceEndpoint(typeInterface, new WSHttpBinding(), httpAddress); if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) { ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; behavior.HttpGetUrl = httpAddress; host.Description.Behaviors.Add(behavior); } host.Opened += delegate { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("服務啓動成功。服務地址:" + strServiceUrl); }; host.Open(); while (true) { Console.ReadLine(); } } } }
複製代碼

對應的App.Config裏面對應的服務的URL佈局

  <appSettings>
    <add key="ServiceUrl" value="http://127.0.0.1:1234/MyWCF.Server"/>
  </appSettings>

StartServices()方法經過反射和兩個特性[ServiceClass]與[ServiceInterface],依次啓動三個服務。post

而後再Program裏面調用測試

     static void Main(string[] args)
        {
            var oBootstrapper = new Bootstrapper();
            oBootstrapper.StartServices();
            Console.ReadLine();
        }

獲得結果:

咱們隨便選擇一個服務,經過瀏覽器訪問,測試服務是否啓動成功。

至此,WCF服務基本完成。

3、DTO說明

DTO,全稱Data Transfer Object,數據傳輸對象。DTO是一個貧血模型,也就是它裏面基本沒有方法,只有一堆屬性,而且全部屬性都具備public的getter和setter訪問器。爲何須要一個DTO對象?這個問題在C#進階系列——MEF實現設計上的「鬆耦合」(終結篇:面向接口編程)這篇裏面介紹過,它的做用其實很單一,就是用於數據傳遞和數據綁定。至於DTO如何設計,博主的項目裏,DTO是按照聚合來劃分的,也就是一個聚合對應一個DTO,DTO裏面屬性的定義能夠根據項目需求來定。咱們來看看代碼:

複製代碼
    /// <summary>
    /// 全部DTO model的父類,用做泛型約束
    /// </summary>
    [DataContract]
    public class DTO_BASEMODEL
    {
    }
複製代碼
複製代碼
/// <summary>
    /// TB_DEPARTMENT
    /// </summary>
    [DataContract]
    public class DTO_TB_DEPARTMENT : DTO_BASEMODEL
    {
        [DataMember]
        public string DEPARTMENT_ID { get; set; }

        [DataMember]
        public string DEPARTMENT_NAME { get; set; }

        [DataMember]
        public string PARENT_ID { get; set; }

        [DataMember]
        public string DEPARTMENT_LEVEL { get; set; }

        [DataMember]
        public string STATUS { get; set; }
    }
複製代碼

其餘DTO都和這個相似,就不一一列舉了。因爲DTO須要由WCF傳遞到Web前臺,因此要求這個對象能夠序列化,須要標記[DataContract]和[DataMember]兩個特性,DTO_BASEMODEL做爲全部DTO的父類, 用做泛型約束和定義DTO的一些公用特性。到此,WCF的搭建基本完成,下篇咱們來介紹下Automapper的使用。

相關文章
相關標籤/搜索