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

1

11

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)]
Papuan answered 9/7, 2012 at 6:43 Comment(2)
Are you ssure that Dispose(..) is called on the same instance you created ? I mean, may be there was created another instance of the class and Dispose(..) was called on that one. Check hashcode of the instance you get Dispose(..) on...Alialia
@Tigran: I updated my question with : "I have verified that Dispose() method is called on the same instance which I have saved in my dictionary, as the _Disposed becomes true for the saved object."Papuan
B
16

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 = 
Befool answered 9/7, 2012 at 8:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.