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

C# DLL 非同步 HTTP 請求回呼 JavaScript:跨語言事件整合

     編輯:關於C#

應用場景

JavaScript XMLHttpRequest 受限於單執行緒與瀏覽器並發限制,需由 C# DLL 提供多執行緒非同步 HTTP 下載,完成後回呼 JS 函式。

C# DLL 核心實作


using System;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

public class AsyncHttpClient
{
    // 回呼委派定義 (供 JS/COM 呼叫)
    public delegate void CallbackDelegate(string url, string content, int errorCode);

    private CallbackDelegate _callback;

    /// 
    /// 設定完成回呼
    /// 
    public void SetCallback(CallbackDelegate callback)
    {
        _callback = callback;
    }

    /// 
    /// 非同步 GET 請求 (多執行緒)
    /// 
    public void AsyncGet(string url, int timeoutMs = 30000)
    {
        Task.Run(async () =>
        {
            string content = null;
            int errorCode = 0;
            
            try
            {
                using (var client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMilliseconds(timeoutMs);
                    content = await client.GetStringAsync(url);
                }
            }
            catch (TaskCanceledException)
            {
                errorCode = -1; // Timeout
                content = "timeout";
            }
            catch (Exception ex)
            {
                errorCode = -2; // Other error
                content = ex.Message;
            }
            
            // 執行回呼 (確保在正確執行緒/上下文)
            _callback?.Invoke(url, content, errorCode);
        });
    }
}

暴露給 COM/JS 的介面


[ComVisible(true)]
[Guid("YOUR-GUID-HERE")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IAsyncHttpClient
{
    void SetCallback([MarshalAs(UnmanagedType.IDispatch)] object callback);
    void AsyncGet(string url, int timeoutMs);
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("YOUR-CLASS-GUID")]
[ProgId("MyHttpClient.AsyncHttpClient")]
public class ComAsyncHttpClient : IAsyncHttpClient
{
    private readonly AsyncHttpClient _inner = new AsyncHttpClient();
    
    public void SetCallback(object callback)
    {
        // JS 函式物件轉為委派
        _inner.SetCallback((url, content, errorCode) =>
        {
            try
            {
                // 動態呼叫 JS 函式
                var callbackType = callback.GetType();
                callbackType.InvokeMember("", 
                    System.Reflection.BindingFlags.InvokeMethod, 
                    null, callback, new object[] { url, content, errorCode });
            }
            catch { /* 忽略 JS 端錯誤 */ }
        });
    }
    
    public void AsyncGet(string url, int timeoutMs) => _inner.AsyncGet(url, timeoutMs);
}

註冊與使用

  1. 專案屬性 → Build → 勾選 Register for COM interop (需管理員權限)
  2. 或手動註冊:regasm MyHttpClient.dll /codebase /tlb
  3. HTML/JS 端使用:
    
    <script>
        var http = new ActiveXObject("MyHttpClient.AsyncHttpClient");
        
        http.SetCallback(function(url, content, errorCode) {
            if (errorCode === 0) {
                console.log("成功:", url, content.substring(0, 100));
                document.getElementById("result").innerText = content;
            } else if (errorCode === -1) {
                alert("請求逾時: " + url);
            } else {
                alert("錯誤: " + content);
            }
        });
        
        http.AsyncGet("https://api.example.com/data", 5000);
    </script>
    

關鍵技術點

項目說明
ComVisible組件/類別/介面必須標記,才能被 COM/JS 存取
IDispatch支援晚期繫結,JS 可動態呼叫
回呼封送JS 函式物件 → object → InvokeMember 動態呼叫
執行緒安全C# 回呼在 ThreadPool 執行緒,JS 為單執行緒,通常無衝突
錯誤代碼約定:0=成功, -1=逾時, -2=其他錯誤
部署需目標機器註冊 DLL,或用免註冊 COM (Manifest)

現代替代方案

  • WebAssembly:C# (Blazor WASM) 直接在瀏覽器運行,無需 COM
  • Native Messaging:Chrome/Firefox 擴充功能與本機程式通訊
  • WebSocket / SignalR:伺服器推播,避免輪詢
  • Edge WebView2:內嵌 Edge 瀏覽器,C# 與 JS 共享進程記憶體

安全性提醒

  • COM 物件擁有完整系統權限,僅信任來源使用
  • 生產環境建議簽署組件、啟用代碼存取安全性 (CAS)
  • 考慮將網路邏輯移至獨立服務,前端透過 HTTP/API 呼叫

此模式解決了舊版 Web 專案 (IE/HTA/HTC) 的並發下載限制,現代開發建議採用上述替代架構。

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