Dispose and returning Disposable objects?

C

Carl R

I have a class that owns a dataset, adding to it during it's work.
The method using the class fetches the dataset in order to return it
as a result in a web method.

Simplified:
class A
{
Dataset m_b;
public A()
{m_b=new Dataset();}

public DoWork()
{ /* appends to dataset m_b */}

public Dataset Result
{ return m_b;}
}

Allright, since A owns a dataset, according to fxcop it should
implement IDisposable.

class A: IDisposable
{
Dataset m_b;
public A()
{m_b=new Dataset();}

public DoWork()
{ /* appends to dataset m_b */}

public Dataset Result
{ return m_b;}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
m_b.Dispose();
}
}
}

If I use the class like this:

[WebMethod]
Dataset DoStuff()
{
Dataset d;

using(A a = new A())
{
a.DoWork();
d = a.Result;
}

//d is already disposed here
return d;
}

Then A would dispose the dataset resulting in d being invalid on the
last row.
Ok, so if I change A to return a copy this problem is solved right?
class A: IDisposable
{
public Dataset Result
{ return m_b.Copy();}
}


Now what happens with the dataset that I return in the webservice?
The serialized dataset is up to the retriever, but the one on my side
can hardly be disposed automatically? (only finalized)
Alternatives:

[WebMethod]
Dataset DoStuff()
{
Dataset d;

using(A a = new A())
{
a.DoWork();
d = a.Result;
}

try
{
return d;
}
finally
{
d.Dispose();
}
}

[WebMethod]
Dataset DoStuff()
{
using(Dataset d)
{

using(A a = new A())
{
a.DoWork();
d = a.Result;
}

return d;
}
}

[WebMethod]
Dataset DoStuff()
{

using(A a = new A())
{
a.DoWork();
Using(Dataset d = a.Result)
{
return d;
}
}
}

Do you find theese alternatives reasonable? I think they look rather
strange all of them.
What is the correct way?

("Dataset" can be anything IDisposable.
d can be used between retrieving it and returning it.)

Thanks!
 
C

Carl R

Why do you say that "A owns a dataset"?  From the example code you've  
posted, it doesn't appear to me that A owns the dataset at all.

http://msdn.microsoft.com/en-us/ms182172.aspx
Well it declares it and creates it. Then it gives away the ownership
all right, but looking at fxcop it seemed that C# had a different
view, seing the class as responsible for it.

Since microsoft says...
"When to Suppress Warnings:
Do not suppress a warning from this rule. "
....I figured I'd do my best to understand how the c# language views
this.
Also, beware of FxCop giving what are essentially false-positive  
warnings.  At the very least, in your example you have no need of a  
finalizer (and in fact didn't even post one), and so there's no need to  
call GC.SuppressFinalize().  But beyond that, FxCop doesn't really have 
any way to know that your class doesn't really own the DataSet instance,  
and so shouldn't necessarily be disposing it.

Are there any authorative design guidelines for this situation? Google
didn't help before I posted here.
Without seeing the actual code, or at least a better representation of it 
than you've shown here so far, it's hard to know what the best alternative  
would be.  But it's not clear to me why you have the "DoWork()/Result"  
pattern in the first place, nor why part of that pattern requires you to  
store the DataSet reference in the class itself.

It doesn't matter. One reason could be that "DoStuff" gets called
several times. It's just an example.
It could just as well be a builder etc.
[...]
Do you find theese alternatives reasonable? I think they look rather
strange all of them.
What is the correct way?

None of those are appropriate, as they all dispose the DataSet before  
returning it.

Then what is the correct way? ;)
 
C

Carl R

[...]
Do you find theese alternatives reasonable? I think they look rather
strange all of them.
What is the correct way?
None of those are appropriate, as they all dispose the DataSet before  
returning it.
Then what is the correct way? ;)

The only answer that can be given based on what you've shown so far is  
simply "don't dispose the DataSet before returning it".

The question is too vague to provide anything beyond that.

Pete

