同步调用asynchronous方法

我有一个async方法:

 public async Task<string> GenerateCodeAsync() { string code = await GenerateCodeService.GenerateCodeAsync(); return code; } 

我需要从同步方法调用这个方法。

我怎样才能做到这一点,而不必重复GenerateCodeAsync方法,以使其同步工作?

更新

但没有find合理的解决办法

但是,我看到HttpClient已经实现了这种模式

 using (HttpClient client = new HttpClient()) { // async HttpResponseMessage responseAsync = await client.GetAsync(url); // sync HttpResponseMessage responseSync = client.GetAsync(url).Result; } 

您可以访问该任务的Result属性,这将导致您的线程阻塞,直到结果可用:

 string code = GenerateCodeAsync().Result; 

注意:在某些情况下,这可能导致死锁:您对Result调用会阻塞主线程,从而阻止执行其余的asynchronous代码。 您有以下选项来确保不会发生这种情况:

  • .ConfigureAwait(false)添加到您的库方法
  • 在线程池线程中明确执行你的asynchronous方法并等待它完成:

     string code = Task.Run(GenerateCodeAsync).Result; 

您应该得到awaiter( GetAwaiter() )并结束等待asynchronous任务( GetResult() )的完成。

 string code = GenerateCodeAsync().GetAwaiter().GetResult(); 

你应该可以使用委托,lambdaexpression式来完成这个任务

 private void button2_Click(object sender, EventArgs e) { label1.Text = "waiting...."; Task<string> sCode = Task.Run(async () => { string msg =await GenerateCodeAsync(); return msg; }); label1.Text += sCode.Result; } private Task<string> GenerateCodeAsync() { return Task.Run<string>(() => GenerateCode()); } private string GenerateCode() { Thread.Sleep(2000); return "I m back" ; } 

我需要从同步方法调用这个方法。

可以使用GenerateCodeAsync().ResultGenerateCodeAsync().Wait() ,如其他答案所示。 这将阻止当前的线程,直到GenerateCodeAsync完成。

然而,你的问题是用asp.net标记的,你也留下了评论:

我希望得到一个更简单的解决scheme,认为asp.net处理这一点比编写这么多行代码容易得多

我的意思是,你不应该阻止在ASP.NET中的asynchronous方法。 这将减less您的Web应用程序的可伸缩性,并可能创build一个死锁(当GenerateCodeAsync内部的await继续发布到AspNetSynchronizationContext )。 使用Task.Run(...).Result将某些内容卸载到一个池线程,然后阻塞会更多地损害可伸缩性,因为它会导致多出一个线程来处理给定的HTTP请求。

ASP.NET通过asynchronous控制器(在ASP.NET MVC和Web API中)或直接通过经典ASP.NET中的AsyncManagerPageAsyncTask来内置对asynchronous方法的支持。 你应该使用它。 有关更多详细信息,请查看此答案 。

Microsoft Identity具有同步调用asynchronous方法的扩展方法。 例如,有GenerateUserIdentityAsync()方法和相等的CreateIdentity()

如果你看看UserManagerExtensions.CreateIdentity(),它看起来像这样:

  public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user, string authenticationType) where TKey : IEquatable<TKey> where TUser : class, IUser<TKey> { if (manager == null) { throw new ArgumentNullException("manager"); } return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType)); } 

现在让我们来看看AsyncHelper.RunSync的function

  public static TResult RunSync<TResult>(Func<Task<TResult>> func) { var cultureUi = CultureInfo.CurrentUICulture; var culture = CultureInfo.CurrentCulture; return _myTaskFactory.StartNew(() => { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = cultureUi; return func(); }).Unwrap().GetAwaiter().GetResult(); } 

所以,这是你的asynchronous方法的包装。 请不要从结果中读取数据 – 它可能会阻止您的代码在ASP中。

还有另外一种方法 – 这对我来说很可疑,但你也可以考虑

  Result r = null; YourAsyncMethod() .ContinueWith(t => { r = t.Result; }) .Wait(); 
 Task task1 = Task.Factory.StartNew(() => System.Threading.Thread.Sleep(3000)); task1.Wait(); Messagebox.Show("task1 completed"); Task task2 = Task.Factory.StartNew(() => System.Threading.Thread.Sleep(3000)); task2.Wait(); Messagebox.Show("task2 completed"); 

这帮助我下面的脚本只有在task1完成后才能继续工作。