【问题标题】:Getting a token from an external web API is returning system.threading.tasks从外部 Web API 获取令牌正在返回 system.threading.tasks
【发布时间】:2021-09-25 09:05:12
【问题描述】:

我成功地从我的GetAccessToken()GetAccessTokenAsync 方法中获取了一个令牌,但是直到GetCourses 的主要方法之后才检索到令牌,这将不起作用,因为这是收集的方法我需要在我的 cshtml 页面上显示的数据。我试过拆开这个控制器并创建一个只包含 URI、apiKey 和令牌的 Globals 类,但后来我读到这对MVC 来说是不好的做法,所以我放弃了这项工作。无论如何,它在GetCourses 方法之后被调用,所以它也是死路一条。

我是 MVC 的新手,来自 WebForms 背景,我习惯于在我的 PageInit 中抛出这种代码,但我正在努力弄清楚如何在 @987654328 中实现这一点@。有人可以帮我弄清楚我做错了什么,或者我是否需要以不同的方式解决这个问题?

    public ActionResult GetCourses()
    {
        TempData["EthosURI"] = "redacted";
        TempData["Token"] = GetAccessToken().ToString();

        IEnumerable<Course> courses = null;

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri((string)TempData["EthosURI"]);
            client.DefaultRequestHeaders.Add("Authorization", "Bearer {" + (string)TempData["Token"] + "}");
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //HTTP GET
            var responseTask = client.GetAsync("courses");
            responseTask.Wait();

            var result = responseTask.Result;
            if (result.IsSuccessStatusCode)
            {
                var readTask = result.Content.ReadAsAsync<IList<Course>>();
                readTask.Wait();

                courses = readTask.Result;
            }
            else //web api sent error response 
            {
                //log response status here..

                courses = Enumerable.Empty<Course>();
                ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
            }
        }
        return View(courses);
    }

    public static async Task<string> GetAccessToken()
    {
        var token = await GetAccessTokenAsync("redactedUrl", "redactedAPIKey");
        return token;
    }
    public static async Task<string> GetAccessTokenAsync(string ethosURI, string apiKey)
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(ethosURI);
            client.DefaultRequestHeaders.Accept.Clear();

            HttpRequestMessage request = new HttpRequestMessage
            {
                Method = HttpMethod.Post,
                RequestUri = new Uri(ethosURI)
            };
            request.Headers.Clear();
            request.Headers.Add("Authorization", $"Bearer {apiKey}");
            request.Headers.Add("Accept", "application/json");
            request.Headers.CacheControl = new CacheControlHeaderValue() { NoCache = true };

            var response = await client.SendAsync(request);
            response.EnsureSuccessStatusCode();

            return await response.Content.ReadAsStringAsync();
        }
    }

【问题讨论】:

  • 即使您没有使用 Async 对 GetAccessToken 进行后缀,它仍然是一种异步方法,因此您需要等待它完成。我还建议将您的签名更改为public async Task&lt;ActionResult&gt; GetCourses(),这样您就可以await 所有以TaskTask&lt;TResult&gt; 作为返回类型的调用。
  • 谢谢。我更改了GetCourses() 方法并且能够取回令牌。 :)

标签: c# asp.net asynchronous model-view-controller bearer-token


【解决方案1】:

C# 中等待任务完成的(非阻塞)方式是使用await 关键字。对于使用await 关键字的方法,它必须标记为async。通过使用await,您不仅可以等待任务完成,而且当前线程也不会被阻塞。将异步操作包装在另一种方法中不会使其同步。换句话说,异步特性会向上传播调用层次结构,调用者必须等待。所以,GetAccessToken() 仍然需要等待。控制器操作也可以标记为异步的,因此您可能想要:

public async Task<ActionResult> GetCourses()
{
    TempData["EthosURI"] = "redacted";
    TempData["Token"] =  (await GetAccessToken()).ToString(); // note the additional parentheses
   ....

在调用ToString() 之前,请注意上面的附加括号。但是,由于GetAccessToken() 已经返回了string,因此您不需要多余的ToString() 调用:

TempData["Token"] =  await GetAccessToken();

现在,你也可以改变这个:

var readTask = result.Content.ReadAsAsync<IList<Course>>();
readTask.Wait();
courses = readTask.Result;

只是:

courses = await result.Content.ReadAsAsync<IList<Course>>();

微软在异步编程方面有相当不错的documentation,我建议你去看看。

【讨论】:

  • 这很有帮助,非常感谢!那个额外的GetAccessToken 方法是我希望我能弄清楚如何在非异步方法中使用异步任务。我摆脱了它,现在只有GetCoursesGetAccessTokenAsync。我也非常感谢这个链接,我真的需要吸收这些东西,因为 API 现在已经放在我的盘子上了,而且不会去任何地方。
【解决方案2】:

这不是异步在 C# 中的工作方式。您需要制作GetCourses() async 并等待GetAccessToken(),或者使用肮脏的hack GetAccessToken().GetAwaiter().GetResult(),但在某些情况下它可能会变得不安全。

【讨论】:

  • 谢谢。我更改了GetCourses() 方法,现在能够取回令牌。 :)
猜你喜欢
  • 2017-05-25
  • 1970-01-01
  • 2017-05-20
  • 1970-01-01
  • 2016-02-04
  • 2012-08-05
  • 1970-01-01
  • 2017-02-09
  • 1970-01-01
相关资源
最近更新 更多