1. 上下文概述
上下文:其實就是一個邏輯上的業(yè)務(wù)、功能區(qū)域。在這個邏輯區(qū)域里可以有效的進行管理,算是一種制度的約束,也可以理解為某種范圍類的數(shù)據(jù)共享。
其實在很多應(yīng)用框架中到處可以看見上下文的概念,包括.NET本身的設(shè)計就建立在這種思想上的。實例化的對象默認存在于系統(tǒng)中的默認上下文中,我們可以構(gòu)建自己的上下文將對象在運行時進行合理的管理。
在ASP.NET框架中比較經(jīng)典的就是HttpContext上下文對象。所有的運行時對象都會邏輯歸屬到HttpContext上下文中來,如:我們可以使用Request、Response等對象訪問HTTP處理的生命周期數(shù)據(jù)。
在Remoting中跨AppDomin訪問也是建立在上下文基礎(chǔ)上的,請求的消息通過隧道后序列化到達調(diào)用發(fā)。王清培版權(quán)所有,轉(zhuǎn)載請給出署名
在這些強大的應(yīng)用框架背后總有著讓人難以琢磨的設(shè)計秘方,諸多的設(shè)計原則、設(shè)計模式、豐富的實踐經(jīng)驗都將是框架穩(wěn)定運行的基石。Context算是一個比較完美的邏輯范圍設(shè)計模式。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
那么就讓我們來領(lǐng)略一下上下文的奧秘吧!
2. 上下文的一般應(yīng)用
上下文的設(shè)計思想絕對的美妙,很多地方一旦進行上下文抽象就能解決很多問題。比如在Remoting中我們可以動態(tài)的在上下文中加入很 多擴展對上下文中的所有對象進行強制管理,比如:調(diào)用某一個方法我們需要進行安全檢查,我們可以編寫一個滿足自己當前項目需求的安全認證插件動態(tài)的注入到 上下文管理器區(qū)域中,在這個地方就體現(xiàn)出上下文的設(shè)計優(yōu)勢。
在Web編程中,由于它有著與Winfrom編程很大的差異性,需要將同一組對象同時服務(wù)于N個客戶端進行使用,而在Winfrom中基本上都是屬于單線程的,當然可以手動的開啟多線程并行操作。對于ASP.NET每當有新的請求處理時,框架會自動開啟新的線程去處理當前的調(diào)用,然后這個時候就是需要一個相對于之前操作的獨立上下文數(shù)據(jù)環(huán)境,而不是在同一個服務(wù)器上的所有線程都是共享的。王清培版權(quán)所有,轉(zhuǎn)載請給出署名
那么我們就需要將當前的HTTP處理的相關(guān)數(shù)據(jù)納入到一個邏輯的上下文進行管理和數(shù)據(jù)共享。
這么多的優(yōu)勢存在,看來我們是有必要嘗試一下這中設(shè)計模式了。那么就目前系統(tǒng)開發(fā)框架而言我們的上下文能用在哪里呢?我想當務(wù)之急就是將分層架構(gòu)中的所有單條線上的對象進行上下文管理。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
典型的三層架構(gòu):
- View Code
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Reflection;
- namespace ConsoleApplication1.BLL
- {
- [ContextModule.ContextEveningBound(IsEvening = true)]
- public class BLL_Order : ContextModule.ContextModuleBaseObject<BLL_Order>
- {
- DAL.DAL_Order dal_order = new DAL.DAL_Order();
- [ContextModule.ContextExceptionHandler(OperationSort = 1)]
- public Model.Model_Order InsertOrderSingle(Model.Model_Order ordermodel)
- {
- return ContextModule.ContextAction.PostMethod<DAL.DAL_Order, Model.Model_Order>(
- dal_order, dal_order.GetMethodInfo("InsertOrderSingle"), ordermodel);
- }
- [ContextModule.ContextExceptionHandler(OperationSort = 1)]
- public void SendOrder(Model.Model_Order ordermodel)
- {
- ContextModule.ContextAction.PostMethod<DAL.DAL_Order, object>(
- dal_order, dal_order.GetMethodInfo("SendOrder"), ordermodel);
- }
- }
- }
DAL的執(zhí)行代碼:
- View Code
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ConsoleApplication1.DAL
- {
- [ContextModule.ContextEveningBound(IsEvening = true)]
- public class DAL_Order : ContextModule.ContextModuleBaseObject<DAL_Order>
- {
- [ContextModule.ContextLogHandler(OperationSort = 1)]
- [ContextModule.ContextSecurityHanlder(OperationSort = 2)]
- public Model.Model_Order InsertOrderSingle(Model.Model_Order ordermodel)
- {
- return new Model.Model_Order() { OrderGuid = Guid.NewGuid(), OrderTime = DateTime.Now };
- }
- [ContextModule.ContextLogHandler(OperationSort = 1)]
- public void SendOrder(Model.Model_Order ordermodel)
- {
- Console.WriteLine("訂單發(fā)送成功!");
- }
- }
- }
上述代碼是我模擬一個上下文的執(zhí)行過程。
在每個獨立的上下文環(huán)境中應(yīng)該有一片共享的數(shù)據(jù)存儲區(qū)域,以備多個上下文對象訪問。這種方便性多半存在于項目比較緊張的修改需求的時候或者加新業(yè)務(wù)的時候擴展方法用的。
BLL調(diào)用代碼:
- View Code
- [ContextModule.ContextExceptionHandler(OperationSort = 1)]
- public void UpdateOrderSingle()
- {
- Model.Model_Order ordermodel = new Model.Model_Order() { OrderGuid = Guid.NewGuid(), OrderTime = DateTime.Now };
- //放入上下文共享對象池
- ContextModule.ContextRuntime.CurrentContextRuntime.SetValue("updateorder", ordermodel);
- ContextModule.ContextAction.PostMethod<DAL.DAL_Order, object>(
- dal_order, dal_order.GetMethodInfo("UpdateOrderSingle"), null);
- }
DAL執(zhí)行代碼:DAL執(zhí)行代碼:DAL執(zhí)行代碼:DAL執(zhí)行代碼:
- [ContextModule.ContextLogHandler(OperationSort = 1)]
- public void UpdateOrderSingle()
- {
- Model.Model_Order ordermodel =
- ContextModule.ContextRuntime.CurrentContextRuntime.GetValue("updateorder") as Model.Model_Order;
- }
對于上下文運行時環(huán)境的構(gòu)建需要考慮到運行時是共享的上下文對象。對于納入上下文管理的所有對象都需要共享或者說是受控于上下文運行時。
上下文構(gòu)建:
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ContextModule
- {
- /// <summary>
- /// 上下文運行時環(huán)境。
- /// 上下文邏輯運行時環(huán)境,環(huán)境中的功能都是可以通過附加進來的。
- /// </summary>
- public class ContextRuntime : IDisposable
- {
- #region IDisposable成員
- void IDisposable.Dispose()
- {
- _currentContextRuntime = null;
- }
- #endregion
- protected ContextRuntime() { }
- private DateTime _initTime = DateTime.Now;
- /// <summary>
- /// 獲取運行時創(chuàng)建上下文的時間
- /// </summary>
- public virtual DateTime InitTime { get { return _initTime; } }
- private Dictionary<object, object> _runTimeResource = new Dictionary<object, object>();
- private ContextFilterHandlerMap _filterMap = new ContextFilterHandlerMap();
- /// <summary>
- /// 獲取上下文中的方法、類過濾器映射表
- /// </summary>
- public ContextFilterHandlerMap FilterMap { get { return _filterMap; } }
- private Guid _initPrimaryKey = Guid.NewGuid();
- /// <summary>
- /// 獲取運行時創(chuàng)建上下文的唯一標識
- /// </summary>
- public virtual Guid InitPrimaryKey { get { return _initPrimaryKey; } }
- /// <summary>
- /// 獲取上下文共享區(qū)域中的數(shù)據(jù)
- /// </summary>
- /// <param name="key">數(shù)據(jù)Key</param>
- /// <returns>object數(shù)據(jù)對象</returns>
- public virtual object GetValue(object key)
- {
- return _runTimeResource[key];
- }
- /// <summary>
- /// 設(shè)置上下文共享區(qū)域中的數(shù)據(jù)
- /// </summary>
- /// <param name="key">數(shù)據(jù)Key</param>
- /// <param name="value">要設(shè)置的數(shù)據(jù)對象</param>
- public virtual void SetValue(object key, object value)
- {
- _runTimeResource[key] = value;
- }
- [ThreadStatic]
- private static ContextRuntime _currentContextRuntime;
- /// <summary>
- /// 獲取當前上下文運行時對象.
- /// </summary>
- public static ContextRuntime CurrentContextRuntime { get { return _currentContextRuntime; } }
- /// <summary>
- /// 開始運行時上下文
- /// </summary>
- /// <returns>ContextRuntime</returns>
- public static ContextRuntime BeginContextRuntime()
- {
- //可以通過配置文件配置上下文運行時環(huán)境的參數(shù)。這里只是實現(xiàn)簡單的模擬。
- _currentContextRuntime = new ContextRuntime();
- return _currentContextRuntime;
- }
- }
- }
對于上下文的入口構(gòu)建:
- //開啟上下文
- using (ContextModule.ContextRuntime.BeginContextRuntime())
- {
- }
通過Using的方式我們開始上下文生命周期。
上下文對象的綁定需要延后,不能在對象的構(gòu)建時就創(chuàng)建上下文。
使用后期綁定動態(tài)的切入到執(zhí)行的上下文中。
調(diào)用代碼,上下文入口:
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Data;
- using ConsoleApplication1.BLL;
- using ConsoleApplication1.Model;
- namespace ConsoleApplication1
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- BLL.BLL_Order order = new BLL.BLL_Order();
- using (ContextModule.ContextRuntime.BeginContextRuntime())
- {
- Model.Model_Order ordermodel = new Model_Order() { OrderGuid = Guid.NewGuid(), OrderTime = DateTime.Now };
- Model.Model_Order resultmodel = ContextModule.ContextAction.PostMethod<BLL.BLL_Order, Model.Model_Order>(order, order.GetMethodInfo("InsertOrderSingle"), ordermodel);
- ContextModule.ContextAction.PostMethod<BLL.BLL_Order, object>(order, order.GetMethodInfo("SendOrder"), ordermodel);
- }
- }
- }
- }
6. 上下文在分層架構(gòu)中的運用
有了上下文的核心原型之后我們可以擴展到分層架構(gòu)中來,對于分層架構(gòu)的使用其實很有必要,一般的大型業(yè)務(wù)系統(tǒng)都是混合的使用模式,可能有C/S、B/S、Mobile終端等等。
對于加入Service層之后BLL、DAL將位于服務(wù)之后,對于來自客戶端的調(diào)用需要經(jīng)過一些列的身份驗證及權(quán)限授予。有了WCF之后面向SOA的架構(gòu)開發(fā)變的相對容易點,對安全、性能、負載等等都很完美,所以大部分的情況下我們很少需要控制BLL、DAL的執(zhí)行運行。
那么沒有使用WCF構(gòu)建分布式的系統(tǒng)時或者是沒有分布式的需求就是直接的調(diào)用,如WEB的一般開發(fā),從UI到BLL到DAL。或者是普通的Winfrom的項目、控制臺項目屬于內(nèi)網(wǎng)的使用,可能就需要控制到代碼的執(zhí)行。
下面我通過演示一個具體的實例來看看到底效果如何。
我以控制臺的程序作為演示項目類型,也使用簡單的三層架構(gòu)。
這個再簡單不過了吧,為了演示越簡單越好,關(guān)鍵是突出重點。
需求:
在DAL對象里面加入一個插入Order實體對象的方法:
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ConsoleApplication1.DAL
- {
- [ContextModule.ContextEveningBound(IsEvening = true)]
- public class DAL_Order : ContextModule.ContextModuleBaseObject<DAL_Order>
- {
- [ContextModule.ContextLogHandler(OperationSort = 1)]
- [ContextModule.ContextSecurityHanlder(OperationSort = 2)]
- public Model.Model_Order InsertOrderSingle(Model.Model_Order ordermodel)
- {
- return new Model.Model_Order() { OrderGuid = Guid.NewGuid(), OrderTime = DateTime.Now };
- }
- }
- }
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Reflection;
- namespace ConsoleApplication1.BLL
- {
- [ContextModule.ContextEveningBound(IsEvening = true)]
- public class BLL_Order : ContextModule.ContextModuleBaseObject<BLL_Order>
- {
- DAL.DAL_Order dal_order = new DAL.DAL_Order();
- [ContextModule.ContextExceptionHandler(OperationSort = 1)]
- public Model.Model_Order InsertOrderSingle(Model.Model_Order ordermodel)
- {
- return ContextModule.ContextAction.PostMethod<DAL.DAL_Order, Model.Model_Order>(
- dal_order, dal_order.GetMethodInfo("InsertOrderSingle"), ordermodel);
- }
- }
- }
- /***
- * author:深度訓練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Data;
- using ConsoleApplication1.BLL;
- using ConsoleApplication1.Model;
- namespace ConsoleApplication1
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- BLL.BLL_Order order = new BLL.BLL_Order();
- //開啟上下文
- using (ContextModule.ContextRuntime.BeginContextRuntime())
- {
- Model.Model_Order ordermodel = new Model_Order() { OrderGuid = Guid.NewGuid(), OrderTime = DateTime.Now };
- Model.Model_Order resultmodel =
- ContextModule.ContextAction.PostMethod<BLL.BLL_Order, Model.Model_Order>(
- order, order.GetMethodInfo("InsertOrderSingle"), ordermodel);
- }
- }
- }
- }
執(zhí)行效果:
會先執(zhí)行日志的記錄,然后要求我們輸入用戶憑證才能繼續(xù)執(zhí)行下面的方法。