四、面向雲的.net core開發框架基礎設施層-應用程式集和類的查找

来源:http://www.cnblogs.com/BenDan2002/archive/2016/10/26/5996724.html
-Advertisement-
Play Games

在編寫開發框架的時候,經常會遇到要找出應用所用到的所有程式集和類,然後進行下一步的處理。 例如,我們有一個通用控制項類BaseControl,各種富文本編輯器控制項、表格控制項、分頁控制項等都繼承於通用控制項類BaseControl。甚至CMS這個項目的評論等控制項也會繼承該通用控制項類BaseControl。我 ...


在編寫開發框架的時候,經常會遇到要找出應用所用到的所有程式集和類,然後進行下一步的處理。

例如,我們有一個通用控制項類BaseControl,各種富文本編輯器控制項、表格控制項、分頁控制項等都繼承於通用控制項類BaseControl。甚至CMS這個項目的評論等控制項也會繼承該通用控制項類BaseControl。我們有一個需求,就是要做一個下拉列表,列出所有的控制項。因為控制項會分散在不同的程式集中,這樣我們必然會搜索當前應用中的所有程式集,從中找出所有繼承於BaseControl的控制項子類。這就是控制項的列表。(如果我懶病不發作,能夠寫的夠久的話,自定義表單、自定義查詢等技術點可以看到這個需求。)

下麵的方法是找到所有的應用程式集:

 1         private static IEnumerable<Assembly> GetAssemblies()
 2         {
 3             List<Assembly> assemblies = new List<Assembly>();
 4 
 5             //以下2行,總是認為所有的個人程式集都依賴於core
 6             Type type = typeof(ReflectionHelper);
 7 
 8             var libs = DependencyContext.Default.CompileLibraries;
 9             foreach (CompilationLibrary lib in libs)
10             {
11                 //if (lib.Name.StartsWith("Microsoft") || lib.Name.StartsWith("System") || lib.Name.Contains(".System.") || lib.Name.StartsWith("NuGet") || lib.Name.StartsWith("AutoMapper")) continue;
12                 if (lib.Serviceable) continue;
13                 if (lib.Type == "package") continue;
14 
15                 var assembly = Assembly.Load(new AssemblyName(lib.Name));
16                 assemblies.Add(assembly);
17 
18                 //以下,總是認為所有的個人程式集都依賴於core
19 
20                 ////過濾掉“動態生成的”
21                 //if (assembly.IsDynamic) continue;
22 
23                 //if (assembly.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", ""))
24                 //{
25                 //    assemblies.Add(assembly);
26                 //    continue;
27                 //}
28 
29                 //if (assembly.GetReferencedAssemblies().Any(ass => ass.FullName == type.AssemblyQualifiedName.Replace(type.FullName + ", ", "")))
30                 //{
31                 //    assemblies.Add(assembly);
32                 //}
33             }
34 
35             return assemblies;
36         }

此處有個假設,第6行Type type = typeof(ReflectionHelper)。其中ReflectionHelper是核心應用程式集中的一個靜態類,而核心應用程式集假設會被所有的應用程式集所引用。如果該假設不成立,需要將19-22行的註釋去掉,針對每個找到的程式集獲取所有引用的程式集。

if (lib.Serviceable) continue;和if (lib.Type == "package") continue; 這兩行的意思是排除所有的系統程式集、Nuget下載包,減少搜索範圍,提高效率。(這2行暫未最終確認。)

找到所有應用程式集後,下一步該獲取所有繼承於BaseControl的控制項子類。因為控制項子類繼承於BaseControl,因此子類所在的應用程式集必然引用BaseControl的應用程式集。通用寫法如下:

 1         #region 類型搜索
 2         /// <summary>
 3         /// 獲取子類型
 4         /// </summary>
 5         /// <param name="type">父類型</param>
 6         /// <returns></returns>
 7         public static IEnumerable<Type> GetSubTypes(Type type)
 8         {
 9             var assemblies = _Assemblies.Where(a =>
10             {
11                 Assembly assembly = type.GetTypeInfo().Assembly;
12                 //基類所在程式集或依賴於基類的其他程式集
13                 return a.FullName == assembly.FullName || a.GetReferencedAssemblies().Any(ra => ra.FullName == assembly.FullName);
14             });
15 
16             TypeInfo typeInfo = type.GetTypeInfo();
17 
18             return assemblies.SelectMany(a =>
19             {
20                 return a.GetTypes().Where(t =>
21                 {
22                     if (type == t)
23                     {
24                         return false;
25                     }
26 
27                     TypeInfo tInfo = t.GetTypeInfo();
28 
29                     if (tInfo.IsAbstract || !tInfo.IsClass || !tInfo.IsPublic)
30                     {
31                         return false;
32                     }
33 
34                     if (typeInfo.IsGenericTypeDefinition)
35                     {
36                         return type.IsAssignableFromGenericType(t);
37                     }
38 
39                     return type.IsAssignableFrom(t);
40                 });
41             });
42         }
43 
44         /// <summary>
45         /// 獲取子類型
46         /// </summary>
47         /// <typeparam name="T">父類型</typeparam>
48         /// <returns></returns>
49         public static IEnumerable<Type> GetSubTypes<T>()
50         {
51             return GetSubTypes(typeof(T));
52         }
53         #endregion

