Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Dispose is being called on DataContract even though the service still refers to it?

I have defined the following DataContract which implements IDisposable:

[DataContract]
public class RegularFileMetadata : FileMetadataBase, IDisposable
{
   bool _Disposed = false; //note this!

   //...

   protected virtual void Dispose(bool disposing)
   {
      if (!_Disposed)
      {
          //...
          _Disposed = true; //note this too!
      }
   }
   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }
}

And I call the following service method passing an instance of the above data contract:

[OperationContract]
[ServiceKnownType(typeof(RegularFileMetadata))]
Guid BeginUpload(FileMetadataBase metadata);

In the implementation of BeginUpload, I simply save metadata in a dictionary as:

Dictionary<Guid, RegularFileMetadata> _Dict;

public Guid BeginUpload(FileMetadataBase fileMetadata)
{
    //...
    var metadata = fileMetadata as RegularFileMetadata; 
    Guid sessionId = Guid.NewGuid();
    _Dict.Add(sessionId, metadata); //metadata SAVED!
    return sessionId ;
}

My question is, immediately after returning from this method, why Dispose() is called even though I've saved the instance in the dictionary _Dict?

I have verified that Dispose() method is called on the same instance which I have saved in my dictionary, as _Disposed becomes true for the saved object, i.e _Dict[sessionId]._Disposed becomes true!

The service behavior of my service is set as:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
like image 263
Nawaz Avatar asked Jul 09 '12 06:07

Nawaz


1 Answers

It's being disposed because that object "belongs" to WCF - it created the object instance out of thin air, to pass as a parameter to your method. And, it's kind enough to observe that this object implements IDisposable, so it's disposing of it once your method completes.

If you want an instance of this object to hang onto after your method completes, then you need to create such an instance yourself, copying relevant details from one instance to the other.

why Dispose() is called even though I've saved the instance in the dictionary _Dict

Because the Dispose pattern has nothing to do with references and garbage collection. All that matters is that, whenever references to a disposable object are being passed around between multiple methods/actors/agents, that there is an agreement on "who" is responsible for calling Dispose and when. In this instance, the "who" is the WCF infrastructure.


Correction - you can alter this behaviour by adding the OperationBehavior attribute to your method, and setting AutoDisposeParameters to false:

[OperationBehavior(AutoDisposeParameters=false)]
public Guid BeginUpload(FileMetadataBase fileMetadata)
{
    //...
    var metadata = 
like image 76
Damien_The_Unbeliever Avatar answered Oct 19 '22 04:10

Damien_The_Unbeliever