我一直在使用async / await和我所阅读的大多数状态“不要阻止异步代码”,但控制台应用程序中的main函数除外。我发现自己无法遵循这个简单的规则:(
我的应用程序在很大程度上依赖于WebAPI层。我在MVC应用程序中使用的客户端使用System.Net.Http.HttpClient
上的异步方法来调用API方法。目前我正在以两种方式处理它。在某些地方,我们在调用客户端后立即获得结果:
//WebAPI Client
public object GetSomething(int id)
{
var task = _client_GetSomethingFromApiAsync(id);
var result = task.Result;
return result;
}
在其他人中使用async一直到控制器。我正在使用SiteFinity,不能使用异步控制器操作,所以我最终得到这样的东西:
//WebAPI Client
public Task<object> GetSomethingAsync(int id)
{
return _client_GetSomethingFromApiAsync(id);
}
//Domain Service
public Task<object> GetSomethingDomainServiceAsync(int id)
{
return _service.GetSomethingAsync(id);
}
//Controller
public JsonResult GetSomethingControllerAction(int id)
{
var result = _domainService.GetSomethingDomainServiceAsync(viewModel.id).Result;
return Json(new { Success = true, Payload = result });
}
根据我的研究,这些解决方案都不理想,虽然我没有遇到任何死锁问题,但一切似乎都有效。有人可以帮我理解我应该遵循的最佳模式并解释原因吗?
谢谢!
答案 0 :(得分:2)
我使用的是SiteFinity,无法使用异步控制器操作
According to SiteFinity,它确实支持异步控制器操作,而不支持小部件中的异步操作。如果这是您的情况,我建议您vote。
假设您处于这种情况 - 并且无法使用async
代码 - 那么我建议您只使用同步代码。也就是说,将HttpClient
替换为WebClient
或类似的东西。我建议不要使用Result
,因为即使您的代码今天没有死锁,HttpClient
的未来更新可能会导致死锁,因此可能(不太可能,但可能)。
如果您不想丢失已经在async
中投入的投资,那么我建议您使用&#34;布尔参数hack&#34;正如我在brownfield async的文章中所述。
答案 1 :(得分:1)
您永远不应该只在异步方法上调用Result
,因为您可能会在应用程序中导致死锁。我没有使用SiteFinity,但确实在MVC中大量使用子操作,而且那些也不允许异步响应。我的做法是使用我从Entity Framework代码库中窃取的助手类。
实体框架6除了原始的同步方法之外还添加了异步方法,但在幕后,只有异步方法可以进行任何实际工作。同步方法现在只是同步调用异步方法。为此,他们实现了一个名为AsyncHelper
的内部帮助程序类(内部可见性,因此您无法在自己的应用程序中使用它)。但是,我接受了代码并在我的应用程序中创建了自己的AsyncHelper
:
public static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return AsyncHelper._myTaskFactory
.StartNew<Task<TResult>>(func)
.Unwrap<TResult>()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
AsyncHelper._myTaskFactory
.StartNew<Task>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
要使用此功能,请在控制器操作中执行以下操作:
var something = AsyncHelper.RunSync<SomeType>(() => _client_GetSomethingFromApiAsync(id));
答案 2 :(得分:0)
据我了解,异步控制器操作只会为您节省一个线程。它对网站的行为没有其他影响。
因此,如果没有异步控制器,您将不得不等到任务完成(阻塞线程,因此不能用于其他请求)。
或者你可以在任务完成之前返回,然后每隔几秒钟继续进行一次轮询,询问“我们还在吗?”,这看起来相当极端,除非绝对必要,否则我不会这样做。