.NET面向上下文架構(gòu)模式
1. 上下文概述
上下文:其實(shí)就是一個(gè)邏輯上的業(yè)務(wù)、功能區(qū)域。在這個(gè)邏輯區(qū)域里可以有效的進(jìn)行管理,算是一種制度的約束,也可以理解為某種范圍類的數(shù)據(jù)共享。
其實(shí)在很多應(yīng)用框架中到處可以看見上下文的概念,包括.NET本身的設(shè)計(jì)就建立在這種思想上的。實(shí)例化的對象默認(rèn)存在于系統(tǒng)中的默認(rèn)上下文中,我們可以構(gòu)建自己的上下文將對象在運(yùn)行時(shí)進(jìn)行合理的管理。
在ASP.NET框架中比較經(jīng)典的就是HttpContext上下文對象。所有的運(yùn)行時(shí)對象都會(huì)邏輯歸屬到HttpContext上下文中來,如:我們可以使用Request、Response等對象訪問HTTP處理的生命周期數(shù)據(jù)。
在Remoting中跨AppDomin訪問也是建立在上下文基礎(chǔ)上的,請求的消息通過隧道后序列化到達(dá)調(diào)用發(fā)。王清培版權(quán)所有,轉(zhuǎn)載請給出署名
在這些強(qiáng)大的應(yīng)用框架背后總有著讓人難以琢磨的設(shè)計(jì)秘方,諸多的設(shè)計(jì)原則、設(shè)計(jì)模式、豐富的實(shí)踐經(jīng)驗(yàn)都將是框架穩(wěn)定運(yùn)行的基石。Context算是一個(gè)比較完美的邏輯范圍設(shè)計(jì)模式。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
那么就讓我們來領(lǐng)略一下上下文的奧秘吧!
2. 上下文的一般應(yīng)用
上下文的設(shè)計(jì)思想絕對的美妙,很多地方一旦進(jìn)行上下文抽象就能解決很多問題。比如在Remoting中我們可以動(dòng)態(tài)的在上下文中加入很多擴(kuò)展對上下文中的所有對象進(jìn)行強(qiáng)制管理,比如:調(diào)用某一個(gè)方法我們需要進(jìn)行安全檢查,我們可以編寫一個(gè)滿足自己當(dāng)前項(xiàng)目需求的安全認(rèn)證插件動(dòng)態(tài)的注入到上下文管理器區(qū)域中,在這個(gè)地方就體現(xiàn)出上下文的設(shè)計(jì)優(yōu)勢。
在Web編程中,由于它有著與Winfrom編程很大的差異性,需要將同一組對象同時(shí)服務(wù)于N個(gè)客戶端進(jìn)行使用,而在Winfrom中基本上都是屬于單線程的,當(dāng)然可以手動(dòng)的開啟多線程并行操作。對于ASP.NET每當(dāng)有新的請求處理時(shí),框架會(huì)自動(dòng)開啟新的線程去處理當(dāng)前的調(diào)用,然后這個(gè)時(shí)候就是需要一個(gè)相對于之前操作的獨(dú)立上下文數(shù)據(jù)環(huán)境,而不是在同一個(gè)服務(wù)器上的所有線程都是共享的。王清培版權(quán)所有,轉(zhuǎn)載請給出署名
那么我們就需要將當(dāng)前的HTTP處理的相關(guān)數(shù)據(jù)納入到一個(gè)邏輯的上下文進(jìn)行管理和數(shù)據(jù)共享。
這么多的優(yōu)勢存在,看來我們是有必要嘗試一下這中設(shè)計(jì)模式了。那么就目前系統(tǒng)開發(fā)框架而言我們的上下文能用在哪里呢?我想當(dāng)務(wù)之急就是將分層架構(gòu)中的所有單條線上的對象進(jìn)行上下文管理。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
典型的三層架構(gòu):
在一般的三層架構(gòu)開發(fā)過程中我們的調(diào)用關(guān)系基本都是這樣的,利用上下文設(shè)計(jì)模式我們可以將本來鼓勵(lì)的對象進(jìn)行合理的管理。上圖中User對象線將是屬于User上下文的,Order對象線將是屬于Order上下文的。大家互不干擾,可以在這個(gè)邏輯上下文中共享數(shù)據(jù)、設(shè)置調(diào)用安全策略、設(shè)計(jì)日志記錄方式、甚至可以計(jì)算每個(gè)方法的性能。
BLL的調(diào)用代碼:
- View Code
- /***
- * author:深度訓(xùn)練
- * 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:深度訓(xùn)練
- * 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ā)送成功!");
- }
- }
- }
上述代碼是我模擬一個(gè)上下文的執(zhí)行過程。
3. 上下文共享區(qū)域
在每個(gè)獨(dú)立的上下文環(huán)境中應(yīng)該有一片共享的數(shù)據(jù)存儲(chǔ)區(qū)域,以備多個(gè)上下文對象訪問。這種方便性多半存在于項(xiàng)目比較緊張的修改需求的時(shí)候或者加新業(yè)務(wù)的時(shí)候擴(kuò)展方法用的。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í)行代碼:
- [ContextModule.ContextLogHandler(OperationSort = 1)]
- public void UpdateOrderSingle()
- {
- Model.Model_Order ordermodel =
- ContextModule.ContextRuntime.CurrentContextRuntime.GetValue("updateorder") as Model.Model_Order;
- }
#p#
4. 上下文運(yùn)行時(shí)環(huán)境
對于上下文運(yùn)行時(shí)環(huán)境的構(gòu)建需要考慮到運(yùn)行時(shí)是共享的上下文對象。對于納入上下文管理的所有對象都需要共享或者說是受控于上下文運(yùn)行時(shí)。
上下文構(gòu)建:
- View Code
- /***
- * author:深度訓(xùn)練
- * blog:http://wangqingpei557.blog.51cto.com/
- * **/
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ContextModule
- {
- /// <summary>
- /// 上下文運(yùn)行時(shí)環(huán)境。
- /// 上下文邏輯運(yùn)行時(shí)環(huán)境,環(huán)境中的功能都是可以通過附加進(jìn)來的。
- /// </summary>
- public class ContextRuntime : IDisposable
- {
- #region IDisposable成員
- void IDisposable.Dispose()
- {
- _currentContextRuntime = null;
- }
- #endregion
- protected ContextRuntime() { }
- private DateTime _initTime = DateTime.Now;
- /// <summary>
- /// 獲取運(yùn)行時(shí)創(chuàng)建上下文的時(shí)間
- /// </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>
- /// 獲取運(yùn)行時(shí)創(chuàng)建上下文的唯一標(biāo)識(shí)
- /// </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>
- /// 獲取當(dāng)前上下文運(yùn)行時(shí)對象.
- /// </summary>
- public static ContextRuntime CurrentContextRuntime { get { return _currentContextRuntime; } }
- /// <summary>
- /// 開始運(yùn)行時(shí)上下文
- /// </summary>
- /// <returns>ContextRuntime</returns>
- public static ContextRuntime BeginContextRuntime()
- {
- //可以通過配置文件配置上下文運(yùn)行時(shí)環(huán)境的參數(shù)。這里只是實(shí)現(xiàn)簡單的模擬。
- _currentContextRuntime = new ContextRuntime();
- return _currentContextRuntime;
- }
- }
- }
對于上下文的入口構(gòu)建:
- using (ContextModule.ContextRuntime.BeginContextRuntime())
- {
- }
通過Using的方式我們開始上下文生命周期。
5. 上下文活動(dòng)對象
上下文對象的綁定需要延后,不能在對象的構(gòu)建時(shí)就創(chuàng)建上下文。
使用后期綁定動(dòng)態(tài)的切入到執(zhí)行的上下文中。
調(diào)用代碼,上下文入口:
- View Code
- /***
- * author:深度訓(xùn)練
- * 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);
- }
- }
- }
- }
#p#
6. 上下文在分層架構(gòu)中的運(yùn)用
有了上下文的核心原型之后我們可以擴(kuò)展到分層架構(gòu)中來,對于分層架構(gòu)的使用其實(shí)很有必要,一般的大型業(yè)務(wù)系統(tǒng)都是混合的使用模式,可能有C/S、B/S、Mobile終端等等。
對于加入Service層之后BLL、DAL將位于服務(wù)之后,對于來自客戶端的調(diào)用需要經(jīng)過一些列的身份驗(yàn)證及權(quán)限授予。有了WCF之后面向SOA的架構(gòu)開發(fā)變的相對容易點(diǎn),對安全、性能、負(fù)載等等都很完美,所以大部分的情況下我們很少需要控制BLL、DAL的執(zhí)行運(yùn)行。
那么沒有使用WCF構(gòu)建分布式的系統(tǒng)時(shí)或者是沒有分布式的需求就是直接的調(diào)用,如WEB的一般開發(fā),從UI到BLL到DAL?;蛘呤瞧胀ǖ?span style="font-family: Calibri">Winfrom的項(xiàng)目、控制臺(tái)項(xiàng)目屬于內(nèi)網(wǎng)的使用,可能就需要控制到代碼的執(zhí)行。
下面我通過演示一個(gè)具體的實(shí)例來看看到底效果如何。
我以控制臺(tái)的程序作為演示項(xiàng)目類型,也使用簡單的三層架構(gòu)。
這個(gè)再簡單不過了吧,為了演示越簡單越好,關(guān)鍵是突出重點(diǎn)。
需求:
在DAL對象里面加入一個(gè)插入Order實(shí)體對象的方法:
- View Code
- /***
- * author:深度訓(xùn)練
- * 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 };
- }
- }
- }
在這個(gè)類的上面有一個(gè)特性ContextEveningBound,該是用來表示當(dāng)前對象屬于后期綁定到上下文的對象。同時(shí)該類也繼承自一個(gè)ContextModuleBaseObject<DAL_Order>泛型類,主要作用是將對象強(qiáng)制的綁定到上下文進(jìn)行管理。
在方法InsertOrderSingle上面有兩個(gè)特性,ContextLogHandler是用來記錄方法的執(zhí)行日志,ContextSecurityHanlder是用來在方法執(zhí)行的過程中強(qiáng)制要求管理員認(rèn)證。
BLL對象代碼:
- View Code
- /***
- * author:深度訓(xùn)練
- * 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);
- }
- }
- }
在BLL對象里面有一個(gè)調(diào)用DAL對象方法的實(shí)例對象,為了演示簡單這里沒有加入層的依賴注入設(shè)計(jì)方案,通過直接調(diào)用方式。在BLL方法體中有一個(gè)專門用來在上下文中調(diào)用方法的接口,這是約束目的是為了能讓框架切入到方法的執(zhí)行之前先執(zhí)行。具體的設(shè)計(jì)原理我將在下一篇文章中詳細(xì)講解。
在方法的上面有一個(gè)ContextExceptionHandler特性,目的是安全的調(diào)用DAL對象的方法,在有異常的情況下能通過上下文的方式人性化的提示錯(cuò)誤信息。這樣我們就不需要頻繁的編寫捕獲異常的代碼,看起來也不爽,我們要的是代碼的整潔、美麗。
UI調(diào)用:
- View Code
- /***
- * author:深度訓(xùn)練
- * 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í)行效果:
會(huì)先執(zhí)行日志的記錄,然后要求我們輸入用戶憑證才能繼續(xù)執(zhí)行下面的方法。
我輸入YES才能繼續(xù)執(zhí)行插入的方法。我們可以通過很簡單的實(shí)現(xiàn)上下文的管理接口,對方法進(jìn)行控制。
總結(jié):該篇文章只是介紹上下文的作用、原理、優(yōu)勢。下篇文章:“.NET 面向上下文架構(gòu)模式(實(shí)現(xiàn))”將詳細(xì)的介紹上下文框架如何開發(fā)。
原文鏈接:http://www.cnblogs.com/wangiqngpei557/archive/2012/07/29/2614220.html