由于SignalR集线器调用,我需要发送一封电子邮件。我不希望发送同步执行,因为我不想绑定WebSocket连接,但如果可能的话,我希望调用方得到通知,如果有错误的话。我想我可以在集线器中使用这样的东西(减去错误处理和我希望它做的所有其他事情):
public class MyHub : Hub {
public async Task DoSomething() {
var client = new SmtpClient();
var message = new MailMessage(/* setup message here */);
await client.SendMailAsync(message);
}
}但很快就发现它无法工作;client.SendMailAsync调用抛出了以下内容:
System.InvalidOperationException:此时无法启动异步操作。异步操作只能在异步处理程序或模块中启动,或者在页生命周期中的某些事件期间启动。
进一步的研究和阅读已经告诉我,SmtpClient.SendMailAsync是EAP方法的一个TAP包装器,而SignalR不允许这样做。
我的问题是,有什么简单的方法可以直接从集线器方法异步发送电子邮件吗?
还是我唯一的选择是把电子邮件发送代码放在其他地方?(例如,让集线器排队一条服务总线消息,然后独立的服务可以处理这些消息并发送电子邮件,尽管我还需要做更多的工作来实现结果通知给集线器的客户端;或者让中心向完成电子邮件发送的webservice发出HTTP请求)。
发布于 2014-06-24 12:13:18
SignalR团队是意识到这个问题,但还没有修复它。在这一点上,它看起来将进入SignalR v3。
在此期间,一个快速的黑客将是:
public async Task DoSomething() {
using (new IgnoreSynchronizationContext())
{
var client = new SmtpClient();
var message = new MailMessage(/* setup message here */);
await client.SendMailAsync(message);
}
}
public sealed class IgnoreSynchronizationContext : IDisposable
{
private readonly SynchronizationContext _original;
public IgnoreSynchronizationContext()
{
_original = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
public void Dispose()
{
SynchronizationContext.SetSynchronizationContext(_original);
}
}发布于 2014-06-24 12:12:10
我的理解是,最初的EAP风格的SmtpClient.SendAsync (被SendMailAsync包装为TAP)调用SynchronizationContext.Current.OperationStarted/OperationCompleted。据称,这就是让SignalR主机不开心的原因。
作为一种解决办法,以这种方式尝试(未经测试)。如果对你有用的话请告诉我们。
public class MyHub : Hub {
public async Task DoSomething() {
var client = new SmtpClient();
var message = new MailMessage(/* setup message here */);
await TaskExt.WithNoContext(() => client.SendMailAsync(message));
}
}
public static class TaskExt
{
static Task WithNoContext(Func<Task> func)
{
Task task;
var sc = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
task = func();
}
finally
{
SynchronizationContext.SetSynchronizationContext(sc);
}
return task;
}
}https://stackoverflow.com/questions/24377081
复制相似问题