如何使用不允许异步控制器操作的CMS处理异步API调用?

我一直在使用async / await,而且我所阅读的大多数内容都是“不要阻止异步代码” ,但控制台应用程序中的main函数除外。 我发现自己无法遵循这个简单的规则:(

我的应用程序在很大程度上取决于WebAPI层。 我在MVC应用程序中使用的客户端使用System.Net.Http.HttpClient上的async方法来调用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 GetSomethingAsync(int id) { return _client_GetSomethingFromApiAsync(id); } //Domain Service public Task 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 }); } 

根据我的研究,这些解决方案都不理想,虽然我没有遇到任何死锁问题,但一切似乎都有效。 有人可以帮我理解我应该遵循的最佳模式并解释原因吗?

谢谢!

我正在使用SiteFinity,无法使用异步控制器操作

根据SiteFinity ,它确实支持异步控制器操作,而不支持小部件中的异步操作。 如果这是你的情况,我鼓励你投票 。

假设您处于这种情况 – 并且不能使用async代码 – 那么我建议您只使用同步代码。 也就是说,用WebClient替换HttpClient或类似的东西。 我不建议使用Result因为即使您的代码今天没有死锁, HttpClient未来更新可能会导致死锁(不太可能,但可能)。

如果您不想失去已经在async进行的投资,那么我建议使用我在Brownfield async上的文章中描述的“boolean argument hack”。

您永远不应该只在异步方法上调用Result ,因为您可能会导致应用程序出现死锁。 我不使用SiteFinity,但在MVC中大量使用子操作,而且也不允许异步响应。 我的做法是使用我从Entity Framework代码库中窃取的助手类。

entity framework6除了原始的同步方法之外还添加了异步方法,但在幕后,只有异步方法可以进行任何实际工作。 同步方法现在只是同步调用异步方法。 为此,他们实现了一个名为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(Func> func) { return AsyncHelper._myTaskFactory .StartNew>(func) .Unwrap() .GetAwaiter() .GetResult(); } public static void RunSync(Func func) { AsyncHelper._myTaskFactory .StartNew(func) .Unwrap() .GetAwaiter() .GetResult(); } } 

要使用它,在控制器操作中,您只需执行以下操作:

 var something = AsyncHelper.RunSync(() => _client_GetSomethingFromApiAsync(id)); 

据我了解,异步控制器操作只会为您节省一个线程。 它对网站的行为没有其他影响。

因此,如果没有异步控制器,您将不得不等到任务完成(阻塞线程,因此它不能用于其他请求)。

或者你可以在任务完成之前返回,然后每隔几秒钟继续进行一次轮询,询问“我们还在吗?”,这看起来相当极端,除非绝对必要,否则我不会这样做。