在 Visual Studio 中为 C# .NET 异步/等待请求指定本地主机端口

Specify Localhost Port for C# .NET Async / Await Requests in Visual Studio

我正在调试一个使用 Oauth2 凭据的控制台应用程序,服务提供商要求我指定一个重定向 URI。我在服务提供商的 Web 门户中指定重定向 URI。该服务是 Google 分析。

我已经使用 Node.js 应用程序成功测试了该服务。在服务的配置中,我指定了 http://localhost:8080 的重定向 URI。 Node 应用程序实际上默认在端口 8080 上启动,所以我可以简单地 运行 http-server,浏览到 http://localhost:8080,调用服务,然后查看带有数据的响应。

但是,当我尝试使用 C# 控制台应用程序调用同一服务时,我在浏览器中收到 HTTP 400 错误。错误状态:

The redirect URI in the request, http://localhost:59291/authorize/, does not match the ones authorized for the OAuth client.

每次我尝试 运行 应用程序时,端口都会改变。这是代码(引用自):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Google.Apis.AnalyticsReporting.v4;
using Google.Apis.AnalyticsReporting.v4.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System.Threading;

namespace Google_Analytics_API_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var credential = GetCredential().Result;
                using (var svc = new AnalyticsReportingService(
                    new BaseClientService.Initializer
                    {
                        HttpClientInitializer = credential,
                        ApplicationName = "Google Analytics API Console"
                    }))
                {
                    var dateRange = new DateRange
                    {
                        StartDate = "2017-04-24",
                        EndDate = "today"
                    };
                    var sessions = new Metric
                    {
                        Expression = "ga:sessions",
                        Alias = "Sessions"
                    };
                    var date = new Dimension { Name = "ga:date" };

                    var reportRequest = new ReportRequest
                    {
                        DateRanges = new List<DateRange> { dateRange },
                        Dimensions = new List<Dimension> { date },
                        Metrics = new List<Metric> { sessions },
                        ViewId = "<<viewID>>"
                    };

                    var getReportsRequest = new GetReportsRequest
                    {
                        ReportRequests = new List<ReportRequest> {    reportRequest }
                    };
                    var batchRequest =    svc.Reports.BatchGet(getReportsRequest);
                    var response = batchRequest.Execute();
                    foreach (var x in response.Reports.First().Data.Rows)
                    {
                        Console.WriteLine(string.Join(",", x.Dimensions) +
                            " " + string.Join(", ",    x.Metrics.First().Values));
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

            static async Task<UserCredential> GetCredential()
            {
                using (var stream = new FileStream("client_secret.json",
                    FileMode.Open, FileAccess.Read))
                {
                    const string loginEmailAddress = "<<emailAddress>>";
                return await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { AnalyticsReportingService.Scope.Analytics },
                    loginEmailAddress, CancellationToken.None,
                    new FileDataStore("GoogleAnalyticsApiConsole"));
                }
           }
       }
    }

我已经搜索了一种使用静态端口配置 IIS Express 以进行调试的方法,但我不确定此处是否涉及 IIS - 而不是像 TcpClient / TcpListener 对象那样由Google 分析库?

有没有办法在 C# .NET 控制台应用程序中为异步/等待请求指定端口?

显然,这里的问题是您的请求是通过 HttpClient 发出的; Google.Apis.Http.HttpClientfactory returns 这是通过 ConfigurableHttpClient 实现的。 HttpClient 没有向底层 ServicePoint 暴露方法来设置本地绑定的 IP 地址(更多信息在底部)

解决此问题的最佳方法是确保您以正确的方式使用凭据。由于您是从控制台应用程序连接的,因此您可以轻松地将这些凭据设置为其他,这实际上是首选方式。尝试查看 "Create Credentials" 按钮和 select 按钮 "Help Me Choose",它们可以指导您完成场景。否则,只需创建如下。

根据@panagiotis-kanavos的建议,我补充说明一下:

HttpClient does not expose access to ServicePoint. You could use reflection to access the underlying ServicePoint object. It may provide a resolution to your attempts to bind to a specifical local address if you do not want to use console API credentials withing Google API for Analytics

为此,请检查这个问题:

据我所知,BaseClientService 只允许您设置自定义 HttpFactory 或自定义 HttpClientInitializer(修改 post-create),因此您需要创建自定义 HttpFactory 实例返回ConfigurableHttpClient 修改如上。

  1. GoogleApi HttpClientFactory
  2. GoogleApi ConfigurableHttpClient

完成后,您将自定义 HttpClientFactory 传递给它。

 using (var svc = new AnalyticsReportingService(
     new BaseClientService.Initializer
 {
     HttpClientInitializer = credential,
     ApplicationName = "Google Analytics API Console",
     HttpClientFactory = new CustomHttpClientFactory()
 }))