问题描述
我在控制器中有以下代码。
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
private ApplicationDbContext userDB;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetowinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public async Task SendEmail(string user_id,string subject,string user_email )
{
await UserManager.SendEmailAsync(user_id,subject,user_email);
}
public ActionResult Transfer(int id,int nurse_id,int ambulance_id,int driver_id,int nurse_account_id)
{
...
/////////////////////////////////
//Send email
string nurse_user_id = db.Nurse_Account.Where(m => m.nurse_account_id == call.nurse_account_id).Select(m => m.nurse_account_user_id).First();
string usr = db.AspNetUsers.Where(m => m.Id == nurse_user_id).Select(m => m.Id).First();
string usr_mail = db.AspNetUsers.Where(m => m.Id == nurse_user_id).Select(m => m.Email).First();
SendEmail(usr,"New call",usr_mail);
////////////////////////////////
...
return Json(new { result = "OK" },JsonRequestBehavior.AllowGet);
}
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=mscorlib
StackTrace:
at System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.PostAction(Object state)
at System.Threading.Tasks.AwaitTaskContinuation.runcallback(ContextCallback callback,Object state,Task& currentTask)
at System.Threading.Tasks.AwaitTaskContinuation.<>c.<ThrowAsyncIfNecessary>b__18_0(Object s)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback callback,Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
This exception was originally thrown at this call stack:
[External Code]
解决方法
您看到的问题是由请求外部代码引起的。所有请求外部代码都是危险的。
具体来说,代码正在调用 SendEmail
但没有 await
对结果进行处理。所以它试图做一种“即发即忘”。在它调用 SendEmail
之后,它将响应发送回客户端,让 SendEmail
作为请求外部代码运行。
然而,SendEmail
是在 ASP.NET 请求上下文中调用的,因此当它尝试在 await
之后继续执行时,会遇到错误,因为该 ASP.NET 请求上下文已经消失.响应已经发送,所以没有更多的 ASP.NET 请求上下文。
最好的解决方案是删除请求外部代码。 await
调用 SendEmail
或 build a basic distributed architecture for asynchronous messaging。我只想说使用 await
除非你必须提前返回,在这种情况下你需要一个持久队列和一个工作进程。 MVC 操作会将包含所有电子邮件详细信息的消息写入队列,然后返回 HTTP 结果。工作进程将读取该队列并发送实际的电子邮件。
任何其他解决方案都将使用 request-extrinsic code,which is inherently dangerous。具体来说,任何请求外部代码都可能在没有警告和日志的情况下停止工作。 “即发即忘”字面意思的意思是“忘记”。工作(在这种情况下是电子邮件)可能会丢失。但是,如果您对此没有意见,那么您可以使用 NoContext
from my AsyncEx library 之类的东西以不引用 ASP.NET 请求上下文的方式调用请求外部代码。