【问题标题】:sharing class variable between async method and normal return method在异步方法和正常返回方法之间共享类变量
【发布时间】:2017-02-06 16:20:05
【问题描述】:

这是我的课,有异步方法和获取方法

class Webservice
{
    public string token;
    public async void login (string url)
    {
        Console.WriteLine(url);
        var client = new HttpClient();

        // Create the HttpContent for the form to be posted.
        string username = ConfigurationSettings.AppSettings["email"];
        string password = ConfigurationSettings.AppSettings["password"];

        var requestContent = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string, string>("email", username),
                new KeyValuePair<string, string>("password", password),
        });

        // Get the response.
        HttpResponseMessage response = await client.PostAsync(url, requestContent);

        // Get the response content.
        HttpContent responseContent = response.Content;

        // Get the stream of the content.
        using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
        {
            // Write the output.
            //Console.WriteLine(await reader.ReadToEndAsync());
            token = await reader.ReadToEndAsync();

        }
    }


    public string getToken (string url)
    {
        this.login(url);
        Console.WriteLine(token);
        return token+"abc";
    }

令牌 = 等待 reader.ReadToEndAsync();无法设置类变量,或者getToken返回后设置,有人知道如何处理这种情况吗?

【问题讨论】:

  • 不要使用async void,这是不好的做法,使用async Task。我想你想让token 静态,所以public static string token;。我猜,因为你没有说你得到什么错误信息或它发生在哪里......
  • 为什么登录是异步的?如我所见,您希望在登录后立即获得结果。
  • async void 仅用于事件处理程序。不能等待,这意味着您无法知道该方法是否已完成。 而不是设置字段(这是非常糟糕的做法)将签名更改为async Task&lt;string&gt; 并返回令牌。然后你可以很容易地写var token=await login(url);并用它做任何你想做的事情

标签: c# winforms asynchronous


【解决方案1】:

通过调用:

this.login(url);

您正在触发并忘记了异步调用。

您需要使包含函数异步并等待login 调用完成

public async Task<string> getToken (string url)
{
    await this.login(url);
    Console.WriteLine(token);
    return token+"abc";
}

不要使用this.login(url).Wait()

终于

public async void login (string url)

async void 用于事件处理程序,应该是这样的:

public async Task login (string url)

恕我直言

我相信这个类有太多的责任。它不应该用于检索和存储令牌。有人会假设您的应用程序中有某种缓存层(它可能只是内存)。

因此,我更喜欢这样的逻辑:

if (string.IsNullOrWhiteSpace(this.cache[TOKEN_KEY])) {
   this.cache[TOKEN_KEY] = await this.webservice.login(url);
}

// use the this.cache[TOKEN_KEY] here...
await this.anotherService.MakeRequest(this.cache[TOKEN_KEY]);

cache 可能只是一个带有字典的单例类...

新的Task&lt;string&gt; login(string url) 方法现在将在底部返回令牌,而不仅仅是设置私有字段:

return await responseContent.ReadAsStringAsync();

如果需要,此逻辑将使您更容易在登录中和周围添加层,而不会使代码难以推理。

【讨论】:

  • 谢谢,但您知道如何获取任务 值吗?网络服务 ws = 新的网络服务(); Task token = ws.getToken("localhost/m1/m1apiserver/public/api/login"); Console.WriteLine(token); 它将返回“System.Threading.Tasks.Task`1[System.String]”
  • @hkguile 与您从ReadToEndAsync 获得结果的方式相同,您需要等待该功能。如果你打算使用 async/await,你需要整个调用堆栈一直使用它,直到框架调用你的代码的起点。
  • @hkguile 就像斯科特说的那样,string token = await ws.getToken(...)
  • @hkguile 您是从 winforms 中的按钮事件触发此登录请求吗?如果是这样,您需要使该事件异步:public async void Login_Button_Click(EventArgs e)
猜你喜欢
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 2011-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多