1. 程式人生 > >C#進階系列——MEF實現設計上的“鬆耦合”(二)

C#進階系列——MEF實現設計上的“鬆耦合”(二)

前言:前篇 C#進階系列——MEF實現設計上的“鬆耦合”(一) 介紹了下MEF的基礎用法,讓我們對MEF有了一個抽象的認識。當然MEF的用法可能不限於此,比如MEF的目錄服務、目錄篩選、重組部件等高階應用在這裡就不做過多講解,因為博主覺得這些用法只有在某些特定的環境下面才會用到,著實不太普遍,感覺沒有鑽下去的必要。如果你有興趣也可以去了解下。這篇打算將MEF和倉儲模式結合起來談談MEF在專案中的使用。

1、倉儲模式:也叫Repository模式。Repository是一個獨立的層,介於領域層與資料對映層(資料訪問層)之間。它的存在讓領域層感覺不到資料訪問層的存在,它提供一個類似集合的介面提供給領域層進行領域物件的訪問。Repository是倉庫管理員,領域層需要什麼東西只需告訴倉庫管理員,由倉庫管理員把東西拿給它,並不需要知道東西實際放在哪。Repository模式一般是用來封裝資料訪問層的,這也就是為什麼很多地方看到說的什麼“資料倉儲”,大概就是這個意思。Repository模式並不是本文的重點,這裡就不再展開,後面會單獨分享這塊。

關於倉儲模式有以下幾點需要注意:

(1)Repository模式是架構模式,在設計架構時,才有參考價值;

(2)Repository模式使用的意義:一是隔離業務邏輯層和底層資料訪問層,保證資料出入口的唯一性;二是Repository模式針對聚合根設計的,而並不是針對表和實體設計的,換句話說,使用Repository是為了實現內聚,前端只負責向Repository請求資料即可,而不用關心資料的具體來源;

(3)Repository模式實際用途:更換、升級ORM引擎,不影響業務邏輯;

上面這些東西寫得有點官方。博主的理解是,倉儲模式就是對資料訪問層(或者叫資料對映層)做了一層包裝,每一次前端需要查詢什麼資料或者提交什麼資料的時候,都是通過倉儲物件Repository去操作的,前端基本上感覺不到資料訪問層的存在。這樣說你有沒有好理解一點呢?沒有?好吧,我們來看Demo。

2、MEF在倉儲模式上面的應用:由於框架使用的是EF,所以這裡也用EF結合倉儲模式進行講解。為了省略Repository模式的複雜結構,我們僅僅通過倉儲的Save方法來說明。

IRepository<TEntity>介面以及實現程式碼:

  public interface IRepository<T>
     where T : BaseEntity
    {
        T Save(T entitiy);
    }
  [Export(typeof(IRepository<BaseEntity>))]
    
public abstract class Repository<T> : IRepository<T> where T : BaseEntity { //工作單元 [Import] protected IUnitOfWork context { set; get; } private IDbSet<T> _entities; //註冊MEF public Repository() { Register.regisgter().ComposeParts(this); } public virtual T Save(T entitiy) { if (entitiy == null) throw new ArgumentException("entitiy nul"); context.Save<T>(entitiy); return entitiy; } } public static class Register { public static CompositionContainer regisgter() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); return container; } }

BaseEntity是一個EF實體的公共基類,定義EF實體必須要遵循的約束。

IUnitOfWork工作單元介面以及實現

  public interface IUnitOfWork : IDisposable
    {
        int Commit();

        void Rollback();

        void Save<T>(T entity) where T : BaseEntity;
    }
     /// <summary>
        /// 單元操作實現
        /// </summary>
     [Export(typeof(IUnitOfWork))]
public abstract class UnitOfWorkContextBase : IUnitOfWork { [ImportMany] protected abstract IEnumerable<DbContext> Contexts { get; } protected abstract DbContext Cur_context { get; set; } public UnitOfWorkContextBase() {
          Register.regisgter().ComposeParts(this);
if (Contexts.Count() <= 0) { throw new Exception(); } Cur_context = Contexts.FirstOrDefault(); } /// <summary> /// 獲取 當前單元操作是否已被提交 /// </summary> public bool IsCommitted { get; private set; } /// <summary> /// 提交當前單元操作的結果 /// </summary> /// <returns></returns> public int Commit() { if (IsCommitted) { return 0; } try { int result = Cur_context.SaveChanges(); IsCommitted = true; return result; } catch (DbUpdateException e) { if (e.InnerException != null && e.InnerException.InnerException is SqlException) { SqlException sqlEx = e.InnerException.InnerException as SqlException; string msg = DataHelper.GetSqlExceptionMessage(sqlEx.Number); throw PublicHelper.ThrowDataAccessException("提交資料更新時發生異常:" + msg, sqlEx); } throw; } } /// <summary> /// 把當前單元操作回滾成未提交狀態 /// </summary> public void Rollback() { IsCommitted = false; } public void Dispose() { if (!IsCommitted) { Commit(); } Cur_context.Dispose(); } public void Save<T>(T entity) where T : T { Cur_context.SaveChanges(); } }

既然這裡使用了ImportMany,那麼肯定有一個地方需要Export。我們使用EF新建一個edmx檔案,在生成的上下文物件上面加上Export

