C# 在异步方法和正常返回方法之间共享类变量

C# 在异步方法和正常返回方法之间共享类变量,c#,winforms,asynchronous,C#,Winforms,Asynchronous,这是我的类,有一个异步方法和get方法 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.

这是我的类,有一个异步方法和get方法

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";
    }
类Web服务
{
公共字符串令牌;
公共异步无效登录(字符串url)
{
Console.WriteLine(url);
var client=新的HttpClient();
//为要发布的表单创建HttpContent。
字符串username=ConfigurationSettings.AppSettings[“email”];
字符串密码=配置设置。应用设置[“密码”];
var requestContent=newformurlencodedcontent(new[]{
新的KeyValuePair(“电子邮件”,用户名),
新的KeyValuePair(“密码”,password),
});
//得到回应。
HttpResponseMessage response=wait client.PostAsync(url,requestContent);
//获取响应内容。
HttpContent responseContent=response.Content;
//获取内容流。
使用(var reader=new StreamReader(wait responseContent.ReadAsStreamAsync()))
{
//写入输出。
//Console.WriteLine(wait reader.ReadToEndAsync());
token=wait reader.ReadToEndAsync();
}
}
公共字符串getToken(字符串url)
{
登录名(url);
控制台写入线(令牌);
返回令牌+“abc”;
}
token=wait reader.ReadToEndAsync();无法设置类变量,或者可能在返回getToken后设置,有人知道如何处理这种情况吗?

通过调用:

this.login(url);
您正在启动并忘记异步调用

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

public async Task<string> getToken (string url)
{
    await this.login(url);
    Console.WriteLine(token);
    return token+"abc";
}
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]);
缓存
可能只是一个带有字典的单例类

新的
任务登录(字符串url)
方法现在将返回底部的令牌,而不仅仅是设置私有字段:

return await responseContent.ReadAsStringAsync();
如果需要,此逻辑将使您更容易在登录中及其周围添加层,而不会使代码难以推理。

通过调用:

this.login(url);
您正在启动并忘记异步调用

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

public async Task<string> getToken (string url)
{
    await this.login(url);
    Console.WriteLine(token);
    return token+"abc";
}
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]);
缓存
可能只是一个带有字典的单例类

新的
任务登录(字符串url)
方法现在将返回底部的令牌,而不仅仅是设置私有字段:

return await responseContent.ReadAsStringAsync();

如果需要的话,这种逻辑将使您更容易在登录中及其周围添加层,而不会使代码难以解释。

不要使用
异步void
,这是一种不好的做法,使用
异步任务
。我想您希望使
令牌
成为静态的,所以
公共静态字符串令牌;
。我猜,because您还没有说您收到了什么错误消息或它发生在哪里…为什么登录是异步的?正如我所看到的,您希望在登录后立即得到结果。
async void
仅适用于事件处理程序。它不能等待,这意味着您根本无法知道该方法是否已完成。而不是设置字段(这是非常糟糕的做法)将签名更改为
async Task
并返回令牌。然后您可以轻松编写
var-token=wait-login(url)
并用它做任何你想做的事不要使用
异步无效
,这是一种不好的做法,使用
异步任务
。我想你想让
令牌
静态,所以
公共静态字符串令牌;
。我猜,因为你还没有说你得到了什么错误消息或者它发生在哪里……为什么登录是异步的?正如我看到的,你想登录后立即显示结果。
async void
仅适用于事件处理程序。不能等待它,这意味着您无法知道该方法是否已完成。而不是设置字段(这是一种非常糟糕的做法)将签名更改为
async Task
并返回令牌。然后您可以轻松编写
var-token=wait-login(url);
并使用iThanks执行任何操作,但您知道如何获取任务值吗?Webservice ws=new-Webservice();任务令牌=ws.getToken(“);Console.WriteLine(令牌);它将返回“System.Threading.Tasks.Task`1[System.String]“@hkguile与从
ReadToEndAsync
获得结果的方式相同,您需要等待函数。如果要使用async/await,则需要整个调用堆栈一直使用它,直到框架调用代码的起点为止。@hkguile就像Scott说的,
string-token=await-ws.getToken(…)
@hkguile您是否从winforms中的按钮事件触发此登录请求?如果是这样,您需要使该事件异步:
public async void login\u button\u单击(EventArgs e)
谢谢,但您知道如何获取任务值吗?Webservice ws=new Webservice();task token=ws.getToken(“);Console.WriteLine(令牌);它将返回“System.Threading.Tasks.Task`1[System.String]“@hkguile与您从
ReadToEndAsync
获得结果的方式相同,您需要等待函数。如果您要使用async/wait,则需要整个调用堆栈一直使用它,直到框架调用代码的起点为止。@hkgu”