2

The following two lines of code execute one right after the other:

this.dataWriter.WriteBytes(message.MessageBuffer);
await this.dataWriter.StoreAsync();

Although the WriteBytes call completes without exception, the StoreAsync call right below it bombs with a ObjectDisposedException and says

The object has been closed. (Exception from HRESULT: 0x80000013)

this.DataWriter (Windows.Storage.Streams.DataWriter) is not null, so what exactly is it saying is "closed?"

EDIT

Just for some further context on how the object is created

this.socket = new StreamSocketListener();
this.socket.ConnectionReceived += this.EventSocketConnectionReceived;
private void EventSocketConnectionReceived(StreamSocketListener sender,
    StreamSocketListenerConnectionReceivedEventArgs args)
{
    if (this.dataWriter == null)
    {
       this.dataWriter = new DataWriter(args.Socket.OutputStream);
    }
}
O.O
  • 11,077
  • 18
  • 94
  • 182
  • What's the type of dataWriter? – Camilo Terevinto Jan 04 '16 at 23:12
  • Windows.Storage.Streams.DataWriter – O.O Jan 04 '16 at 23:17
  • What does the constructor for `dataWriter` look like, in your code? What do you pass it? – Matthew Haugen Jan 04 '16 at 23:19
  • you are getting the exception because datawriter is a disposed object. But from posted code, it is not clear how it is happening. – Abhinav Galodha Jan 04 '16 at 23:20
  • 1
    It is entirely normal. Classes implement IDisposable because they have a private member that disposable. And just leave it up to *that* class to generate the exception. You're unlikely to use that disposable object when you call WriteBytes() because that just takes memory. Store(), sure, kaboom now. Add the wrinkle that ICloseable was added to WinRT very, very late and easy to see why existing methods did not have the extra check. – Hans Passant Jan 04 '16 at 23:21
  • @O.O please post the entire method body (omit parts not related to the streams if you want) – Camilo Terevinto Jan 04 '16 at 23:37

1 Answers1

2

I have no experience with Windows.Storage.Streams.DataWriter, but my bet is that you're passing it a stream, then closing it, then calling this. It's probably not the dataWriter that's even throwing the exception, although glancing at the Stack Trace would tell you.

This code would cause this error, and it's a pretty easy mistake to make:

Windows.Storage.Streams.DataWriter dataWriter;
using (var file = File.OpenRead("..."))
{
    dataWriter = new DataWriter(file);
}

dataWriter.WriteBytes(message.MessageBuffer);
await dataWriter.StoreAsync();

Disposal has little to directly do with null. There's rarely much to do with something that's disposed, so we make it null, but that's not necessary.

I'd check around to see what stream you're passing into the constructor, and then look for any references to that stream that might be disposing it (either through a using block like I showed here, or an explicit call to stream.Dispose()).

There are an infinite combination of lines to throw it, and it's unlikely that what you've got is as simple as anything I'm saying here (it's probably spread across constructors and methods, and mixed in with unrelated code). But I'd virtually guarantee that it's something like this pattern.


Just since it sounds like there's some disagreement, the issue here is that it's difficult to tell if something is disposed without telling it to do something.

Because DataWriter is essentially caching up operations, it doesn't talk to the underlying stream until you call StoreAsync(). That's why WriteBytes isn't async, as well. You can imagine an implementation that just pins them onto a List<byte> (although it'd be much more complicated than that, of course).

But when you do call the StoreAsync() method, it reaches out to the stream and says "write this stuff I have cached up." The stream tries, but it's already been closed, so it throws that exception.

That's why it doesn't throw on the first line, but does on the second. And why I'm hazarding the guess that this is a disposed stream, as compared to the DataWriter itself being disposed.


Per your edit and comment, your stream is coming from event args.

My guess is that the stream is getting closed by the event caller, or else the socket is getting closed by the remote client (perhaps due to a timeout?). I don't know whether there's a right way to persist that stream, if it is the former. But that's probably where you should put your research time.

Community
  • 1
  • 1
Matthew Haugen
  • 12,916
  • 5
  • 38
  • 54
  • @cFrozenDeath Does `WriteBytes` check disposal of the underlying stream? I'd assume not, in which case that detail is irrelevant. That's why I jumped to what I said first, rather than the obvious choice that the `DataWriter` itself could be disposed. – Matthew Haugen Jan 04 '16 at 23:27
  • @MatthewHaugen - the writer is not disposed and it is not null, unless you can have an object that is not null but is disposed.... – O.O Jan 04 '16 at 23:32
  • @O.O You can. Disposal just means `Dispose()` was called, which can happen at any point, just like any other method. You'd normally want to get rid of it afterwards, but that isn't a contract guarantee. – Matthew Haugen Jan 04 '16 at 23:34
  • Very well, the code in this class that uses the data writer never once calls dispose (and the member is only ever used in this class). and I don't see a way to check if it is disposed either. – O.O Jan 04 '16 at 23:36
  • @O.O Yeah, I don't think the DataWriter is disposed. I think the underlying stream is. Have you looked into what stream you passed to the constructor, and what references there are to it throughout your code? – Matthew Haugen Jan 04 '16 at 23:36
  • Yeah, I think that would have to be it. Looks like the stream is passed in when an event socket connection is received and then the writer is created as such from the event arguments (custom class): `this.dataWriter = new DataWriter(args.Socket.OutputStream);` So the error has nothing to do with the writer, but everything to do with the steam. Guess it's just a confusing error message. – O.O Jan 04 '16 at 23:40
  • @O.o Yep, exactly. And it makes sense that they would dispose that stream when the socket gets closed, too, if that's the case (don't quote me on that being your cause here, there are lots of reasons to close a stream). In any event, the powers that be probably don't guarantee that stream to be around outside the scope of the event, so it gets disposed, and there you go. That makes sense. – Matthew Haugen Jan 04 '16 at 23:43
  • @O.O for what it's worth, I mentioned this in my answer, but if you do see this sort of error again, I'd definitely check in the stack trace. That would confirm that it was happening in the `Stream.WriteAsync` call, which would have been a hint to look there. Not a bad question, but just for future reference. – Matthew Haugen Jan 04 '16 at 23:45
  • Well, the stack trace is really not helpful in this case, it just shows one line which is the method that has the two lines above. – O.O Jan 04 '16 at 23:47