  [Export(typeof(DbContext))]
    public partial class Entities : DbContext
    {
        public Entities()
            : base("name=Entities")
        {
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
    
        public DbSet<TB_USERS> TB_USERS { get; set; }
    }

這裡為什麼要使用ImportMany?前面說了,倉儲的好處之一在於對資料訪問層做封裝,使得前端不比關心資料的具體來源。當我們再建一個數據庫連線的edmx時,我們只需要修改倉儲裡面的Cur_context 這個物件的賦值即可,由於其他地方都是針對Cur_context這一個上下文物件做的操作,所以基本都不需要做很大的變化。繞了這麼大一圈,其實博主只是想說明Import和ImportMany和倉儲模式結合使用的好處,至於倉儲模式的適用性問題不是本文的重點。

相關推薦

C#系列——MEF實現設計的“耦合

前言:前篇 C#進階系列——MEF實現設計上的“鬆耦合”(一) 介紹了下MEF的基礎用法,讓我們對MEF有了一個抽象的認識。當然MEF的用法可能不限於此,比如MEF的目錄服務、目錄篩選、重組部件等高階應用在這裡就不做過多講解,因為博主覺得這些用法只有在某些特定的環境下面才會用到,著實不太普遍,感覺沒有鑽下去的

C#系列——MEF實現設計的“耦合

前言:最近去了趟外地出差,介紹推廣小組開發的框架類產品。推廣物件是本部門在專案上面的同事——1到2年工作經驗的初級程式設計師。在給他們介紹框架時發現很多框架設計層面的知識他們都沒有接觸過,甚至沒聽說過,這下囧了~~於是乎在想該如何跟他們解釋MEF、AOP、倉儲模式等方面的東東。本來 C#基礎系列 應該還有兩篇

C#系列——MEF實現設計的“耦合:建構函式注入

前言:今天十一長假的第一天,本因出去走走,奈何博主最大的樂趣是假期坐在電腦前看各處堵車,順便寫寫部落格,有點收穫也是好的。關於MEF的知識,之前已經分享過三篇,為什麼有今天這篇?是因為昨天分享領域服務的時候,用到MEF的注入有參建構函式的方法,博主好奇心重,打算稍微深挖一下,這篇來對此知識點做個總結。 還是

C#系列——MEF實現設計的“耦合終結篇:面向介面程式設計

序:忙碌多事的八月帶著些許的倦意早已步入尾聲,金秋九月承載著抗戰勝利70週年的喜慶撲面而來。沒來得及任何準備,似乎也不需要任何準備,因為生活不需要太多將來時。每天忙著上班、加班、白加班,忘了去憤,忘了去算計所謂的價值。天津爆炸事故時刻警示著我們生命的無常,逝者安息,活著的人生活還得繼續,珍惜生命,遠離傷害。武

【VMCloud雲平臺篇】應用數據層面優化

vmcloud在上一篇中我們講到準備SQL基礎環境改造,這一篇將繼續講述如何為應用提供高可用的底層數據層,以下是本次要進行實驗的拓撲(紅色為已完成搭建,藍色是本次文章涉及的區域):1、 上一篇我們搭建好了SQL底層,這一篇來講述如何創建一個AlwayOn可用組對外提供服務,設置兩個SQL節點的AlwayOn高

docker:自定義映象、網路架構

一、製作自定義映象(docker commit) 要求:基於centos映象使用commit建立新的映象檔案。 1、使用映象啟動容器 在該容器基礎上修改yum源 [[email protected] docker_images]# docker run

C# 基礎知識系列- 9 字串的更多用法

0. 前言 上一篇文章介紹了字串自身的一些方法,就是物件方法。在字串體系中,還有一些是string類提供的靜態方法。這兩部分構成了字串體系,當然還有一些三方庫為字串提供了擴充套件方法。 這裡簡單的介紹一下string類的靜態方法。 1. 玩轉建立字串 1.1 Create一個字串 通過呼叫string.Cre

C#系列——DDD領域驅動設計初探:倉儲Repository

前言:上篇介紹了DDD設計Demo裡面的聚合劃分以及實體和聚合根的設計,這章繼續來說說DDD裡面最具爭議的話題之一的倉儲Repository,為什麼Repository會有這麼大的爭議,博主認為主要原因無非以下兩點:一是Repository的真實意圖沒有理解清楚,導致設計的紊亂,隨著專案的橫向和縱向擴充套件,

【9】C++系列泛型設計以及STL標準模板庫

1、泛型程式設計基本概念 泛型程式設計:編寫不依賴與具體資料型別的程式,將演算法從特定的資料結構中抽象出來,成為通用的。C++的模板為泛型程式設計定義了關鍵的基礎。 兩個術語:概念,模型 概念:用來界定具備一定功能的資料型別,例如:將“可以比較大小的所有資料型別(有比較

C#系列——DDD領域驅動設計初探:領域服務

前言:之前一直在搭建專案架構的程式碼,有點偏離我們的主題(DDD)了,這篇我們繼續來聊聊DDD裡面另一個比較重要的知識點:領域服務。關於領域服務的使用,書中也介紹得比較晦澀,在此就根據博主自己的理解談談這個知識點的使用。 DDD領域驅動設計初探系列文章: 一、領域服務的引入 在《領域驅動設計:軟體核

C#系列——DDD領域驅動設計初探:WCF搭建

前言:前面三篇分享了下DDD裡面的兩個主要特性:聚合和倉儲。領域層的搭建基本完成,當然還涉及到領域事件和領域服務的部分,後面再專案搭建的過程中慢慢引入,博主的思路是先將整個架構走通,然後一步一步來新增相關元素,使架構慢慢變得豐滿。這篇打算分享下應用層的搭建。根據DDD的設計原則,應用層不包含任何領域邏輯,它主

C#系列——DDD領域驅動設計初探:AutoMapper使用

前言:前篇搭建了下WCF的程式碼,就提到了DTO的概念,對於為什麼要有這麼一個DTO的物件,上章可能對於這點不太詳盡,在此不厭其煩再來提提它的作用: 從安全上面考慮,領域Model都帶有領域業務,讓Client端引用Domain Model就意味著Client端可以繞過應用層直接完成業務邏輯的呼叫,這樣

C#系列——DDD領域驅動設計初探:倉儲Repository

前言:上篇介紹了下倉儲的程式碼架構示例以及簡單分析了倉儲了使用優勢。本章還是繼續來完善下倉儲的設計。上章說了,倉儲的最主要作用的分離領域層和具體的技術架構,使得領域層更加專注領域邏輯。那麼涉及到具體的實現的時候我們應該怎麼做呢,本章就來說說倉儲裡面具體細節方便的知識。 DDD領域驅動設計初探系列文章:

C#系列——DDD領域驅動設計初探:Web層的搭建

前言:好久沒更新部落格了,每天被該死的業務纏身,今天正好一個模組完成了,繼續來完善我們的程式碼。之前的六篇完成了領域層、應用層、以及基礎結構層的部分程式碼,這篇打算搭建下UI層的程式碼。 DDD領域驅動設計初探系列文章: 一、UI層介紹 在DDD裡面,UI層的設計也分為BS和CS,本篇還是以Web為

C#系列——DDD領域驅動設計初探:聚合

前言:又有差不多半個月沒寫點什麼了,感覺這樣很對不起自己似的。今天看到一篇博文裡面寫道:越是忙人越有時間寫部落格。呵呵,似乎有點道理,博主為了證明自己也是忙人,這不就來學習下DDD這麼一個聽上去高大上的東西。前面介紹了下MEF和AOP的相關知識,後面打算分享Automapper、倉儲模式、WCF等東西的,可是

C#系列——WebApi 異常處理解決方案

機制 輸出 ges 如果 但是 rom lba slist 解決 出處:http://www.cnblogs.com/landeanfen/p/5363846.html 閱讀目錄 一、使用異常篩選器捕獲所有異常 二、HttpResponseException自

C#系列——WebApi 接口測試工具:WebApiTestClient

spa type 區域 all 手動 shee 找到 網絡 打開文件 C#進階系列——WebApi 接口測試工具:WebApiTestClient 前言:這兩天在整WebApi的服務,由於調用方是Android客戶端,Android開發人員也不懂C#語法,API裏

C#系列——WebApi 路由機制剖析:你準備好了嗎?

事先 blank path can tex 全局配置 dex 找不到 save 前言:從MVC到WebApi,路由機制一直是伴隨著這些技術的一個重要組成部分。 它可以很簡單:如果你僅僅只需要會用一些簡單的路由,如/Home/Index,那麽你只需要配置一個默認路由就能簡

C#系列——WebApi 跨域問題解決方案:CORS

dea ati ice pro target default 異常 測試工具 復雜 前言:上篇總結了下WebApi的接口測試工具的使用,這篇接著來看看WebAPI的另一個常見問題:跨域問題。本篇主要從實例的角度分享下CORS解決跨域問題一些細節。 WebApi系列文章

[轉]C#系列——WebApi 接口返回值不困惑:返回值類型詳解

try 接口測試工具 des rep home creat port 調用 學習 本文轉自:http://www.cnblogs.com/landeanfen/p/5501487.html 閱讀目錄 一、void無返回值 二、IHttpActionResult