c# - 尝试使用异步方法访问 Thread.CurrentPrincipal 时出现 ObjectDisposedException

标签 c# multithreading asynchronous async-await

我对新的 async/await 东西还很陌生。但是,我有以下类(class):

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,...);
        }
    }
 }

最佳答案

When I return from that call and try to call base.LogEvent(), I get an ObjectDisposedException stating that "Safe Handle has been Closed".

那是因为在调用链的较高位置,有人正在处置您的插件对象,而该对象尚未真正完成异步操作。使用 async void 是在执行“即发即弃”操作。您实际上并没有在 Processawait,因此调用它的任何人都假定它已完成并处理您的对象。

将您的async void方法更改为async Task,然后await它:

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,...);
   }
}

请注意,您还需要await ProcessAsync 位于调用堆栈更高层的位置。

关于c# - 尝试使用异步方法访问 Thread.CurrentPrincipal 时出现 ObjectDisposedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30577518/

相关文章:

c# - 是否有任何常用的 IQueryable 实现?

c# - 使用 MySQL 在 ASP.NET 中登录错误

java - 限制迭代器的线程和/或重用线程?

python - 在 Django/Gunicorn 应用程序中拥有持久(非守护进程)线程的危险?

c# - TcpClient 已连接但服务器未收到消息

c# - 在运行时保存并重新加载 app.config(applicationSettings)

java - 同步:我的代码有什么问题?

c# - 如何从异步方法返回对象 (c# - xamarin.forms)?

javascript - 异步 JavaScript 回调

java - 使用@Async调用方法与在新线程中调用方法