泄露Web服务已完成事件?

时间:2013-07-30 14:44:09

标签: c# .net web-services event-handling

在我的C#应用​​程序中,我有一个服务引用,我一遍又一遍地执行相同的调用。

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;
  service.GetDataCompleted += (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times
  }
  service.GetDataAsync(request);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;
  service.GetDataCompleted += (sender, args) => 
  {
      // do something different here!
  }
  service.GetDataAsync(request);
}

我怀疑这会以某种方式泄漏,因为我每次都会注册一个新的事件处理程序。 这是真的,如果是的话,我怎么能避免这种情况呢?

1 个答案:

答案 0 :(得分:0)

你可以这样做:

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;

  EventHandler handler = null; 
  handler = (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;
  EventHandler handler = null; 

  handler = (sender, args) => 
  {
      // do something different here!

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);
}

编辑:关于仅将呼叫同步到其处理程序:如果您紧跟GetData2()后跟GetData(),则会从上述代码中获得不可预知的结果。大多数情况下,两个请求都会被调用。

最简单的解决方案是每个service方法使用单独的GetDataX()代理对象。这样你就可以同时发出两个请求。

但是,如果您被迫只使用一个代理对象,并进行并发请求 - 则可以调用错误的处理程序。一个选项是您可以使用UserState对象来标识您的请求,因此即使调用了错误的处理程序,它也可以检测到它被调用了错误的请求。

void GetData()
{
  var request = new GetDataRequest { someData = "blabla" } ;

  Guid userState = Guid.NewGuid();

  EventHandler<GetDataCompletedEventArgs> handler = null; 
  handler = (sender, args) => 
  {
      if (userState.Equals(args.UserState)) 
      {
          // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

          //remove itself
          service.GetDataCompleted -= handler;
      }
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request, userState);
}

void GetData2()
{
  var request = new GetDataRequest { someData = "blabla2" } ;

  Guid userState = Guid.NewGuid();

  EventHandler<GetDataCompletedEventArgs> handler = null; 
  handler = (sender, args) => 
  {
      if (userState.Equals(args.UserState)) 
      {
          // do something different here!

          //remove itself
          service.GetDataCompleted -= handler;
      }
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request, userState);
}

现在,如果您发出并发请求,即使两个请求都调用了两个处理程序,只有正确请求的正确代码才会在if条件内运行。

如果您不想使用UserState,可以通过某些方法同步呼叫,以便处理程序不会互相跳过。以下是使用Tasks的一种非阻塞方式,可确保请求一个接一个地发生。

Task<GetDataResponse> GetData()
{
  var src = new TaskCompletionSource<GetDataResponse>();     

  var request = new GetDataRequest { someData = "blabla" } ;
  EventHandler handler = null; 
  handler = (sender, args) => 
  {
      // do something; i'm afraid that this is executed multiple times, as GetData() is called multiple times

      src.SetResult(args.Result);

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);

  return src.Task;
}

Task<GetDataResponse> GetData2()
{
  var src = new TaskCompletionSource<GetDataResponse>();

  var request = new GetDataRequest { someData = "blabla2" } ;
  EventHandler handler = null; 

  handler = (sender, args) => 
  {
      // do something different here!

      src.SetResult(args.Result);

      //remove itself
      service.GetDataCompleted -= handler;
  };

  service.GetDataCompleted += handler;
  service.GetDataAsync(request);

  return src.Task;

}

在调用方法中,你确保它们被一个接一个地调用:

GetData().ContinueWith( t => GetData2() );