其中_Assemblies是從GetAssemblies()方法返回的結果。

這樣就能夠獲取當前的子類列表IEnumerable<Type>,可是如果用下拉列表展示,總不能顯示類似namespace.classname, assemblyname的樣子吧,這樣會被客戶罵的。應該下拉出來的是中文名,例如富文本編輯器、文件上傳、分頁、自動完成等。

如果我們在BaseControl中增加一個抽象的Name屬性,各個子類實現時override這個屬性,標識該控制項的中文名,倒是可以實現,不過在獲取Name屬性時,必須要實例化各個子類,天知道子類的構造函數有哪些參數。因此我們應該採取其他方式。建一個TypeNameAttribute。具體實現如下:

  1     /// <summary>
  2     /// 子類中,甚至TypeName,包括中英文及屬性,以便反射使用
  3     /// </summary>
  4     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
  5     public class TypeNameAttribute : Attribute
  6     {
  7         private string _Code, _Name, _Description;
  8         /// <summary>
  9         /// 英文
 10         /// </summary>
 11         public string Code
 12         {
 13             get
 14             {
 15                 return _Code;
 16             }
 17             set
 18             {
 19                 _Code = value;
 20             }
 21         }
 22         /// <summary>
 23         /// 中文
 24         /// </summary>
 25         public string Name
 26         {
 27             get
 28             {
 29                 return _Name;
 30             }
 31             set
 32             {
 33                 _Name = value;
 34             }
 35         }
 36         /// <summary>
 37         /// 描述
 38         /// </summary>
 39         public string Description
 40         {
 41             get
 42             {
 43                 return _Description;
 44             }
 45             set
 46             {
 47                 _Description = value;
 48             }
 49         }
 50         /// <summary>
 51         /// 構造函數
 52         /// </summary>
 53         /// <param name="code">英文</param>
 54         /// <param name="name">中文</param>
 55         /// <param name="description">描述</param>
 56         public TypeNameAttribute(string code, string name, string description)
 57         {
 58             this._Code = code;
 59             this._Name = name;
 60             this._Description = description;
 61         }
 62 
 63         /// <summary>
 64         /// 構造函數
 65         /// </summary>
 66         /// <param name="code">英文</param>
 67         /// <param name="name">中文</param>
 68         public TypeNameAttribute(string code, string name) : this(code, name, string.Empty)
 69         {
 70         }
 71     }
 72 
 73     /// <summary>
 74     /// TypeName的工具類
 75     /// </summary>
 76     public static class TypeNameHelper
 77     {
 78         public static ConcurrentDictionary<Type, List<TypeNameHelperInfo>> list = new ConcurrentDictionary<Type, List<TypeNameHelperInfo>>();
 79 
 80         public static TypeNameHelperInfo GetTypeNameHelperInfo<T>(string code)
 81         {
 82             List<TypeNameHelperInfo> list = GetTypeNameHelperList<T>();
 83 
 84             return list.SingleOrDefault(info => info.Code == code);
 85         }
 86 
 87         /// <summary>
 88         /// 根據基類,獲取所有子類的TypeName
 89         /// </summary>
 90         /// <typeparam name="T">基類型</typeparam>
 91         /// <returns>子類的TypeName信息</returns>
 92         public static List<TypeNameHelperInfo> GetTypeNameHelperList<T>()
 93         {
 94             if (list.ContainsKey(typeof(T)))
 95             {
 96                 return list[typeof(T)];
 97             }
 98 
 99             List<TypeNameHelperInfo> result = new List<TypeNameHelperInfo>();
100 
101             IEnumerable<Type> typeList = ReflectionHelper.GetSubTypes<T>();
102 
103             foreach (Type type in typeList)
104             {
105                 try
106                 {
107                     TypeNameAttribute attribute = ReflectionHelper.GetCustomAttribute<TypeNameAttribute>(type);
108                     result.Add(new TypeNameHelperInfo()
109                     {
110                         Code = attribute.Code,
111                         Name = attribute.Name,
112                         Description = attribute.Description,
113                         Type = type
114                     });
115                 }
116                 catch
117                 {
118                 }
119             }
120 
121             list[typeof(T)] = result;
122 
123             return result;
124         }
125     }
126 
127     /// <summary>
128     /// TypeName的信息類
129     /// </summary>
130     public class TypeNameHelperInfo
131     {
132         /// <summary>
133         /// 英文
134         /// </summary>
135         public string Code { get; set; }
136         /// <summary>
137         /// 中文
138         /// </summary>
139         public string Name { get; set; }
140         /// <summary>
141         /// 描述
142         /// </summary>
143         public string Description { get; set; }
144         /// <summary>
145         /// 類型
146         /// </summary>
147         public Type Type { get; set; }
148     }