I don't think it's vague at all.
However, regarding datasets here's some food for thought:
http://www.developerdotstar.com/community/node/247
 
C

Carl R

[...]
The question is too vague to provide anything beyond that.
I don't think it's vague at all.

Well, for better or worse, whether _you_ think it's vague isn't all that  
relevant.  Unless, of course, you wish to answer the question yourself. :)

Should Disposable objects be disposed?
If a Disposable object is serialized by a web service as a result of a
return statement, does it dispose the object, taking ownership of it?

Is that more concise?
 
C

Carl R

Yes, they should (but obviously not before you're done with them).


I don't know off the top of my head, and without a concise-but-complete  
code sample demonstrating the specific issue, I don't have a practical way  
to explore the question myself.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Diagnostics;

namespace DisposableTestService
{
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
/// <summary>
/// Yields:
/// Creating X
/// X has value: Hello World
/// Disposing X with value: Hello World
/// -----
/// Serialized object: <X xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://tempuri.org/" />
/// </summary>
/// <returns></returns>
[WebMethod]
public X HelloWorld()
{
Trace.WriteLine("Creating X");
using (X x = new X("Hello World"))
{
Trace.WriteLine("X has value: " + x.Foo);
return x;
}
}

/// <summary>
/// Creating X
/// X has value: Hello World
/// -----
/// Serialized object:
/// <X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://
tempuri.org/">
/// <Foo>Hello World</Foo>
/// </X>
/// </summary>
/// <returns></returns>
[WebMethod]
public X HelloWorldNoDispose()
{
Trace.WriteLine("Creating X");
X x = new X("Hello World");
Trace.WriteLine("X has value: " + x.Foo);
return x;
}
}

public class X : IDisposable
{
string m_foo;

//For serialization
public X()
{ }

public X(string value)
{
m_foo = value;
}

public string Foo
{
get { return m_foo; }
set { m_foo = value; }
}

public void Dispose()
{
Trace.WriteLine("Disposing X with value: " + m_foo);
m_foo = null;
}
}
}
Not only is it more concise, it's a much more specific and answerable  
question.  Thank you!

Pete

Given the above example, how could one go about to have a local
disposable object disposed yet returned through the web service?
 
C

Carl R

[...]
Given the above example, how could one go about to have a local
disposable object disposed yet returned through the web service?

I admit, I know not very much about web services at all.  But your code 
example appears to be incomplete.  I don't see anything that would  
actually cause the web service methods to be used.

