我有一个async方法:
public async Task<string> GenerateCodeAsync()
{
string code = await GenerateCodeService.GenerateCodeAsync();
return code;
}
我需要从一个同步方法调用这个方法。
我如何才能做到这一点,而不必复制GenerateCodeAsync方法,以使其同步工作?
更新
但没有找到合理的解决方案。
但是,我看到HttpClient已经实现了这个模式
using (HttpClient client = new HttpClient())
{
// async
HttpResponseMessage responseAsync = await client.GetAsync(url);
// sync
HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
我需要从同步方法调用这个方法。
这可以通过GenerateCodeAsync()实现。Result或GenerateCodeAsync(). wait(),如其他答案所示。这将阻塞当前线程,直到GenerateCodeAsync完成。
然而,你的问题被标记为asp.net,你也留下了评论:
我希望有一个更简单的解决方案,认为asp.net可以处理
这比写这么多行代码要容易得多
我的观点是,你不应该阻塞ASP.NET中的异步方法。这将降低web应用的可伸缩性,并且可能会产生死锁(当GenerateCodeAsync内部的await continuation被发布到AspNetSynchronizationContext时)。使用Task.Run(……)。结果,将某些内容卸载到池线程,然后阻塞将进一步损害可伸缩性,因为它会导致+1个线程来处理给定的HTTP请求。
ASP。NET内置了对异步方法的支持,可以通过异步控制器(在ASP。NET MVC和Web API)或直接通过经典ASP.NET中的AsyncManager和PageAsyncTask。你应该使用它。要了解更多细节,请检查这个答案。
Microsoft Identity具有同步调用异步方法的扩展方法。
例如,有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确实
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();
}
这是async方法的包装器。
请不要从Result中读取数据——它可能会在ASP中阻塞你的代码。
还有另一种方法——对我来说有点可疑,但你也可以考虑一下
Result r = null;
YourAsyncMethod()
.ContinueWith(t =>
{
r = t.Result;
})
.Wait();