MEF 插件式開發 - 小試牛刀

来源:https://www.cnblogs.com/hippieZhou/archive/2018/08/01/9398354.html
-Advertisement-
Play Games

[TOC] MEF 簡介 Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可 ...


目錄


MEF 簡介

Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可以跨程式重覆使用。

在進行傳統的 C/S 端開發,如果項目不是特別複雜,常規的開發模式還是可以應對的。但是一旦場景複雜度提升,一個小小業務功能的修改就需要更新整個客戶端,這個對於開發者來說是不能忍受的。因此微軟為我們引入了 MEF 的開發模式。允許我們將眾多的業務模塊拆分開來設計成獨立的 DLL,然後由客戶端來進行統一載入,這樣就能解決上述我們所說的痛點。

實踐出真知

創建一個高擴張的 MEF 框架涉及的技術點較多。為了方便初學者能較快理解,上手實踐,我這裡主要通過 3 個方面來進行相關敘述。

面向介面編程

如果你還不能理解什麼是面向介面編程的話,那你應該還不能區分抽象類和介面之間的區別。其實在剛開始的時候我也不是很能理解,直到我看到了一句話:抽象類規定了你是什麼,介面規定了你能幹什麼,只要你能理解這句話,那麼你應該就明白什麼是面向介面編程,這種編程方式的好處是統一化了業務的暴露方式,方便外部使用。下麵我們看一個簡單的例子。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMessage email = new EmailService();
        email.Send();

        IMessage sms = new SMSService();
        sms.Send();

        Console.ReadKey();
    }
}

上述代碼中,我們創建了一個 IPlugin 的介面,介面定義了一個 ShowPluginName() 方法,然後我們再定義了兩個獨立的類來分別繼承該介面並實現相應的介面函數。在主函數中,我們只需要定義一個介面類型的對象,然後接收一個具體的類型實例,函數就會輸出對應的正確信息。這樣編程的好處就不言而喻了。代碼很簡單,這裡就不過多描述。輸出結果如下圖所示


控制反轉(IOC)

所謂控制反轉,就是將對象初始化的控制權交出去。要實現控制反轉,我們需要有面向介面編程的介面,同樣的,這裡也是展示一個代碼段來敘述。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

public static class Factory
{
    public static EmailService GetEmailService() => new EmailService();

    public static SMSService GetSMSService() => new SMSService();
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("DependencyService:");
        DependencyService();

        Console.WriteLine();

        Console.WriteLine("InversionDependencyService:");
        InversionDependencyService();

        Console.ReadKey();
    }

    static void DependencyService()
    {
        EmailService fooEmailService = new EmailService();
        fooEmailService.Send();
    }
    static void InversionDependencyService()
    {
        IMessage fooMessage = Factory.GetEmailService();
        fooMessage.Send();
        fooMessage = Factory.GetSMSService();
        fooMessage.Send();
    }
}

在這個例子中,我們通過工廠模式創建具體的服務,然後供主程式來調用,代碼依然很簡單,分別用傳統創建服務的方式和 控制反轉的方式來進行對比。程式輸出如下


構建入門級 MEF

有了上面兩個知識點做鋪墊,我們可以開始創建一個入門級的 MEF 示常式序。想要在程式中使用 MEF 的話需要引入如下程式集

  • System.ComponentModel.Composition

這裡還是以控制台程式來展示。項目結構如下圖所示


  • MefSample.Core:核心介面定義在該項目中
  • MefSample.EmailService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample.SMSService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample:主程式,需要引用 MefSample.Core 和 System.ComponentModel.Composition

註意:上述所有項目程式的輸出目錄需要保持一致

MefSample.Core 代碼段

public interface IMessage
{
    void Send();
}

MefSample.EmailService 代碼段

[Export(typeof(IMessage))]
public class EmailService: IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

MefSample.SMSService 代碼段

[Export(typeof(IMessage))]
public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

MefSample 代碼段

