NetDh框架適用於C/S、B/S的服務端框架,可用於項目開發和學習。目前包含如下四個模塊html
1.數據庫操做層封裝Dapper,支持多種數據庫類型、多庫實例,簡單強大;git
此部分具體說明可參考博客: http://www.javashuo.com/article/p-yiwcfheq-k.htmlgithub
2.提供簡單高效的日誌操做類使用,支持日誌寫入Db和txt、支持任何數據庫類型寫入(包括傳統sql數據庫和nosql數據庫等)、支持同步寫入日誌和後臺獨立線程異步處理日誌隊列;redis
此部分具體說明可參考博客: http://www.javashuo.com/article/p-njmgohqn-ek.htmlsql
3.提供簡單緩存設計和使用;數據庫
此部分具體說明可參考博客: 本文如下章節內容。緩存
4.業務邏輯層服務簡單設計,可方便支持二次開發模式。app
此部分具體說明可參考博客: 本文如下章節內容。框架
項目中應當都要考慮緩存的設計,無論是小項目的內存緩存仍是大項目中的Redis/Memcache等。緩存的介質比較有可能切換,好比因爲數據量的提升,會從內存緩存切換到memcache。這時候就要設計緩存接口,用接口操做緩存動做,以下圖的ICacheHandle接口。以前文章有講到數據庫操做是設計爲抽象基類DbHandleBase,抽象類注重代碼的重用,接口定義類的行爲,類能夠實現多個接口,但只能繼承一個抽象類。異步
緩存操做類比較簡單,上圖的內存緩存操做類RuntimeCacheHandle直接使用現成的System.Web.HttpRuntime.Cache實現,B/S、C/S均可以使用。上代碼(取緩存使用泛型操做,使用起來方便不少):
using System; using System.Collections.Generic; using System.Web; using System.Web.Caching; namespace NetDh.Cache { /* * 若是你的緩存介質會有切換的可能,則建議用接口操做, * 此內存緩存操做類RuntimeCacheHandle是使用現成的System.Web.HttpRuntime實現,B/S、C/S均可以使用。 */ /// <summary> /// 內存緩存操做類。 /// </summary> public class RuntimeCacheHandle : ICacheHandle { /// <summary> /// 取緩存。 /// </summary> /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam> /// <param name="key"></param> /// <returns>當緩存不存在時,引用類型返回null;而值類型返回的默認值,並不表明緩存存在。</returns> public T Get<T>(string key) { object value = HttpRuntime.Cache.Get(key); if (value != null) { return (T)value; } return default(T);//注意:值類型返回的默認值 ,並不表明緩存存在。 } /// <summary> /// 存入緩存。存入的是源value數據的備份,源數據修改不影響緩存。 /// (通常直接寫Set("key1",obj),而不用Set<object>("key1",obj),由於.net會自動根據obj判斷T的類型) /// </summary> /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="timeOut">緩存的過時時間(秒),-1表明不過時。</param> /// <returns></returns> public bool Set<T>(string key, T value, int timeOut = -1) { if (timeOut == -1) { HttpRuntime.Cache.Insert(key, value); } else { var timeSpan = new TimeSpan(0, 0, timeOut); HttpRuntime.Cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, timeSpan); } return true; } /// <summary> /// 若是不存在key緩存,則添加,返回true。若是已經存在key緩存,則不做操做,返回false。 /// (存入的是源value數據的備份,源數據修改不影響緩存。) /// </summary> /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="timeOut">緩存的過時時間(秒),-1表明不過時。</param> /// <returns></returns> public bool AddIfNotExist<T>(string key, T value, int timeOut = -1) { var timeSpan = timeOut > 0 ? new TimeSpan(0, 0, timeOut) : System.Web.Caching.Cache.NoSlidingExpiration; var oldCache = HttpRuntime.Cache.Add(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, timeSpan, CacheItemPriority.Normal, null); return oldCache == null; } /// <summary> /// 刪除緩存 /// </summary> /// <param name="key"></param> public void Remove(string key) { HttpRuntime.Cache.Remove(key); } public List<T> GetList<T>(List<string> keys) { //內存緩存不實現此接口函數,直接屢次使用Get函數。 //memcache/redis通常會實現此接口函數,是爲了一次鏈接可取回多個值。 throw new NotImplementedException(); } } }
memcache的操做類,網上代碼不少,這邊再也不介紹。
需求場景:多個客戶須要同一個項目產品,可是客戶之間對該產品的需求點又有些不同。若是爲多個客戶都創建一個.net項目,那通用功能的代碼就要維護多份,若是隻創建一個.net項目,而後在同一個項目里加if判斷,那改一個客戶的需求,可能會影響到其它客戶的功能。
解決方案:設計一種「二次開發模式」,即寫一套通用功能的.net通用項目(實際環境中,若是一開始只有一個客戶,那就以第一個客戶的需求爲通用項目,具體問題具體分析),不一樣客戶都創建一個.net項目,但只處理客戶定製的功能,這就涉及到override通用項目功能。
上示例代碼來講明:
#region 正常調用服務和調用二次開發服務 //能夠用服務工廠調用相應方法 ServiceFactory.Get<UserService>().TestFunc(); //也能夠直接調用服務靜態方法 UserService.TestStaticFunc(); //二次開發模式 //1.調用的是UserService中的TestVirtualFunc方法 ServiceFactory.Get<UserService>().TestVirtualFunc(); //2.場景:後續不改原系統代碼,只是在原來基礎上作二次開發 //註冊二次開發Service //ServiceFactory.AddSecondaryAssembly(typeof(UserServiceX).Assembly);//其中UserServiceX繼承自UserService //3.假如執行了ServiceFactory.AddSecondaryAssembly,則下行代碼會調用到UserServiceX中的TestVirtualFunc方法 ServiceFactory.Get<UserService>().TestVirtualFunc(); #endregion
當註冊了二次開發的程序集Assembly,就能夠不改變通用項目的代碼,而運行到二次開發程序集中的代碼。
上ServiceFactory源碼:
using System; using System.Collections; using System.Collections.Concurrent; using System.Reflection; using System.Text; namespace NetDh.TestService { /// <summary> /// 獲取Service對象幫助類 /// </summary> public class ServiceFactory { private static readonly ConcurrentDictionary<Type, BaseService> _services = new ConcurrentDictionary<Type, BaseService>(); static ServiceFactory() { //默認添加本程序集Service var types = Assembly.GetExecutingAssembly().GetTypes(); var baseType = typeof(BaseService); foreach (var type in types) { if (type.IsSubclassOf(baseType)) { //不會實例化服務對象。只有用到時纔會實例化 _services.TryAdd(type, null); } } } /// <summary> /// 獲取服務,T必定是繼承自BaseService /// </summary> /// <typeparam name="T">BaseService子類</typeparam> /// <returns></returns> public static T Get<T>() where T : BaseService { Type type = typeof(T); BaseService service; if (!_services.TryGetValue(type, out service)) { throw new Exception("This service cannot be found"); } if (service == null) { service = Activator.CreateInstance(type) as BaseService; _services[type] = service; } return (T)service; } /// <summary> /// 添加二次開發Service程序集 /// </summary> /// <param name="assembly"></param> public static void AddSecondaryAssembly(Assembly secondaryAssembly) { if (secondaryAssembly == null) return; var secTypes = secondaryAssembly.GetTypes(); var baseType = typeof(BaseService); foreach (var secType in secTypes) { if (secType.IsSubclassOf(baseType)) { Type parentType = null; foreach (var type in _services.Keys) { if (secType.IsSubclassOf(type)) { parentType = type; break; } } if (parentType != null) {//若是二次開發重寫了原Service類 //優先使用二次開發的Service對象。須要在初始化時就實例化。 _services[parentType] = Activator.CreateInstance(secType) as BaseService; } else {//若是二次開發的Service類是新增的,則直接添加,使用時再實例化 _services.TryAdd(secType, null); } } } } } }
國外有github,國內有碼雲,在國內使用碼雲速度很是快。NetDh框架源碼放在碼雲上: