使用等待和异步返回字符串列表

Posted

技术标签:

【中文标题】使用等待和异步返回字符串列表【英文标题】:Return list of string using await and async 【发布时间】:2018-10-20 09:37:30 【问题描述】: 我在组织租户 Azure 环境中部署了一个 ASP.NET (4.5) 网站。 它具有上传/下载/删除文件(任何类型)到/从网络位置(我们称之为 nas 驱动器)的功能,例如\nas8782\xyz\abc\

上传/下载/删除工作正常(见下面的代码)。我们使用由 Azure 团队创建的 CloudSdk.Azure 库。

nasClient.UploadAsync nasClient.DownloadAsync nasClient.DeleteAsync nasClient.ListFilesAsync

文件服务.cs

using CloudSdk.Azure;

private string userId = ConfigurationManager.AppSettings["userId"].ToString();
    private string userPassword = ConfigurationManager.AppSettings["userPassword"].ToString();
    private string baseNasLocation = ConfigurationManager.AppSettings["baseNasLocation"].ToString();
    string env = ConfigurationManager.AppSettings["env"].ToString().ToUpper();

public async Task Upload(string fileName, string fileToSave, string projectID)
    
        var nasClient = new NasClient(userId, userPassword);
        var localFiles = new List<string>();
        localFiles.Add(fileToSave);
        await nasClient.UploadAsync(baseNasLocation + env + @"\" + projectID + @"\", localFiles);

public async Task Download(string fileToDownload, string projectID)
    
        var nasClient = new NasClient(userId, userPassword);
        Stream stream2 = nasClient.DownloadAsync(baseNasLocation + env + @"\" + projectID + @"\" + fileToDownload).Result;
        var appPath2 = HostingEnvironment.MapPath("~\\TempUpload");
        var localFullPath2 = string.Format("0\\1", appPath2, fileToDownload);
        using (var fileStream2 = System.IO.File.Create(localFullPath2))
        
            stream2.CopyTo(fileStream2);
        



 public async Task Delete(string fileToDelete, string projectID)
    
        var nasClient = new NasClient(userId, userPassword);
        Task stream2 = nasClient.DeleteAsync(baseNasLocation + env + @"\" + projectID + @"\" + fileToDelete);

我从我的 default.aspx.cs 页面调用这些函数

private void Download(string fileName)
    
        FileService fObj = new FileService();
        var task = Task.Run(async () =>  await fObj.Download(fileName, projectId.ToString()); );
        task.Wait();
    
 private void Delete(string fileName)
    
        FileService fObj = new FileService();
        var task = Task.Run(async () =>  await fObj.Delete(fileName, projectId.ToString()); );
        task.Wait();
    
private void Upload(string fileName, string fileToSave)
    
        FileService fObj = new FileService();
  var task = Task.Run(async () =>  await fObj.Upload(fileName, fileToSave, projectId.ToString()); );
        task.Wait();
    

问题

-这个 CloudSdk.Azure 库有另一个函数调用 ListFilesAsync,它获取提供的路径中存在的所有文件的列表。

我正在使用下面的代码来做同样的事情,但无法得到它。

如果我调用这个 Fileservice 方法

没有 async 和 await - 它运行但继续运行并且从不返回结果。

public  Task<string> ListFileNames(string projectID)
        
            var nasClient = new NasClient(userId, userPassword);
            string nasPath = baseNasLocation + env + @"\" + projectID + @"\"; 

            var content =  nasClient.ListFilesAsync(nasPath).Result;
            //return content;
            return JsonConvert.DeserializeObject <Task<string>> (content); 
        

使用 Async 和 await - 它会引发编译错误 > “字符串”不包含“GetAwaiter”的定义,并且找不到接受“字符串”类型的第一个参数的扩展方法“GetAwaiter”(您是否缺少 using 指令或程序集引用?)

 public async Task<string> ListFileNames(string projectID)
        
            var nasClient = new NasClient(userId, userPassword);
            string nasPath = baseNasLocation + env + @"\" + projectID + @"\"; 

            var content = await nasClient.ListFilesAsync(nasPath).Result;
            //return content;
            return JsonConvert.DeserializeObject <Task<string>> (content); 
        

我如何从 aspx.cs 页面调用此方法 > 如何返回结果?

  var task = Task.Run(async () =>  await fObj.ListFileNames(projectId.ToString()); );
        task.Wait();

对不起,问题太长了,我只是想尽可能多地描述一下。 我是这个 await 和 async 的新手,非常感谢所有帮助。

【问题讨论】:

你需要做await nasClient.ListFilesAsync(nasPath),就像你在所有其他地方做的一样(例如await nasClient.UploadAsync(...) 在 await 调用中你最后不需要Result,只需调用var content = await nasClient.ListFilesAsync(nasPath) 然后return content,你不需要JsonConvert.DeserializeObject &lt;Task&lt;string&gt;&gt;,它会自动将结果包装成Task&lt;string&gt; 让我尝试所有提到的建议。会通知的。 @SaK 我推荐阅读 Stephen Cleary 的 blog 及其 许多 篇关于 async/await 的文章。我从中学到了很多。 @john 感谢您的链接,一定会看看。 【参考方案1】:

您的实现如下:

  public async Task<string> ListFileNames(string projectID)
    
        var nasClient = new NasClient(userId, userPassword);
        string nasPath = baseNasLocation + env + @"\" + projectID + @"\"; 

        return await nasClient.ListFilesAsync(nasPath);
    
在 await 调用中没有调用 Result 不对Task&lt;string&gt;进行反序列化,它会自动将结果包装在Task&lt;T&gt;ResultWait 正在阻塞对 Task 的调用,而不是与 Async-Await 内联,因为操作是异步进行的。在少数情况下,您可能会使用 GetAwaiter().GetResult(),但我没有找到太多的用例。 Async 方法的返回类型可以是 TaskTask&lt;T&gt;,其中结果由设计自动包装。

Async Await 的工作方式是真正基于 Async / IO 的操作,它会释放调用上下文,而操作发生在后台,从而提高系统可扩展性

【讨论】:

我进行了编辑 - 我如何从 aspx.cs 调用此方法,如果需要更改,请查看并告诉我。 使用await代替Task.Wait(),因为你的调用方法本身是异步的,你可以执行以下操作:await fObj.ListFileNames(projectId.ToString());,甚至不需要包裹在Task.Run中,因为您正在调用 Async 方法 即使你使用Task.Run,这不是必需的,那么它仍然应该是await Task (将释放调用线程)而不是Task.Wait()(将保持线程) 谢谢,让我试一次。【参考方案2】:

您可以使用 Task.Result 以同步方式获取 Task 的结果。

字符串结果 = Task.Result;

另外,您不应该使用 JsonConvert.DeserializeObject 来创建任务。我不确定你想在那里做什么。您可以使用允许动态访问的 JObject。

【讨论】:

以上是关于使用等待和异步返回字符串列表的主要内容,如果未能解决你的问题,请参考以下文章

异步等待正确使用

等待 api 中的空响应

Redux 中的异步/等待

异步函数返回undefined

useEffect 等待异步函数的结果

等待异步函数调用完成