class Program
{
    static void Main(string[] args)
    {
        var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
        var catalog = new DirectoryCatalog(dir.FullName, "*.dll");
        using (CompositionContainer container = new CompositionContainer(catalog))
        {
            IEnumerable<IMessage> messages = container.GetExportedValues<IMessage>();
            if (messages != null)
            {
                foreach (var message in messages)
                {
                    message.Send();
                }
            }
        }
        Console.ReadKey();
    }
}

仔細觀察的話,其實上述代碼還是挺簡單的, 我這裡使用了 DirectoryCatalog 的方式來尋找目標插件,感興趣的朋友可以試試其他方式:AggregateCatalogAssemblyCatalogDirectoryCatalog。當然,你也可以自定義。程式輸出結果如下圖所示


好了,程式寫到這裡相信你對 MEF 也多少有些瞭解。我沒有過多的講解抽象理論,而是更多地通過代碼來描述我所想要說的。在下篇文章中,我將會簡單講述一下 MEF 在 WPF 中的入門使用,方便初學者更上一層樓。加油,共勉!

相關參考


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 概述 OLE,Object Linking and Embedding,即對象連接與嵌入。我們在設計程式時,OLE可以用來創建複合文檔,把文字、聲音、圖像、表格、應用程式等類型的信息組合在一起,在Word中,我們可以通過OLE來實現以上要素信息的組合。下麵的示例中將介紹如何通過C# 來操作Word中 ...
  • 簡介 繼承(封裝、多態)是面向對象編程三大特性之一,繼承的思想就是擯棄代碼的冗餘,實現更好的重用性。 繼承從字面上理解,無外乎讓人想到某人繼承某人的某些東西,一個給一個拿。這個語義在生活中,就像 家族繼承財產,爺爺將財產繼承給兒女,兒女在將財產繼承給子孫,有些東西可以繼承有些的東西只繼承給 某人。映 ...
  • 1.今天在部署IIS7應用程式的時候出現了這個錯誤,本以為是發佈的錯誤,其實不然,是IIS中所依賴的項沒有配置正確 2.選擇創建站點中對應的應用池 高級設置 啟用32位應用程式,然後把值改為true。 3.打開cmd命令進行安裝 如果映射存在,請檢查應用程式是否分配給了.NET Framework4 ...
  • 摘要:接下來的幾篇博客將要講到如何使用ado.net實現簡單的資料庫操作,包括增刪改等內容。首先會介紹基礎的資料庫操作,然後以一個實例來進行講解,這個實例會把一個數據表讀取到winform上,然後在winform上有一些按鈕和文本框,通過這些實現對資料庫里的內容的增刪改的操作。我個人比較菜,因此記錄... ...
  • 效果如下: 鄙人雖然開發WPF有些時間,但之前一直是一些簡單Template和Style改改之類的工作,並沒有深入研究過。此次為了完成工作,首先也是網上搜了半天,沒有找到合適的代碼直接拷貝(搜索能力待提高),乾脆就直接靜下心來琢磨琢磨。 一開始在界面上就放了Slider,撓撓頭,怎麼修改Templa ...
  • 為什麼文章要添加內鏈? 1.有利於讀者 我喜歡內鏈文章的最初動機是讓讀者在我的博客獲得更好的閱讀體驗,並獲得更多的價值。如果我的讀者訪問了我的一篇文章,發現不僅僅回答他需要的答案,還提供了更多相關內容的信息,讓他們能在更多的相關主題去擴展閱讀,他們遲早會喜歡並滿意我的博客。讓讀者滿意就是我們的目標, ...
  • 工作中長期需要用到通過HTTP調用API以及文件上傳下載,積累了不少經驗,現在將各種不同方式進行一個彙總。 首先是HttpWebRequest: 然後是HttpWebResponse: 上面兩個方法需要配合使用,皆為同步方式。當然也可以將上面兩個方法合併到一個方法中,可以參見接下來這個方法。 另外是 ...
  • 使用EF flument API 修改映射資料庫欄位的自增長 modelBuilder.Entity<Invoice>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 報錯Method n ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...