我正在从不同的语言调用 c# dll 非托管方法。我设置了回调,所以当 c# dll 完成时,我的应用程序会通过它获得结果。
这会在 .Invoke 上导致 SEHException:
public static async Task<IList<Models.ValueSet>> Fetch2(Uri uri)
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new HttpClient();
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var references = JsonConvert.DeserializeObject<ValueSetReference[]>(content);
var fetchTasks = references
.Select( async x =>
{
var perValueSetResponse = await client.GetAsync(new Uri(uri, $"{x.Hash}/"));
perValueSetResponse.EnsureSuccessStatusCode();
var perValueSetContent = await perValueSetResponse.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Models.ValueSet>(perValueSetContent);
});
return await Task.WhenAll(fetchTasks);
}
这不会:
public static async Task<IList<Models.ValueSet>> Fetch(Uri uri)
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new HttpClient();
var response = client.GetAsync(uri).Result;
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var references = JsonConvert.DeserializeObject<ValueSetReference[]>(content);
var fetchTasks = references
.Select( async x =>
{
var perValueSetResponse = client.GetAsync(new Uri(uri, $"{x.Hash}/")).Result;
perValueSetResponse.EnsureSuccessStatusCode();
var perValueSetContent = await perValueSetResponse.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Models.ValueSet>(perValueSetContent);
});
return await Task.WhenAll(fetchTasks);
}
这是 Invoke 上发生的异常:
{
"ClassName": "System.Runtime.InteropServices.SEHException",
"Message": "External component has thrown an exception.",
"Data": null,
"InnerException": null,
"HelpURL": null,
"StackTraceString": " at EUDCC.Verifier.<VerifyAsync>d__4.MoveNext()",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "8\nMoveNext\neudcc-verifier.lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\nEUDCC.Verifier+<VerifyAsync>d__4\nVoid MoveNext()",
"HResult": -2147467259,
"Source": "eudcc-verifier.lib",
"WatsonBuckets": null
}
这是 c# dll 的全部主要代码:
using EUDCC.Configuration;
using EUDCC.Models;
using EUDCC.Rules;
using EUDCC.Services;
using EUDCC.TrustList;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using net.r_eg.DllExport;
using System.Diagnostics;
using System.Threading;
namespace EUDCC
{
public static class Verifier
{
static string result { get; set; }
[DllExport(CallingConvention = CallingConvention.StdCall, ExportName = "GetResult")]
[return: MarshalAs(UnmanagedType.BStr)]
public static string GetResult()
{
return result;
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void QRVerifyResult([MarshalAs(UnmanagedType.BStr)] string result);
private static QRVerifyResult dQRVerifyResult;
[DllExport(CallingConvention = CallingConvention.StdCall, ExportName = "SetQRVerifyResultCallback")]
public static void SetQRVerifyResultCallback(int funcAddr)
{
IntPtr cbPtr = new IntPtr(funcAddr);
dQRVerifyResult = (QRVerifyResult)Marshal.GetDelegateForFunctionPointer(cbPtr, typeof(QRVerifyResult));
}
public static async void VerifyAsync(string qrCode, string TrustListUri, string ValueSetUri, string RuleSetUri)
{
var sc = SynchronizationContext.Current;
Task<VerificationReport> t = Verify(qrCode, TrustListUri, ValueSetUri, RuleSetUri);
var verReport = await t;
result = JsonConvert.SerializeObject(verReport);
Trace.WriteLine("Result that INVOKE will send: " + result);
SynchronizationContext.SetSynchronizationContext(sc);
try
{
dQRVerifyResult?.Invoke(result);
}
catch (Exception ex)
{
Trace.WriteLine("Invoke Failed: " + ex.Message+" "+ex.GetBaseException());
}
Trace.WriteLine("VerifySync: Invoking done");
}
[DllExport(CallingConvention = CallingConvention.StdCall, ExportName = "QRVerify")]
public static void DoVerify([MarshalAs(UnmanagedType.BStr)] string qrCode,
[MarshalAs(UnmanagedType.BStr)] string TrustListUri,
[MarshalAs(UnmanagedType.BStr)] string ValueSetUri,
[MarshalAs(UnmanagedType.BStr)] string RuleSetUri)
{
Trace.WriteLine("****************** START *******************");
Trace.WriteLine("DoVerify called from CW, before VerifyAsync called");
try
{
VerifyAsync(qrCode, TrustListUri, ValueSetUri, RuleSetUri);
}
catch (Exception ex)
{
Trace.WriteLine("VerifyAsyncFailed: " + ex.Message);
}
Trace.WriteLine("VerifyAsync Done, DoVerify from CW Done");
}
public static async Task<VerificationReport> Verify([MarshalAs(UnmanagedType.BStr)] string qrCode,
[MarshalAs(UnmanagedType.BStr)] string TrustListUri,
[MarshalAs(UnmanagedType.BStr)] string ValueSetUri,
[MarshalAs(UnmanagedType.BStr)] string RuleSetUri)
{
Trace.WriteLine("Verify procedure called");
_ = new Settings(
trustListUri: new Uri(TrustListUri),
valueSetUri: new Uri(ValueSetUri),
rulesetUri: new Uri(RuleSetUri));
DccCertificate dccCertificate;
bool signatureVerified = false;
var errorMessage = string.Empty;
try
{
dccCertificate = DccCertificateDecoder.Decode(qrCode);
}
catch (Exception ex)
{
Trace.WriteLine("exception VerificationReport called");
errorMessage = $"Unable to decode the QR Code to a valid EU DCC certificate. Error encountered is: {ex.Message}";
return new VerificationReport(signatureVerified, null, null, errorMessage, null);
}
try
{
var signatureCertificate = await TrustListRepository.GetByKid(dccCertificate.SignatureData.Kid);
signatureVerified = SignatureVerifier.Verify(signatureCertificate, dccCertificate);
Trace.WriteLine("back from .Verify");
}
catch (Exception ex)
{
Trace.WriteLine("exception signatureVerified called");
errorMessage = $"DCC certificate was decoded successfully, but verifying certificate signature failed. Error encountered is: {ex.Message}, " + ex.InnerException.Message;
//return new VerificationReport(signatureVerified, null, null, errorMessage, null);
}
if (dccCertificate.MetaData.ExpiringDate < DateTimeOffset.UtcNow)
{
Trace.WriteLine("ErrorMessage called");
errorMessage = "Certificate has expired.";
Trace.WriteLine("Return Verify ExpiringDate");
return new VerificationReport(signatureVerified, dccCertificate.HealthCertificate, dccCertificate.MetaData, errorMessage, null);
}
else
{
Trace.WriteLine("ExpiringDate checked");
}
var healthCertificateJson = JsonConvert.SerializeObject(dccCertificate.HealthCertificate);
var rawHealthCertificate = JsonConvert.DeserializeObject<HealthCertificateRaw>(healthCertificateJson);
var invalidRules = await RuleEngine.Run(rawHealthCertificate, Settings.ValueSetUri, Settings.RulesetUri, Settings.AppName);
if (invalidRules.Any())
{
errorMessage = "Some validation rules are invalid.";
Trace.WriteLine("We got invalid rules");
}
Trace.WriteLine("Just before Verify return");
return new VerificationReport(signatureVerified, dccCertificate.HealthCertificate, dccCertificate.MetaData, errorMessage, invalidRules);
}
}
}
Clarion 中用于调用 c# dll 的原型:
module('eudcc-verifier.dll')
QRVerify(bstring,bstring,bstring,bstring), name('QRVerify'), pascal,raw,dll(true)
SetQRVerifyResultcallback(long),pascal,raw,dll(true)
GetResult(),bstring, pascal, raw, dll(true)
end
QRVerifyResult(bstring result), PASCAL
来电:
qrcodebstr=clip(qrcode)
trustlistbstr='https://...'
ValueSetBstr='https://...'
RuleSetbstr='...'
SetQRVerifyResultCallback(ADDRESS(QRVerifyResult))
QRVerify(qrcodebstr,trustlistbstr,ValueSetBstr,RuleSetbstr)
Clarion 中的回调过程(由 C# 中的 Invoke 回调):
QRVerifyResult PROCEDURE(bstring result)
CODE
message(result)
return
我不精通C#,但为什么会这样?有没有等待客户仍然有效的解决方法?我更喜欢我的应用程序在 c# dll 下载文件时保持响应。在没有“等待”客户端的情况下,我的应用程序在下载时锁定...
谢谢你。