首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

Silverlight 同步調用 WCF 服務:DanielVaughan 庫實現真正阻塞等待

     編輯:ASP.NET 基礎

前言

Silverlight 強制異步調用 WCF (Begin/End 模式),導致複雜業務流程陷入「回調地獄」。本文介紹 DanielVaughan.SynchronousChannelBroker 庫,通過線程池 + 同步上下文切換,實現代碼邏輯同步寫法、底層異步執行,附完整集成步驟、代碼對比、注意事項。

一、痛點:異步回調地獄


// 原生異步:多步驟業務極其痛苦
void Step1() { client.DoWorkAsync(input1); }
void Client_DoWorkCompleted(object sender, DoWorkCompletedEventArgs e) 
{
    if (e.Error != null) return;
    Step2(e.Result); // 再註冊下一個 Completed...
}
void Step2(string input2) { client.DoWork2Async(input2); }
// ... 無盡鏈條

二、引入 DanielVaughan 庫

  1. 下載 DanielVaughan.dll (或源碼編譯)
  2. 項目右鍵「添加引用」→ 瀏覽選中 DLL
  3. 引用命名空間:
    using DanielVaughan;
    using System.Threading;

三、同步調用代碼實現


public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        // 必須初始化同步上下文 (UI 線程)
        UISynchronizationContext.Instance.Initialize(Dispatcher);
    }
    
    private void btnSync_Click(object sender, RoutedEventArgs e)
    {
        string input = txtInput.Text;
        string result = "NULL";
        
        // 關鍵:放入線程池執行同步調用,避免阻塞 UI 線程
        ThreadPool.QueueUserWorkItem(_ =>
        {
            try
            {
                // 獲取通道 (需實現 ChannelManager 單例)
                var svc = ChannelManager.Instance.GetChannel();
                
                // 核心:同步調用,內部自動處理 Begin/End + 異常傳播
                result = SynchronousChannelBroker.PerformAction(
                    svc.BeginDoWork, 
                    svc.EndDoWork, 
                    input);
            }
            catch (Exception ex)
            {
                result = "Error: " + ex.Message;
            }
            
            // 切回 UI 線程更新界面
            Dispatcher.BeginInvoke(() => 
            {
                txtResult.Text += $"\r\n同步調用--{result}\r\n";
            });
        });
    }
    
    // 原生異步對比
    private void btnAsync_Click(object sender, RoutedEventArgs e)
    {
        var client = new Service1Client();
        client.DoWorkCompleted += (s, args) => 
        {
            txtResult.Text += $"異步調用--{args.Result}\r\n";
        };
        client.DoWorkAsync(txtInput.Text);
    }
}

四、ChannelManager 單例實現 (WCF 通道管理)


public class ChannelManager
{
    private static readonly Lazy _instance = 
        new Lazy(() => new ChannelManager());
    
    public static ChannelManager Instance => _instance.Value;
    
    private ChannelFactory _factory;
    
    private ChannelManager()
    {
        var binding = new BasicHttpBinding();
        var endpoint = new EndpointAddress("Service1.svc");
        _factory = new ChannelFactory(binding, endpoint);
    }
    
    public T GetChannel() where T : class
    {
        return _factory.CreateChannel();
    }
}

五、服務端定義 (為完整可運行)


[ServiceContract]
public interface IService1
{
    [OperationContract]
    string DoWork(string input);
}

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
    public string DoWork(string input)
    {
        Thread.Sleep(1000); // 模擬耗時操作
        return $"服務端處理完成,返回: {input} @ {DateTime.Now}";
    }
}

六、關鍵原理解析

組件作用
UISynchronizationContext捕獲 UI 線程 SynchronizationContext,保證回調能切回 UI 更新控件
ThreadPool.QueueUserWorkItem將同步調用移至後台線程,避免凍結 UI
SynchronousChannelBroker.PerformAction內部用 AutoResetEvent 阻塞線程,等待 Begin/End 完成,自動處理異常、超時、取消
ChannelManager複用 ChannelFactory,避免頻繁創建開銷,單例線程安全

七、適用場景與限制

  • ✅ 適用:3+ 步驟強依賴順序的業務流程 (登錄→獲取權限→加載數據→初始化UI)
  • ✅ 適用:需在同步邏輯中捕獲異常、使用 try/catch/finally
  • ❌ 不適用:簡單單次調用 (原生異步更輕量)
  • ❌ 不適用:長時間運行 (超過 30s) 易觸發 WCF 默認超時,需配置 binding sendTimeout
  • ⚠️ 注意:Silverlight 5 已停止支持,新項目請用 Blazor/MAUI/ASP.NET Core + WebAssembly

總結

DanielVaughan 庫通過「線程池阻塞 + 同步上下文切換」巧妙破解 Silverlight 強制異步限制,讓開發者用同步思維編寫複雜 WCF 調用鏈。雖然技術棧已過時,但其同步包裝異步模式 (Sync-over-Async) 在現代 .NET 中依然廣泛應用 (如 Task.Run、AsyncContext、Nito.AsyncEx),理解其原理極具價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved