傳統 ADO.NET 交易代碼充滿樣板:SqlConnection、BeginTransaction、try/catch/commit/rollback/finally/close/dispose。每個資料存取方法重複複製,導致:
解決方案:Enterprise Library Unity Interception Extension + Policy Injection Application Block (PIAB),以 Attribute 宣告式 方式將交易行為注入目標方法。
Unity, Unity.Interception, PolicyInjection, Logging, CommonICallHandler,攔截方法調用,管理 TransactionScope 生命週期HandlerAttribute,標記在類別/方法/屬性上,負責建立 Call Handler 實例PolicyInjection.Create<T>() 建立代理實例,啟用攔截管線// EntLib 內建
public interface ICallHandler
{
int Order { get; set; }
IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext);
}
public abstract class HandlerAttribute : Attribute
{
public abstract ICallHandler CreateHandler(IUnityContainer container);
}
public class TransactionCallHandler : ICallHandler
{
private TransactionScopeOption _scopeOption = TransactionScopeOption.Required;
private TransactionOptions _transactionOptions;
private EnterpriseServicesInteropOption _interopOption = EnterpriseServicesInteropOption.None;
private string _functionName;
private string _actionDescription;
public TransactionCallHandler(string functionName, string actionDescription, TransactionOptions transactionOptions)
{
this._transactionOptions = transactionOptions;
this._functionName = functionName;
this._actionDescription = actionDescription;
}
public TransactionCallHandler(TransactionScopeOption scopeOption, TransactionOptions transactionOptions,
EnterpriseServicesInteropOption interopOption)
{
this._scopeOption = scopeOption;
this._transactionOptions = transactionOptions;
this._interopOption = interopOption;
}
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn result;
using (TransactionScope scope = CreateTransactionScope())
{
// 記錄審計日誌
Logger.Write(string.Format("Function Name: {0}, Action: {1}.", _functionName, _actionDescription));
// 執行目標方法
result = getNext()(input, getNext);
if (result.Exception == null)
{
Logger.Write("Action Done.");
scope.Complete(); // 提交
}
else
{
Logger.Write(result.Exception); // 記錄例外,不呼叫 Complete → 自動回滾
}
}
return result;
}
protected virtual TransactionScope CreateTransactionScope()
{
if (_interopOption == EnterpriseServicesInteropOption.None)
return new TransactionScope(_scopeOption, _transactionOptions);
else
return new TransactionScope(_scopeOption, _transactionOptions, _interopOption);
}
}
關鍵點:
using (TransactionScope) 確保範圍結束時自動處理 (Commit 或 Rollback)getNext()(input, getNext) 執行目標方法 (或管線中下一個 Handler)result.Exception == null 判斷成敗,決定 scope.Complete()Logger 記錄審計軌跡[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)]
public class TransactionCallHandlerAttribute : HandlerAttribute
{
private TransactionScopeOption _scopeOption;
private TimeSpan _timeout = TimeSpan.FromMinutes(1);
private IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;
private TransactionOptions _transactionOptions;
private EnterpriseServicesInteropOption _interopOption;
private string _functionName;
private string _actionDescription;
// 多重建構子支援不同參數組合
public TransactionCallHandlerAttribute() { }
public TransactionCallHandlerAttribute(TransactionScopeOption scopeOption) { this._scopeOption = scopeOption; }
public TransactionCallHandlerAttribute(IsolationLevel isolationLevel) { this._isolationLevel = isolationLevel; }
public TransactionCallHandlerAttribute(TransactionScopeOption scopeOption, IsolationLevel isolationLevel) { ... }
public TransactionCallHandlerAttribute(string functionName) : this(functionName, string.Empty) { }
public TransactionCallHandlerAttribute(string functionName, string actionDescription) { ... }
// 屬性公開給組態/設計工具
public string FunctionName { get; set; }
public string ActionDescription { get; set; }
public TransactionScopeOption ScopeOption { get; set; }
public IsolationLevel IsolationLevel { get; set; }
public EnterpriseServicesInteropOption InteropOption { get; set; }
public TransactionOptions TransactionOptions
{
get
{
if (_transactionOptions == null) _transactionOptions = new TransactionOptions();
_transactionOptions.Timeout = _timeout;
_transactionOptions.IsolationLevel = _isolationLevel;
return _transactionOptions;
}
}
public override ICallHandler CreateHandler(IUnityContainer container)
{
_transactionOptions = TransactionOptions;
if (!string.IsNullOrEmpty(this._functionName))
return new TransactionCallHandler(_functionName, _actionDescription, _transactionOptions);
else
return new TransactionCallHandler(ScopeOption, TransactionOptions, InteropOption);
}
}
參數說明:
| 參數 | 用途 | 預設值 |
|---|---|---|
| ScopeOption | 交易範圍行為 | Required (加入環境交易或建新) |
| IsolationLevel | 隔離級別 | ReadCommitted |
| Timeout | 交易超時 | 1 分鐘 |
| InteropOption | COM+ 互通模式 | None |
| FunctionName/ActionDescription | 審計日誌識別資訊 | 空 |