You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Visual FoxPro调用.NET DLL异步方法遇类型初始化异常求助

Visual FoxPro调用.NET异步DLL的类型初始化异常解决

问题场景

使用Visual FoxPro(VFP)调用.NET DLL的异步方法时,执行到client.PostAsync代码行时抛出异常:

An exception occurred in the log type type initializer

VFP调用代码

n=0
ON ERROR n=1
x = createobject("Business_Bancos.ApiKhipu_Bancos")
if n=0
   ON error
    &&respuesta=x.prueba()
    respuesta=x.obtienerespuestakhipu(tipobanco, host, userNamebd, dataBase, puerto, passworddb, valor_banco, UserName, Password, EnterpriseIdentity, Role, Agreement, accountNumber, BookingDateStart, BookingDateEnd)
    result=respuesta.datos
else
   messagebox("Error....!!",16,"Aviso")
ENDIF

.NET DLL关键代码

public async Task<Respuesta> obtienerespuestakhipu(string tipobanco,
        string host,
        string user,
        string dataBase,
        string puerto,
        string passworddb,
        string codigobanco,
        string UserName,
        string Password,
        string EnterpriseIdentity,
        string Role,
        string Agreement,
        string accountNumber,
        string BookingDateStart,
        string BookingDateEnd)
{
    string url_acount = "";
    string api_key = "";
    Clase_Conexion conexion = new Clase_Conexion(host, user, dataBase, puerto, passworddb);
    string respuesta = "";
    Respuesta resp = new Respuesta(); 
    url_acount = await ObtieneAccountLink_BancoPersonal(api_key, UserName, Password, urlbanco_accountlink);
                     
}

public async Task<string> ObtieneAccountLink_BancoPersonal(string api_key, string UserName, string Password, string urlbanco)
{
    string accountLink = "";
    var serviceCollection = new ServiceCollection();
    Configuere(serviceCollection);
    var servicios = serviceCollection.BuildServiceProvider();
    var httpClientFactory = servicios.GetRequiredService<IHttpClientFactory>();
    var client = httpClientFactory.CreateClient();
    client.DefaultRequestHeaders.Add("x-api-key", api_key);

    String str_json = "{\"Username\":'" + UserName + "',\"Password\":'" + Password + "'}";
    JObject json = JObject.Parse(str_json);
    MessageBox.Show(urlbanco);
    var postData = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
    //程序在此处崩溃
    var request = await client.PostAsync(urlbanco, postData);

    // 后续代码省略
}

问题原因

  1. VFP不支持异步Task调用:VFP作为传统COM宿主,无法正确处理.NET的异步Task返回类型,调用异步方法会导致上下文混乱,触发未预期异常。
  2. HttpClientFactory在COM环境下的初始化问题:IHttpClientFactory依赖的DI容器和日志组件在非托管的VFP宿主环境中,可能出现类型初始化失败(报错中的“log type type initializer”指向日志组件初始化异常)。
  3. 异步方法的上下文切换:await关键字会导致线程上下文切换,而VFP的单线程模型无法兼容这种切换,进而引发异常。

解决方法

方法1:将异步方法改为同步实现

修改.NET端代码,去掉异步逻辑,改用同步HttpClient调用,避免VFP处理异步类型:

// 对外暴露给VFP的同步方法
public Respuesta obtienerespuestakhipu(string tipobanco,
        string host,
        string user,
        string dataBase,
        string puerto,
        string passworddb,
        string codigobanco,
        string UserName,
        string Password,
        string EnterpriseIdentity,
        string Role,
        string Agreement,
        string accountNumber,
        string BookingDateStart,
        string BookingDateEnd)
{
    string url_acount = "";
    string api_key = "";
    Clase_Conexion conexion = new Clase_Conexion(host, user, dataBase, puerto, passworddb);
    Respuesta resp = new Respuesta(); 
    // 调用同步版本的HTTP请求方法
    url_acount = ObtieneAccountLink_BancoPersonal_Sync(api_key, UserName, Password, urlbanco_accountlink);
    // 补充后续业务逻辑
    return resp;
}

// 同步版本的HTTP请求实现
public string ObtieneAccountLink_BancoPersonal_Sync(string api_key, string UserName, string Password, string urlbanco)
{
    string accountLink = "";
    // 直接使用HttpClient,避免依赖IHttpClientFactory的DI容器
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("x-api-key", api_key);
        // 用序列化替代字符串拼接JSON,避免格式错误
        var jsonObj = new { Username = UserName, Password = Password };
        string jsonStr = JsonConvert.SerializeObject(jsonObj);
        var postData = new StringContent(jsonStr, Encoding.UTF8, "application/json");
        
        // 同步执行POST请求
        var response = client.PostAsync(urlbanco, postData).GetAwaiter().GetResult();
        if (response.IsSuccessStatusCode)
        {
            accountLink = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
        }
    }
    return accountLink;
}

方法2:封装异步方法的同步兼容层

如果必须保留异步逻辑,在.NET端封装同步包装方法,阻塞等待异步任务完成,同时移除日志相关配置避免初始化异常:

// 对外暴露给VFP的同步包装方法
public Respuesta obtienerespuestakhipu_Sync(string tipobanco, /* 完整参数列表 */)
{
    // 阻塞等待异步任务完成,返回VFP可识别的同步结果
    return obtienerespuestakhipu(tipobanco, /* 完整参数列表 */).GetAwaiter().GetResult();
}

// 修改异步方法中的HttpClient初始化,移除IHttpClientFactory依赖
public async Task<string> ObtieneAccountLink_BancoPersonal(string api_key, string UserName, string Password, string urlbanco)
{
    string accountLink = "";
    // 直接使用HttpClient替代IHttpClientFactory
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("x-api-key", api_key);
        var jsonObj = new { Username = UserName, Password = Password };
        string jsonStr = JsonConvert.SerializeObject(jsonObj);
        var postData = new StringContent(jsonStr, Encoding.UTF8, "application/json");
        
        var request = await client.PostAsync(urlbanco, postData);
        // 后续逻辑
    }
    return accountLink;
}

方法3:确保DLL的COM环境兼容

  • 编译.NET DLL时选择**.NET Framework**(而非.NET Core/.NET 5+),VFP对.NET Framework的COM支持更稳定。
  • 勾选项目属性中的“使程序集COM可见”,使用32位版本的regasm.exe(路径示例:C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe)注册DLL,匹配VFP的32位运行环境。
  • 检查DLL的所有依赖组件,确保在VFP运行环境中能正常加载。

内容的提问来源于stack exchange,提问作者Carmen Cisterna Chamblas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:24:56