Pan*_*kaj 0 c# asp.net-mvc asp.net-mvc-3 asp.net-mvc-4
我有一个Controller Action方法来保存用户详细信息,如下所示。
public async Task<ActionResult> SaveUser(ViewModel.VM_CreateUser user)
{
var result = await _user.Save(userDetails);
return Json(new { Success = String.IsNullOrEmpty(result) });
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,以上四行功能都没有问题。
public async Task<ActionResult> SaveUser(ViewModel.VM_CreateUser user)
{
var result = await _user.Save(userDetails);
new MailController().CreateUser(user.userDetails); //<==This is problem line of code.
}
Run Code Online (Sandbox Code Playgroud)
下面是我的邮件控制器。
public class MailController : MailerBase
{
public void CreateUser(ViewModel.VM_User user)
{
To.Add(user.EmailAddress);
From = System.Configuration.ConfigurationManager.AppSettings["emailSender"];
Subject = "Hi";
Email("CreateUser", user).DeliverAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,执行电子邮件发送代码时遇到问题。我收到以下错误消息。
异步模块或处理程序在异步操作仍挂起的同时完成
请提出纠正措施!
这是因为async
方法跟踪它们的完成,甚至async void
。他们通过SynchronizationContext
在启动时注册并在返回时将操作标记为完成来完成此操作。ASP.NET会跟踪所有已创建的操作,并要求它们在操作返回之前完成所有操作,否则它将向HTTP客户端返回错误。如果需要运行“即发即弃”方法,则必须手动避免在ASP.NET上启动它SynchronizationContext
。例如,await Task.Run(() => CallFireAndForget())
(await
让你等待同步部分线程池运行这工作,因为,CallFireAndForget()
是async void
要发射它返回的方法。Task
作为发射后不管,你必须明确地避免返回Task
到Task.Run()
这样的:await Task.Run(() => { CallFireAndForgetAsync(); })
) 。
出现相同错误消息的另一种方法应该是在异步操作中编写此消息:
// BAD CODE, DEMONSTRATION ONLY!
AsyncOperationManager.CreateOperation();
Run Code Online (Sandbox Code Playgroud)
如果使用AsyncOperation
API,则必须确保AsyncOperation.OperationCompleted()
在允许操作方法返回之前进行调用。
对于您的情况,如果邮件发送确实是一劳永逸的任务,则可以CreateUser
在将其签名更改为之后执行以下操作async Task CreateUserAsync(ViewModel.VM_User user)
:
await Task.Run(() => Email("CreateUser", user).DeliverAsync());
Run Code Online (Sandbox Code Playgroud)
在你的行动中:
await new MailController().CreateUserAsync(user.userDetails);
Run Code Online (Sandbox Code Playgroud)
理想情况下,您不会使用Task.Run()
这种东西。取而代之的是,您可以临时替换当前的SynchronizationContext
(注意:切勿await
在—内— try{}
而是,如果需要,将其存储Task
在本地,然后在恢复原始值后等待它SynchronizationContext
(使用SynchronizationContextSwitcher.NoContext()
(source)这样的原语可能更安全做正确的事)):
var originalSynchronizationContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
new MailController().CreateUser(user.userDetails);
}
finally
{
SynchronizationContext.SetSynchronizationContext(originalSynchronizationContext);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7235 次 |
最近记录: |