Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从.NET Core调用VISA API时出错_C#_.net Core_Visa Api - Fatal编程技术网

C# 从.NET Core调用VISA API时出错

C# 从.NET Core调用VISA API时出错,c#,.net-core,visa-api,C#,.net Core,Visa Api,我试图从.NET Core向VISA api发出GET请求,在WebException中收到以下错误消息 提供给程序包的凭据未被visa国际组织识别 VISA API支持双向SSL连接,为此,VISA将颁发一组私钥和证书以及一对用户ID和密码 根据VISA文档,我使用以下命令创建了一个p12证书文件 openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" -certfile cert.pem -out myProject_

我试图从.NET Core向VISA api发出GET请求,在WebException中收到以下错误消息

提供给程序包的凭据未被visa国际组织识别

VISA API支持双向SSL连接,为此,VISA将颁发一组私钥和证书以及一对用户ID和密码

根据VISA文档,我使用以下命令创建了一个p12证书文件

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" 
    -certfile cert.pem -out myProject_keyAndCertBundle.p12
然后,我编写了以下代码向VISA API发出请求。我将此代码作为.NET核心控制台应用程序的一部分运行

public string MakeHelloWorldCall()
{
    string requestURL = "https://sandbox.api.visa.com/vdp/helloworld";

    string userId = ConfigurationManager.AppSettings["userId"];
    string password = ConfigurationManager.AppSettings["password"];
    string certificatePath = ConfigurationManager.AppSettings["cert"];
    string certificatePassword = ConfigurationManager.AppSettings["certPassword"];
    string statusCode = "";

    HttpWebRequest request = WebRequest.Create(requestURL) as HttpWebRequest;
    request.Method = "GET";

    request.Headers["Authorization"] = GetBasicAuthHeader(userId, password);

    var certificate = new X509Certificate2(certificatePath, certificatePassword);
    request.ClientCertificates.Add(certificate);

    try
    {
        // Make the call
        // This is the line which throws the exception.
        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            statusCode = response.StatusCode.ToString();
        }
    }
    catch (WebException e)
    {
        Console.WriteLine(e.Message);
        Exception ex = e.InnerException;

        while(ex != null)
        {
            Console.WriteLine(ex.Message);
            ex = ex.InnerException;
        }

        if (e.Response is HttpWebResponse)
        {
            HttpWebResponse response = (HttpWebResponse)e.Response;
            statusCode = response.StatusCode.ToString();
        }
    }

    return statusCode;
}

private string GetBasicAuthHeader(string userId, string password)
{
    string authString = userId + ":" + password;
    var authStringBytes = Encoding.UTF8.GetBytes(authString);
    string authHeaderString = Convert.ToBase64String(authStringBytes);
    return "Basic " + authHeaderString;
}
我在控制台中看到以下输出

The SSL connection could not be established, see inner exception. The credentials supplied to the package were not recognized
The SSL connection could not be established, see inner exception.
The credentials supplied to the package were not recognized
因此,根错误是无法识别提供给包的凭据

我几乎被困在这里,因为我不确定是什么导致了这个错误

我试着在谷歌上搜索这个错误等等。但大多数帖子怀疑访问证书的权限不足。但是我使用管理员用户帐户运行Visual Studio,并且我使用的是证书文件,而不是计算机上安装的证书

我想任何有双向SSL连接和/或VISA API经验的人都能够理解此错误背后的确切原因

编辑:我能够从配置相同的SOAP UI成功调用API。p12证书和授权头。

是否使用完整的IIS? 确保应用程序池有权访问此文件

但是调试你无法访问的东西是很困难的


最后,我终于解决了这个问题

我做了两件事来达成决议

使用HttpClient而不是HttpWebRequest发出API请求。多亏了@Fred。 我没有使用证书文件,而是在当前用户证书存储下的计算机上安装了证书。 以下是工作代码

public string MakeHelloWorldCallUsingHttpClient()
{
    string requestURL = "https://sandbox.api.visa.com/vdp/helloworld";

    string userId = ConfigurationManager.AppSettings["userId"];
    string password = ConfigurationManager.AppSettings["password"];
    string apiResponse = "";

    HttpClientHandler clientHandler = new HttpClientHandler();

    HttpClient httpClient = new HttpClient(clientHandler);
    httpClient.DefaultRequestHeaders.Authorization 
            = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", GetBasicAuthHeaderValue(userId, password));
    try
    {
        // Make the call
        var response = httpClient.GetAsync(requestURL).Result;

        if (response.StatusCode == HttpStatusCode.OK)
        {
            apiResponse = response.Content.ReadAsStringAsync().Result;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        Exception ex = e.InnerException;
        while (ex != null)
        {
            Console.WriteLine(ex.Message);
            ex = ex.InnerException;
        }
    }
    return apiResponse;
}

private string GetBasicAuthHeaderValue(string userId, string password)
{
    string authString = userId + ":" + password;
    var authStringBytes = Encoding.UTF8.GetBytes(authString);
    return Convert.ToBase64String(authStringBytes);
}
下面是我现在从API获得的输出

{"timestamp":"2019-07-01T14:02:22","message":"helloworld"}
下面的代码行确保从当前用户的证书存储中找到客户端证书

clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
将上述ClientCertificateOptions设置为ClientCertificateOptions.Manual将要求将证书手动添加到clientHandler.ClientCertificates,如下所示

var certificate = new X509Certificate2(certificatePath, certificatePassword);
clientHandler.ClientCertificates.Add(certificate);
这将导致与我目前面临的错误相同的错误


这使我认为让框架定位客户端证书是最有利的。我遇到了同样的问题,最终找到了在Visa社区开发者网站上发布解决方案的人

解决方案的要点是使用C而不是使用此命令生成密钥

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" -certfile cert.pem -out myProject_keyAndCertBundle.p12
您应该解压缩-certfile参数并使用以下命令

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" -out myProject_keyAndCertBundle.p12 

在我的C项目中,这解决了我的问题,我仍然能够从文件中加载密钥,而不使用证书存储。

Protip:你应该使用HttpClient而不是WebRequest。谢谢@Fred。。。让我试试…@Fred我也试过HttpClient。。。但这并没有解决问题。我仍然收到与提供给包的凭据不一致的错误recognized@FredHttpClient是个好主意。。我能够用HttpClient解决这个问题,还有一个改变……不,我没有使用IIS。我正在使用控制台应用程序。。。。我不会在我的应用程序中从IIS调用VISA API。它将来自后台服务…既然您使用了HttpClient,就不应该再使用catch WebException了。您不应该捕捉基本异常,这是一种不好的做法。您应该捕获一个更具体的异常类。可能是HttpRequestException。我必须将协议设置为也使用TLS1.2。ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls12;
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;