小喵最近開始寫.NET(Core)(有點慢,都已經快.NET10才開始)T.T
由於以往舊的COM+元件還存活著,就算最終要替換到.NET(Core),也需要一段時間並行
那麼如何呼叫舊元件,如何停止,如何確保交易完整性,就變成現在的課題
緣起
小喵最近開始寫.NET(Core)(有點慢,都已經快.NET10才開始)T.T
由於以往舊的COM+元件還存活著,就算最終要替換到.NET(Core),也需要一段時間並行
那麼如何呼叫舊元件,如何停止,如何確保交易完整性,就變成現在的課題
TransactionScope
過去的COM+本身就支援交易(Transaction)的機制,而在.NET中,如果我需要讓.NET的程式與.NET Framework COM+的元件,可以包在一個Transaction中,那麼就需要 TransactionScope 的幫忙。
Late Binding
由於 COM+ 與 .NET(Core) 可以說是兩個世界的產物,以往寫 .NET Framework 還可以透過加入參考的方式,用 Early Binding的方式來處理。但進入 .NET (Core) 還要跟不同世界的 COM+ 溝通,只能用反射的方式,透過 Late Binding 的方式來處理。
程式碼範例
接著就直接看程式碼範例:
/// <summary>
/// 執行.NET和COM+組件的混合交易處理
/// </summary>
/// <param name="sIsStop">停止標記,預設值為"0",用於控制交易流程</param>
/// <returns>執行結果字串,成功返回"Success",失敗返回"Fail"</returns>
/// <remarks>
/// 撰寫者:topcat(000000)
/// 撰寫日期:2025-07-18
/// 相關邏輯:
/// 1. 使用TransactionScope確保交易一致性
/// 2. 同時處理.NET元件(PTLBT1NET8)和COM+元件(PTLBT3ComPlus)的資料寫入
/// 3. 實現分散式交易處理機制
///
/// 功能說明:
/// - 新增一筆資料至T1NET8資料表
/// - 透過COM+元件新增一筆資料至T3相關資料表
/// - 確保兩個操作在同一個交易範圍內完成
///
/// 資料處理流程:
/// 1. 初始化交易範圍
/// 2. 建立.NET元件實例並寫入T1NET8資料
/// 3. 建立COM+元件實例並寫入T3相關資料
/// 4. 確認所有操作成功後提交交易
///
/// 注意事項:
/// - COM+物件需要正確釋放資源
/// - 交易範圍內的異常會導致整個交易回滾
/// - 需要確保COM+元件已正確註冊在系統中
///
/// 資料來源:
/// - T1NET8資料表
/// - T3相關COM+元件資料表
///
/// 相依性:
/// - PTLBT1NET8.CTLBT1NET8 元件
/// - PTLBT3ComPlus.CTLBT3ComPlus2 COM+元件
/// - System.Transactions命名空間
///
/// 安全性考量:
/// - COM+元件呼叫需要適當的執行權限
/// - 確保交易過程中的資料安全性
///
/// 效能考量:
/// - 使用TransactionScope可能影響效能
/// - COM+物件的建立和釋放需要額外資源
///
/// 錯誤處理:
/// - 包含完整的例外處理機制
/// - 交易失敗時自動回滾所有操作
///
/// 修改者:
/// 修改日期:
/// 修改內容:
/// </remarks>
public string InsertNetAndCOMPlus(string sIsStop = "0")
{
string rc = "";
// 啟用隱含分散式交易
TransactionManager.ImplicitDistributedTransactions = true;
using (TransactionScope scope = new TransactionScope())
{
// 初始化.NET元件
PTLBT1NET8.CTLBT1NET8? oDao1 = new PTLBT1NET8.CTLBT1NET8();
// 初始化COM+元件
Type? type = Type.GetTypeFromProgID("PTLBT3ComPlus.CTLBT3ComPlus2");
object? obj = Activator.CreateInstance(type);
try
{
// 準備並寫入.NET元件資料
T1NET8Info oT1NET8 = new T1NET8Info();
oT1NET8.T1F1 = "TestT1NET8_" + DateTime.Now.ToString("yyyyMMddHHmmss");
oT1NET8.Adder = "topcat";
int NewT1Id = 0;
string? rc1 = oDao1.InsertT1NET8(oT1NET8, ref NewT1Id, sIsStop);
// 準備COM+元件資料
T3ComPlusAM oT3ComPlusAM = new T3ComPlusAM();
oT3ComPlusAM.T3F1 = "TestT3F1ComPlus_" + DateTime.Now.ToString("yyyyMMddHHmmss");
oT3ComPlusAM.T3F2 = "TestT3F2ComPlus_" + DateTime.Now.ToString("yyyyMMddHHmmss");
oT3ComPlusAM.Adder = "topcat";
// 序列化COM+資料
string sT3ComPlus = JsonSerializer.Serialize(oT3ComPlusAM, new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
// 執行COM+方法
object[]? args = { sT3ComPlus, sIsStop };
object? result = type?.InvokeMember("InsertT3ComPlus", BindingFlags.InvokeMethod, null, obj, args);
// 確認執行結果並完成交易
if (result is not null)
{
scope.Complete();
rc = "Success";
}
else
{
scope.Dispose();
rc = "Fail";
}
}
catch (Exception ex)
{
scope.Dispose();
throw new Exception(ex.Message);
}
finally
{
// 清理資源
oDao1 = null;
if (obj is IDisposable disposable)
{
disposable.Dispose();
}
Marshal.ReleaseComObject(obj);
obj = null;
}
}
return rc;
}
註解的部分是AI幫我弄的(現在這個時代,有AI真好)
主要注意的是 COM+ 呼叫,使用反射的方式處理,而回收的部分,小喵找了好久,終於試出來一個可行的方式
if (obj is IDisposable disposable)
{
disposable.Dispose();
}
Marshal.ReleaseComObject(obj);
obj = null;
末語
現在AI時代,很多東西找AI問問就可以,不過像這種.NET 呼叫 .NET Framework COM+的特別需求,資訊真的不多,以往沒有AI幫忙的時代,這個問題可能要花很多時間,在茫茫大海中尋找很久才能找到可能可用的方式。現在有AI幫忙,很快就能找到這個解法。
不過還是紀錄一下,以後如果需要,回來自己的部落格找,比較容易找到。
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
- 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
Microsoft MVP Visual Studio and Development Technologies (2005~2019/6) | topcat Blog:http://www.dotblogs.com.tw/topcat |