最終就可以通過TypeNameHelper.GetTypeNameHelperList<BaseControl>()就可以獲取所有的控制項子類,子類列表存放在List<TypeNameHelperInfo>


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

-Advertisement-
Play Games
更多相關文章
  • 通常在 Shell 中執行命令的時候,我們會在輸入命令的下方看到執行結果,操作系統預設將命令的執行結果輸出到顯示器上。當然,我們也可以手動的指定輸出路徑,或者輸入路徑,這就是 I/O 重定向。 1.標準輸出重定向 使用 cat 命令,命令的執行結果將會列印在屏幕中。 我們使用 > 來進行輸出重定向, ...
  • 1.值類型: 1 static void Main(string[] args) 2 { 3 int a = 5; 4 int b = 3; 5 NumVal(a, b); 6 Console.WriteLine("a={0},b={1}", a, b); //輸出結果為:a=5,b=3 7 8 C ...
  • 由於項目需要在首頁搞一個訂單數量的走勢圖,經過多方查找,體驗,感覺ECharts不錯,封裝的很細,我們只需要看自己需要那種類型的圖表,搞定好自己的json數據就OK。至於說如何體現出來,官網的教程很詳細。大家可以去看下。大概瞭解下用法就OK。 百度ECharts 3:http://echarts.b ...
  • 第一篇 C#中的委托和事件 第二篇 C#中的委托和事件(續) 首先,張子陽先生的這是兩篇關於委托和事件間關係的文章,是目前為止我讀過的介紹委托和事件以及非同步調用最簡明清晰文章,作者通過非常有節奏的“標題”->“問題”->“思路”->“實現”->“講解”的結構,分步驟一步一步地將委托和事件的實現、應用 ...
  • 上一章中筆者講到關於Linq和EF的用法。並以hibernate來進行講解。那麼本章筆者來講一下C#的Asp.Net。即是在B/S模式下開發。現在企業大部分的業務都是面向B/S模式的。所以對於Asp.Net的瞭解變得必不可少的知識點。筆者在從事JAVA開發的時候,很少看到有關於Awt和Swing開發 ...
  • 目錄索引 【無私分享:ASP.NET CORE 項目實戰】目錄索引 簡介 很長時間沒有來更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其實已經完成了一個框架了,並且正在準備在生產環境中試用,但是很多東西也是出於自己理解的膚淺和技術的不斷更新,經常變動,所以,如果自己還沒有完全搞好,就 ...
  • 不要急,源代碼分享在最底部,先問大家一個問題,你在寫開放的API介面時是如何保證數據的安全性的?先來看看有哪些安全性問題在開放的api介面中,我們通過http Post或者Get方式請求伺服器的時候,會面臨著許多的安全性問題,例如: 1. 請求來源(身份)是否合法? 2. 請求參數被篡改? 3. 請... ...
  • 一、概念 Moq是利用諸如Linq表達式樹和Lambda表達式等·NET 3.5的特性,為·NET設計和開發的Mocking庫。Mock字面意思即模擬,模擬對象的行為已達到欺騙目標(待測試對象)的效果. Moq模擬類類型時,不可模擬密封類,不可模擬靜態方法(適配器可解決),被模擬的方法及屬性必須被v ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...