By setting up a web service project and adding this service to it, you
can call it locally from debug mode, on the description web page that
is spawned by default when you start debugging.
Not knowing that much about web services, I don't have first-hand  
knowledge of how you'd manage the object lifetime for web methods.  But,  
I'm sure you can't go around disposing the object before you've returned  
it from the method.  If the web services framework won't do it for you  
(and judging from the comments in your code, it appears you've confirmed  
that it won't), you need some way to detect when the object's been  
successfully serialized, and dispose it after that happens.

Perhaps there's a newsgroup specific to web services -- maybe ASP.NET  
would be better? -- where you're more likely to find people with specific 
information about the question.

Pete

I have a solution. Thank you for making me writing a spike and
confirming the problem.
I think an explanation is that a web service couldn't know wether it
gets an object that it should take ownership on or if it's an object
that I want to keep, serverside.
Thus it occured to me that I should look for events or similar after
the method is returned. Webservice has a dispose that could be
overridden so that is what I did.
I have a list of disposable objects, adding to it as necessary. When
disposing the service I dispose all objects in the list.
For reference, here's the complete code.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Diagnostics;

namespace DisposableTestService
{
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
List<IDisposable> m_disposables;

public Service1()
{
m_disposables = new List<IDisposable>();
}

/// <summary>
/// Yields:
/// Creating X
/// X has value: Hello World
/// Disposing X with value: Hello World
/// -----
/// Serialized object: <X xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://tempuri.org/" />
/// </summary>
/// <returns></returns>
[WebMethod]
public X HelloWorld()
{
Trace.WriteLine("Creating X");
using (X x = new X("Hello World"))
{
Trace.WriteLine("X has value: " + x.Foo);
return x;
}
}

/// <summary>
/// Creating X
/// X has value: Hello World
/// -----
/// Serialized object:
/// <X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://
tempuri.org/">
/// <Foo>Hello World</Foo>
/// </X>
/// </summary>
/// <returns></returns>
[WebMethod]
public X HelloWorldNoDispose()
{
Trace.WriteLine("Creating X");
X x = new X("Hello World");
Trace.WriteLine("X has value: " + x.Foo);
return x;
}

/// <summary>
/// Creating X
/// X has value: Hello World
/// Added X to disposables. Disposable item count: 1
/// Disposing an item.
/// Disposing X with value: Hello World
/// -----
/// <X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://
tempuri.org/">
/// <Foo>Hello World</Foo>
/// </X>
/// </summary>
/// <returns></returns>
[WebMethod]
public X HelloWorldDisposeByServiceDispose()
{
Trace.WriteLine("Creating X");
X x = new X("Hello World");
Trace.WriteLine("X has value: " + x.Foo);
m_disposables.Add(x);
Trace.WriteLine("Added X to disposables. Disposable item
count: " + m_disposables.Count);
return x;
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (null != m_disposables)
{
foreach (IDisposable d in m_disposables)
{
Trace.WriteLine("Disposing an item.");
d.Dispose();
}
m_disposables.Clear();
m_disposables = null; //Do or don't?
}
}

base.Dispose(disposing);
}
}

public class X : IDisposable
{
string m_foo;

//For serialization
public X()
{ }

public X(string value)
{
m_foo = value;
}

public string Foo
{
get { return m_foo; }
set { m_foo = value; }
}

public void Dispose()
{
Trace.WriteLine("Disposing X with value: " + m_foo);
m_foo = null;
}
}
}
 
C

Carl R

[...]
I have a solution. Thank you for making me writing a spike and
confirming the problem.

You're welcome.  :)  Sometimes all a person needs is to be forced to  
explain their question as though they're speaking to a moron, for a  
solution to finally become apparent.  :)
I think an explanation is that a web service couldn't know wether it
gets an object that it should take ownership on or if it's an object
that I want to keep, serverside.

That may well be how the .NET implementation is.  It's unfortunate that 
Microsoft hasn't provided a way for that to happen though.  For example,  
it could have provided a property on the [WebMethod] attribute that  
indicates whether ownership of the returned object is being passed to .NET  
or not.

Alternatively, it could provide some kind of event that's raised when .NET  
is done with objects automatically serialized because of the [WebMethod]  
attribute, so your own code can make a decision about what to do with it  
at that point.  It's still not clear to me whether the call to Dispose()  
provides exactly that information or not.  See below...
Thus it occured to me that I should look for events or similar after
the method is returned. Webservice has a dispose that could be
overridden so that is what I did.
I have a list of disposable objects, adding to it as necessary. When
disposing the service I dispose all objects in the list.

What's the lifetime of an instance of a WebService?  I saw that the class  
implements IDisposable, but not knowing much about web services, I was  
concerned that these objects could live for a very long time.  Perhaps  
longer than if you simply wrote a finalizer for the object and let the GC 
clean them up (which is normally not a good approach, but if the only  
alternative is intentionally pack-ratting, maybe it's better than that :) 
).  I certainly didn't feel qualified to suggest that as an solution.  :)

Does a single WebService instance handle multiple clients?  Or does a new  
one get allocated for each client session?  And if so, is there in fact 
some mechanism that times out the session so that you have some reasonable  
assurance your objects will get cleaned up in a timely manner?  Or is a 
whole new instance created for each call to the [WebMethod], providing a  
precise one-to-one correlation between the method call and the subsequent 
call to Dispose()?

Pete

Dispose is called immediately. A webservice afaik works like a webpage
in that it is created and destroyed for each httprequest.

Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top