这个问题与这个(未回答的)问题非常相似: ASP.NET 中的 SpeechSynthesizer - 异步错误
我正在尝试在 ASP MVC 项目中使用 System.Speech 方法,但如果我这样做:
[HttpGet]
public ActionResult SystemSpeechInstalledVoices()
{
var synt = new System.Speech.Synthesis.SpeechSynthesizer();
var voices = synt.GetInstalledVoices();
var response = Json(voices);
response.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return response;
}
一旦GetInstalledVoices
被调用,页面就会抛出一个:
此时无法启动异步操作。异步操作只能在异步处理程序或模块内或在页面生命周期中的某些事件期间启动。如果在执行页面时发生此异常,请确保将页面标记为 <%@ Page Async="true" %>。此异常还可能表示尝试调用“async void”方法,在 ASP.NET 请求处理中通常不支持该方法。相反,异步方法应该返回一个任务,调用者应该等待它。
但是我在控制器内部所做的一切都是异步的!在控制器内部,我没有什么可以等待或调用 Result 的。更奇怪的是,如果我从 Web API 控制器中执行几乎完全相同的操作:
[HttpGet]
public IHttpActionResult SystemSpeechInstalledVoices()
{
var synt = new System.Speech.Synthesis.SpeechSynthesizer();
var voices = synt.GetInstalledVoices();
var response = Json(voices);
return response;
}
然后当我调用 API 方法时,它首先工作并返回所有信息,但是如果我再次调用它,那么页面就会永远挂起加载。如果我使用其他方法,例如调用 synt.Speak,也会发生同样的事情:
var synt = new System.Speech.Synthesis.SpeechSynthesizer();
synt.Speak("Hello");
尽管文档清楚地指定 Speak 方法“同步说出字符串的内容。”,但这几行代码足以引发提到的行为(我知道我应该对流“说话”,但这不是重点这里)。这里发生了什么事??是否可以在 ASP MVC 中使用 System.Speech?
编辑 1好的,我知道如果我将 Controller Action 转换为 async 返回 Task 它不会抛出错误(因为异常要求我这样做),但在我看来这只是一种规避问题的方法。为什么我必须这样做?它所说的异步操作在哪里?让我烦恼的是,如果代码真的是同步的(正如它在文档中明确指出的那样),为什么有必要这样做?事实上,如果代码是同步的,我应该也可以这样做:
[HttpGet]
public ActionResult SystemSpeechInstalledVoices()
{
var result = Task.Run(() =>
{
using (var synt = new System.Speech.Synthesis.SpeechSynthesizer())
{
var voices = synt.GetInstalledVoices();
var response = Json("anything");
response.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return response;
}
});
return result.Result;
}
当我这样做时,它适用于第一个请求,然后它显然随机抛出异常或不抛出异常。在我看来,在调用 GetInstalledVoices 并返回 Task 之后,“某些东西”留在了后台,只是将问题扫到了地毯下。
编辑 2在阅读https://weblogs.asp.net/ricardoperes/speech-synthesis-with-asp-net-and-html5后:
我们需要设置一个同步上下文,因为 SpeechSynthesizer 是异步工作的,所以我们可以等待它的结果
我努力了:
[HttpGet]
public ActionResult SystemSpeechInstalledVoices()
{
System.ComponentModel.AsyncOperationManager.SynchronizationContext = new System.Threading.SynchronizationContext();
using (var synt = new System.Speech.Synthesis.SpeechSynthesizer())
{
var voices = synt.GetInstalledVoices();
var response = Json("anything");
response.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return response;
}
}
现在它工作了。但老实说,我不知道为什么,也不知道这样做是否有其他后果。任何关于此事的线索将不胜感激。