Код C # ниже, который входит на веб-сайт,
- Работает при вызове на компьютере A из Excel 2010 VBA через com-interop
- Работает при вызове на компьютере Bиз консольного приложения C #, но
- Сбой при вызове на компьютер B из Excel 2010 VBA через com-interop
Основное различие между компьютером A и компьютером B состоит в том, что компьютер A имеетWindows 10 версии 1803, тогда как компьютер B имеет Windows 10 версии 1809. Оба компьютера имеют Studio 2017, и во всех случаях целевой .Net Framework является 4.6.2.
using System;
using System.Runtime.InteropServices;
using System.IO;
[Guid("97E1D9DB-8478-4E56-9D6D-26D8EF13B100")]
[ComVisible(true)]
public interface IToExcel {
string Do();
}
[Guid("BBF87E31-77E2-46B6-8093-1689A144BFC6")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Main : IToExcel {
private const string XAPP_ID = "...";
private const string USERNAME = "...";
private const string PASSWORD = "...";
private const string CERT_FILE = @"...";
private const string CERT_PASSWORD = "...";
private const string WEBSITE = "https:// ...";
public string Do() {
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(new Uri(WEBSITE));
request.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
request.Method = "POST";
request.Accept = "application/json";
request.Timeout = request.ReadWriteTimeout = 20000;
request.ContentType = "application/x-www-form-urlencoded";
request.UseDefaultCredentials = true;
request.Proxy = null;
// setup headers
System.Net.WebHeaderCollection whc = new System.Net.WebHeaderCollection {
{ "X-Application", XAPP_ID },
{ System.Net.HttpRequestHeader.AcceptCharset, "utf-8" },
{ System.Net.HttpRequestHeader.AcceptEncoding, "gzip,deflate" }
};
request.Headers.Add(whc);
// setup certificate
System.Security.Cryptography.X509Certificates.X509Certificate2 m_x509certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(CERT_FILE, CERT_PASSWORD);
request.ClientCertificates.Add(m_x509certificate);
// do call
using (Stream stream = request.GetRequestStream()) {
using (StreamWriter writer = new StreamWriter(stream, System.Text.Encoding.Default)) {
writer.Write("username=" + USERNAME + "&password=" + PASSWORD);
}
}
string responseData = string.Empty;
using (System.Net.WebResponse response = request.GetResponse()) {
using (Stream responseStream = response.GetResponseStream()) {
using (StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8)) {
responseData = reader.ReadToEnd();
}
}
}
return responseData;
}
}
Во всех случаях возвращается небольшой объект JSON, где у объекта JSON есть поле с именем loginStatus.Когда это работает, "loginStatus" = "УСПЕХ", но когда это не удается "loginStatus" = "CERT_AUTH_REQUIRED".
Я пытался просмотреть все настройки в System.Net.ServicePointManager, но во всех случаях настройки былито же самое:
- ReusePort: False
- ServerCertificateValidationCallback:
- DnsRefreshTimeout: 120000
- EnableDnsRoundRobin: False
- Expect100Продолжить: True
- UseNagleAlgorithm: True
- MaxServicePointIdleTime: 100000
- DefaultConnectionLimit: 2
- MaxServicePoints: 0
- Протокол безопасности: Tls, Tls11, Tls12
- CheckCertificateRevocationList: False
- EncryptionPolicy: RequireEncryption
Кроме того, я не знаю, что еще проверить.Обновление с .Net 4.6.2 до 4.7.1 не дало никакого эффекта, результаты были такими же.
Я задавался вопросом, является ли это ошибкой в Windows 1809, но так как она работает при вызове непосредственно в .Netконсольное приложение, я полагаю, это небольшая проблема конфигурации.Может ли кто-нибудь помочь мне получить эту работу из Excel 2010 на компьютере B?
Обновление 8 февраля 2019
Как указано в комментариях, я использовал Fiddler для просмотраструктура вызовов https, которые совершаются на веб-сайт.Два из них работают одинаково, а тот, который не работает, выглядит немного иначе:
Вызовы, которые работают, OK
- Расширение TLS ec_point_formats = uncompressed [0x0]
- TLSРасширение encrypt_then_mac (RFC7366) не указано
- Расширение TLS renegotiation_info = 0
- Шифр TLS_EMPTY_RENEGOTIATION_INFO_SCSV не указано
Ошибка вызова
- ec_point_formats = несжатый [0x0], ansiX962_compressed_prime [0x1], ansiX962_compressed_char2 [0x2]
Но теперь у меня есть эта информация, я не уверен, поможет ли она.Возможно, что работающие вызовы генерируются одним и тем же кодом низкого уровня (несмотря на то, что они выполняются в разных версиях Windows 10), а сбойный вызов генерируется другим кодом низкого уровня.
Обновление 10 февраля 2019
При вызове из Excel через com-interop я заставил код выполнять EXE в новом домене приложений вместо прямого вызова кода входа.И когда я это сделал, EXE-файл не работал и выдал тот же вывод, как если бы я вызывал код входа в систему напрямую.
Ниже представлено окно вывода Visual Studio, в котором показан порядок, в котором находятся библиотеки DLL.загружается при запуске EXE-файла, непосредственно перед выполнением кода входа.Самое большое различие между успешными сценариями и неудачным сценарием заключается в том, что неудачный сценарий никогда не загружает C: \ Windows \ System32 \ ncryptprov.dll.Кто-нибудь знает, что вызывает загрузку этой DLL?
…
(Win32): загружен 'C: \ Windows \ System32 \ msisip.dll'
(Win32): Загружено 'C: \ Windows \ System32 \ coml2.dll' --- ЗАГРУЖЕНО РАНЬШЕ ИЗ EXCEL
(Win32): загружено 'C: \ Windows \ System32 \ wshext.dll'
(Win32): загружено 'C: \ Windows \ System32 \ AppxSip.dll'
(Win32): загружено 'C: \ Windows \ System32 \ tdh.dll'
(Win32)): Загружено 'C: \ Windows \ System32 \ xmllite.dll'
(Win32): загружено 'C: \ Windows \ System32 \ OpcServices.dll'
(Win32): загружено 'C: \ Windows \ System32 \ mintdh.dll '
(Win32): загружено' C: \ Windows \ System32 \ urlmon.dll '--- ЗАГРУЗЕНО РАНЬШЕ ИЗ EXCEL
(Win32): Загружено 'C: \ Windows \ System32 \ mintdh.dll'
(Win32): выгружено 'C: \ Windows \ System32 \ mintdh.dll'
(Win32): загружено 'C: \ Windows \ System32 \ iertutil.dll '--- ЗАГРУЖЕННЫЙ РАНЬШЕ ИЗ EXCEL
(Win32): Загружен' C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ pwrshsip.dll '
(Win32): загружен 'C: \ Windows \ System32 \ EsdSip.dll'
(Win32): загружен 'C: \ Windows \ System32 \ userenv.dll' --- ЗАГРУЗЕН РАНЬШЕ ИЗ EXCEL
(Win32): загружено 'C: \ Windows \ System32 \ dpapi.dll'
(Win32): загружено 'C: \ Windows \ System32 \ dnsapi.dll'
(Win32): загружен 'C:\ Windows \ System32 \ rasadhlp.dll '
(Win32): загружен' C: \ Windows \ System32 \ FWPUCLNT.DLL '
(Win32): загружен' C: \ Windows \ System32\ secur32.dll '
(Win32): загружено' C: \ Windows \ System32 \ sspicli.dll '--- ЗАГРУЖЕНО РАНЬШЕ ИЗ EXCEL
(Win32): загружено' C: \Windows \ System32 \ schannel.dll '
(Win32): загружен' C: \ Windows \ System32 \ mskeyprotect.dll '
(Win32): загружен' C: \ Windows \ System32 \ncrypt.dll '
(Win32): загружен' C: \ Windows \ System32 \ ntasn1.dll '
(Win32): загружен' C: \ Windows \ System32 \ ncryptprov.dll '--- НИКОГДА НЕ ЗАГРУЖАЕТСЯ ИЗ EXCEL
(Win32): загружен 'C: \ Windows \ System32 \ ncryptsslp.dll'
На этом этапе код C # выполняется
Обновление 12 февраля 2019 года
Большое спасибо Саймону Мурье за то, что он рассказал мне, как настроить диагностику System.Net.При выполнении диагностики на компьютере B строки «Информация о System.Net», которые получают выходные данные для двух случаев, начинаются одинаково, но в конечном итоге есть разница.Это вывод из файла Console EXE на компьютере B (т. Е. Случай, который работает):
System.Net Information: 0 : [35268] Current OS installation type is 'Client'.
System.Net Information: 0 : [35268] RAS supported: True
System.Net Information: 0 : [35268] Associating HttpWebRequest#21454193 with ServicePoint#34640832
System.Net Information: 0 : [35268] Associating Connection#43332040 with HttpWebRequest#21454193
System.Net Information: 0 : [35268] Connection#43332040 - Created connection from XXX.XXX.XXX.XXX:53002 to YYY.YYY.YYY.YYY:443.
System.Net Information: 0 : [35268] TlsStream#54444047::.ctor(host=<TargetWebSite>, #certs=1, checkCertificateRevocationList=False, sslProtocols=Tls12)
System.Net Information: 0 : [35268] Associating HttpWebRequest#21454193 with ConnectStream#20234383
System.Net Information: 0 : [35268] HttpWebRequest#21454193 - Request: POST /api/certlogin HTTP/1.1
System.Net Information: 0 : [35268] ConnectStream#20234383 - Sending headers
System.Net Information: 0 : [35268] SecureChannel#47891719::.ctor(hostname=<TargetWebSite>, #clientCertificates=1, encryptionPolicy=RequireEncryption)
System.Net Information: 0 : [35268] Enumerating security packages:
System.Net Information: 0 : [35268] Negotiate
System.Net Information: 0 : [35268] NegoExtender
System.Net Information: 0 : [35268] Kerberos
System.Net Information: 0 : [35268] NTLM
System.Net Information: 0 : [35268] TSSSP
System.Net Information: 0 : [35268] pku2u
System.Net Information: 0 : [35268] CloudAP
System.Net Information: 0 : [35268] WDigest
System.Net Information: 0 : [35268] Schannel
System.Net Information: 0 : [35268] Microsoft Unified Security Protocol Provider
System.Net Information: 0 : [35268] Default TLS SSP
System.Net Information: 0 : [35268] CREDSSP
System.Net Information: 0 : [35268] SecureChannel#47891719 - Attempting to restart the session using the user-provided certificate: [Version]
System.Net Information: 0 : [35268] SecureChannel#47891719 - Left with 1 client certificates to choose from.
System.Net Information: 0 : [35268] SecureChannel#47891719 - Trying to find a matching certificate in the certificate store.
System.Net Information: 0 : [35268] SecureChannel#47891719 - Locating the private key for the certificate: [Version]
System.Net Information: 0 : [35268] SecureChannel#47891719 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [35268] SecureChannel#47891719::.AcquireClientCredentials, new SecureCredential() (flags=(ValidateManual, NoDefaultCred, SendAuxRecord, UseStrongCrypto), m_ProtocolFlags=(Tls12Client), m_EncryptionPolicy=RequireEncryption)
System.Net Information: 0 : [35268] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Information: 0 : [35268] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [35268] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=184, returned code=ContinueNeeded).
System.Net Information: 0 : [35268] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 227c85a89b0:2449d0deff0, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [35268] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=CredentialsNeeded).
Однако при запуске из Excel 2010 через com-interop вместо последних 4 строк InitializeSecurityContext6 строк InitializeSecurityContext выглядят следующим образом:
System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=184, returned code=ContinueNeeded).
System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 8a8e2f0:2449d0def90, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 8a8e2f0:2449d0def90, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
Первые две строки InitializeSecurityContext идентичны, поэтому, по-видимому, принципиальное различие заключается в третьей строке InitializeSecurityContext, где консоль EXE-файла имеет
context = 227c85a89b0: 2449d0deff0
но неудачный запуск через executino com-interop имеет
context = 8a8e2f0: 2449d0def90
После этого все выглядит не так, как можно было бы ожидать,Кто-нибудь знает, что означает эта разница и как ее устранить, чтобы выполнение com-interop осуществлялось так же, как выполнение com-interop?
Обновление 13 февраля 2019 г.
Я разместил больше результатов диагностики на форуме MSDN .