1

My context is .NET PCL Profile111.

I try to use the DataContractSerializer with XmlDictionaryWriter for binary xml serialization. The problem I have is that after I dispose of the XmlDictionaryWriter the MemoryStream it was writing to gets closed. My code:

using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(outputStream))
{
    DataContractSerializer serializer = new DataContractSerializer(iObject.GetType());
    serializer.WriteObject(writer, iObject);
    writer.Flush();
}

//outputStream is closed now.

Documentation for the XmlWriterSettings says that the CloseOutput property is false by default.

I cannot use the overload for XmlDictionaryWriter.CreateBinaryWriter with ownsStream parameter because it is not available in PCL.

How can I make the XmlDictionaryWriter let the output Stream live after the XmlDictionaryWriter is disposed?

Zverev Evgeniy
  • 3,643
  • 25
  • 42
  • No idea how to achieve that, but you are mistaking one thing. The `CloseOutput` property is a setting for behaviour when `Close` method is called. Not `Dispose`. Probably the proper implementation of `IDisposable` in this class required to close the `Stream`. I would do it like that if I were the author. Also, why would you want to do that? Maybe there is an alternative way to achieve your desired effect. – Peuczynski May 19 '16 at 13:50
  • @Peuczyński I looked into the `XmlDictionaryWriter.Dispose` source code, it's inherited from `XmlWriter` and just calls the `Close` method inside. – Zverev Evgeniy May 19 '16 at 14:49
  • that's what I thought. You haven't told what are you trying to achieve. – Peuczynski May 19 '16 at 16:39
  • @Peuczyński Didn't I? This is the last phrase in the question: How can I make the XmlDictionaryWriter let the output Stream live? – Zverev Evgeniy May 19 '16 at 16:40
  • yup, but why? I don't think that will be possible so I want to know is there any other way to help you. Actually I have an idea, give me a few minutes – Peuczynski May 19 '16 at 16:43
  • @Peuczyński I need that because the serialization code is in one place and the stream is sent to a server via HTTP chunked transfer in another place. While the transfer is in place, I am going to append data into the stream. – Zverev Evgeniy May 19 '16 at 16:46
  • 1
    Why can't you just do [`XmlDictionaryWriter.CreateBinaryWriter(outputStream, null, null, false)`](https://msdn.microsoft.com/en-us/library/ms366447%28v=vs.110%29.aspx) ? – dbc May 19 '16 at 20:57
  • @dbc I could if I used full .NET, unfortunately this overload is unavailable in PCL. I am sorry I forgot to mention that I am limited to PCL, editing. – Zverev Evgeniy May 19 '16 at 21:00
  • That's surprising, since the [docs](https://msdn.microsoft.com/en-us/library/ms366447%28v=vs.110%29.aspx) say ***Portable Class Library**: Supported in: [portable .NET platforms](https://msdn.microsoft.com/en-us/library/gg597391.aspx)*. And the [reference source](http://referencesource.microsoft.com/#System.Runtime.Serialization/System/Xml/XmlDictionaryWriter.cs,a4762dfe30620647,references) doesn't show any conditional compilation. – dbc May 19 '16 at 21:03
  • @dbc Yeah. Looks like it is available in some PCL profiles, but not the one I am limited to. – Zverev Evgeniy May 19 '16 at 21:05
  • In that case, same advice as [here](https://stackoverflow.com/a/2666906) for `StreamWriter`: 1) flush but don't dispose the `XmlDictionaryWriter`. Unlike dispose, the finalize method will **not** dispose the underlying stream. 2) Create a wrapper for `Stream` that, when disposed, does not dispose the underlying stream. – dbc May 19 '16 at 21:09
  • 1
    @dbc Wrapper for the MemoryStream...that could work. Post this as an answer. Thanks. – Zverev Evgeniy May 19 '16 at 21:13

2 Answers2

2

Given that the overload XmlDictionaryWriter.CreateBinaryWriter(outputStream, null, null, false) is unavailable on your version of the PCL, you have a couple of options similar to those described in Is there any way to close a StreamWriter without closing its BaseStream?:

  1. You can flush but not dispose the XmlDictionaryWriter and leave it to the GC to clean up. Unlike the Dispose() method, the finalization method will not dispose the underlying stream.

  2. Create a wrapper Stream for your stream that, when disposed, does not dispose the underlying stream. E.g. Jon Skeet has NonClosingStreamWrapper in his MiscUtil.

Zverev Evgeniy
  • 3,643
  • 25
  • 42
dbc
  • 104,963
  • 20
  • 228
  • 340
0

I think the only option would be own implementation of XmlDictionaryWriter class.

That may seem hard, but all you have to do is create 2 new classes: PersistentXmlDictionaryWriter that is exactly like this one but instead of deriving from XmlWriter would derive from your new class PersisternXmlWriter that would be exaxtly like this one but you would change the Dispose method not to close the stream.

That should do it.

Peuczynski
  • 4,591
  • 1
  • 19
  • 33
  • This way I would fork myself out of updates made to the .NET BinaryXmlWriter. This is too dangerous thing to do in the matters of serialization. – Zverev Evgeniy May 19 '16 at 17:27
  • I don't see any other way to do it. If you are trying to do something that differs from the standard approach you have to create your own classes. I don't see any other possible solutions, and we'be both seen the source code. – Peuczynski May 19 '16 at 17:41
  • It is not something non-standard. Actually, `XmlDictionaryWriter.CreateBinaryWriter` has an overload with explicit flag i.e. ownsStream which does what I need but it is not available for PCL. – Zverev Evgeniy May 19 '16 at 18:25
  • When I said non-standard I meant that you're trying to change the natural behaviour of a class. It's like saying teaching cat to bark is not non-standard because another four legged animal has the ability. I hope I am clear this time. Basically, if you try to change some internal piece of code for a class, there is no other way. I tried playing with creating the class deriving from `Stream` and then providing it to the `XmlDictionaryWriter` but then I ended up with the problem of not having constructor that would accept `Stream` as argument and creating it would be basically writing new class. – Peuczynski May 20 '16 at 10:06
  • Again, XmlDictionaryWriter.CreateBinaryWriter is designed to treat the stream as an external asset. This is it's natural behaviour. Teaching a cat to bark is something very different. – Zverev Evgeniy May 20 '16 at 10:12
  • Now I get it. I was referring to the current state, and you were referring to how it suppose to work (as it isn't suppose to dispose of a provided stream). All clear now. – Peuczynski May 20 '16 at 10:24