C# 尝试使用异步方法访问Thread.CurrentPrincipal时发生ObjectDisposedException
我对新的async/await内容还相当陌生。但是,我有以下课程:C# 尝试使用异步方法访问Thread.CurrentPrincipal时发生ObjectDisposedException,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,我对新的async/await内容还相当陌生。但是,我有以下课程: public abstract class PluginBase { //Using EF to store log info to database private EFContext _context = new EFContext(); private int Id = 1; protected void LogEvent(string event, string details) {
public abstract class PluginBase
{
//Using EF to store log info to database
private EFContext _context = new EFContext();
private int Id = 1;
protected void LogEvent(string event, string details)
{
_context.LogEvents.Add(new LogItem(){
PluginId = this.Id,
Event = event,
Details = details,
User = Thread.CurrentPrincipal.Identity.Name
});
}
}
public class Plugin : PluginBase
{
public void Process()
{
CallWebService();
}
public async void CallWebService()
{
using(var http = new HttpClient())
{
...
var result = await http.PostAsync(memberURI, new StringContent(content, Encoding.UTF8,"application/json"));
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
所以,这个想法是Plugin.Process被调用。它依次调用CallWebService()。CallWebService对http.PostAsync进行异步调用。当我从该调用返回并尝试调用base.LogEvent()时,我得到一个ObjectDisposedException,声明“安全句柄已关闭”
我知道当等待完成时,该方法的其余代码必须运行。也许它正在其他线程或上下文中运行?如果是这种情况,如何在写入日志时获取当前用户
谢谢你的帮助
编辑
根据Yuval的回答,我做了以下修改,看起来效果不错
public void Process()
{
var task = CallWebService();
task.Wait();
}
public async Task CallWebService(List<Member> members)
{
using(var http = new HttpClient())
{
...
using(var result = await http.PostAsync(memberURI, new StringContent content, Encoding.UTF8, "application/json")))
{
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
}
公共作废流程()
{
var task=CallWebService();
task.Wait();
}
公共异步任务CallWebService(列表成员)
{
使用(var http=new HttpClient())
{
...
使用(var result=await http.PostAsync(memberURI,newstringcontent,Encoding.UTF8,“application/json”))
{
if(结果。IsSuccessStatusCode)
_status=“Success”;
其他的
_status=“Fail”;
LogEvent(“服务调用-”+_状态,…);
}
}
}
当我从那个调用返回并尝试调用base.LogEvent()时,我得到一个
ObjectDisposedException声明“安全句柄已关闭”
这是因为在调用链的更高层,有人正在处理你的插件对象,而这个对象还没有真正完成异步操作。使用async void
是执行“触发并忘记”操作。实际上,您并没有在进程上等待,因此任何调用它的人都会假定它已完成并处理您的对象
将async void
方法更改为async Task
,然后等待它:
public Task ProcessAsync()
{
return CallWebServiceAsync();
}
public async Task CallWebServiceAsync()
{
using (var http = new HttpClient())
{
var result = await http.PostAsync(memberURI,
new StringContent(content,
Encoding.UTF8,
"application/json"));
if (result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
注意,您还需要在调用堆栈的更高位置等待ProcessAsync。您能解释一下吗?我看不到在您的CallWebServiceAsync代码中返回任务。等待是否导致任务返回?进程是否可以等待该任务,而不是将其进一步传递到管道上?我没有看到在CallWebServiceAsync中返回任务。该任务是由编译器生成的状态机隐式创建的。您可以在CallWebService
中Wait
,但如果已在等待ProcessAsync
,则这将是多余的。使用async时,不要在代码中执行task.Wait()
。正确的解决方案是使Processspublic Task Process()
,并让它返回或等待从CallWebService返回的任务。如果调用Wait()
很有可能导致死锁。如果您想使用wait
,则必须在呼叫链的整个过程中使用它。如果无法将进程更改为返回任务,则不要使用PostAsync
,只需使用Post
,而不要使用async/await。