-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Conversation
…ObjectData and serialization constructors on non-serializable types. Also removes private serialization constructors and some unneeded code that was used to support serializing non-serializable types. A few tests testing GetObjectData implementations are also removed.
CC @danmosemsft @dotnet/corert-contrib |
It would be nice to have a message in the PNSE but I guess that would mean editing lots of resx's... |
@danmosemsft, that was roughly my thinking. There's really no reason to directly call GetObjectData or serialization constructors directly, so hopefully the standard message isn't too bad. |
I should have also clarified that if you actually try to (de)serialize the types, BinaryFormatter will throw a SerializationException with a message that says the type isn't serializable and won't try to call GetObjectData/serialization constructors. |
Sounds good. |
@@ -90,56 +90,12 @@ protected NameObjectCollectionBase(int capacity) | |||
|
|||
protected NameObjectCollectionBase(SerializationInfo info, StreamingContext context) | |||
{ | |||
_serializationInfo = info; | |||
throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume your tool to analyze common serialized types factored in base types? I'm wondering about how common it is to serialize a type derived from NameObjectCollectionBase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have (and can't quickly get) base type data. However, I did a quick GitHub search and found one instance of a serializable derived type. Additionally, since this is more or less a collection, it fits our general model, so I've added it back.
@@ -45,12 +45,6 @@ public TreeSubSet(SortedSet<T> Underlying, T Min, T Max, bool lowerBoundActive, | |||
VersionCheckImpl(); | |||
} | |||
|
|||
private TreeSubSet(SerializationInfo info, StreamingContext context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. TreeSubSet is a type derived from SortedSet and is returned from methods on SortedSet like GetViewBetween. As far as the consumer is concerned, it's a SortedSet... seems odd that some SortedSets from the framework could be serialized and others couldn't, depending on from which method you got them. Maybe it should be on the list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a ton of internal types like TreeSubSet (various KeyCollections, ValueCollections, Synchronized* etc). Do you think they all belong? Is TreeSubSet special in some way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expanding on that a little, I'd think having these sorts of types be serializable limits our internal implementation much more than the restrictions on field names. For example, lots of the older collections have various inner collections that could probably be replaced by generics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you know from your analysis whether the SortedSets people were serializing were TreeSubSet or not? We could start by not having them and only later opting them in if really important, it's just very difficult to reason about. "You can serialize SortedSet... but only if you didn't get it from these APIs on SortedSet."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we don't have that data. As a proxy, how's this? It looks like at least on NetFX, the only way to get a TreeSubSet is through GetViewBetween. According to apisof.net, GetViewBetween has very little usage. Additionally, serializing SortedSets is pretty rare compared to other concrete collections. The intersection of those two very small percentages is hopefully ~zero.
info.AddValue("instance", _instance); | ||
|
||
base.GetObjectData(info, context); | ||
throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be some inconsistency here. If the Exception-derived type was already overriding GetObjectData, then calling it will throw a PNSE, but if it wasn't already overriding GetObjectData, it won't throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good. Left a few comments. I'm not sure about throwing PNSE from overrides of Exception's GetObjectData; maybe we just leave those as nops, so that there's consistency with Exception-derived types that don't have additional state and thus don't override GetObjectData. Throwing from exposed deserialization ctors probably still makes sense.
@@ -263,7 +263,7 @@ internal virtual void AddOutcomeRegistrant(InternalTransaction tx, TransactionCo | |||
|
|||
internal virtual void GetObjectData(InternalTransaction tx, SerializationInfo serializationInfo, StreamingContext context) | |||
{ | |||
throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); | |||
throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't change this. If this "base" method executes, it is an invalid state error. That won't change even when we end up supporting serialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -1533,7 +1516,7 @@ internal override void CreateAbortingClone(InternalTransaction tx) | |||
|
|||
internal override void GetObjectData(InternalTransaction tx, SerializationInfo serializationInfo, StreamingContext context) | |||
{ | |||
throw CreateTransactionAbortedException(tx); | |||
throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is unfortunate that we would need to put this exception back when we start supporting serialization. Maybe comment out the old code and add the PlatformNotSupportedException so we don't need to go back and look for what the code used to be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that the methods in this file aren't ISerializable implementations. I've put their implementations back.
@@ -1683,7 +1666,7 @@ internal override void CheckForFinishedTransaction(InternalTransaction tx) | |||
|
|||
internal override void GetObjectData(InternalTransaction tx, SerializationInfo serializationInfo, StreamingContext context) | |||
{ | |||
throw TransactionInDoubtException.Create(TraceSourceType.TraceSourceBase, SR.TransactionIndoubt, tx._innerException, tx.DistributedTxId); | |||
throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about preserving previous code in a comment. It really applies to all the code that you have replaced with a PlatformNotSupportedException in System.Transactions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cc: @shmao |
@jimcarley , just so we have a better understanding, what's your plan on serialization in Transactions? More detail on the intention of these changes is in #19119 , but we don't want every single type that was serializable on NetFX to also be serializable on Core. Rather, we just want types that are both:
The data I collected for this change showed those that serializing Transactions is very rare (though it may happen). |
@morganbr You are correct that there are probably very few users that serialize Transaction objects. In Desktop, it is a way to get a transaction to flow from one process/AppDomain to another. There are other ways to do it by using the TransactionInterop methods in both processes. But Serialization seemed like a more "managed-friendly" way to do it. Transaction serialization requires distributed transaction support, thus the feature is currently not supported in Core. When a Tx is serialized, it is assumed that the intent is to give the transaction to another process/AppDomain. So we have to promote the transaction to become distributed because when the other process/AppDomain de-serializes the transaction, we now have two "participants" in the transaction and that requires a common commit coordinator, thus the need for a distributed transaction. Yes. SysTx on Core currently doesn't have functional parity with Desktop. But once we do implement distributed transactions, it could have parity. By removing serialization of transactions, you are removing that potential for functional parity. |
@jimcarley thanks for the explanation. You're certainly free to add serialization back when you support distributed transactions (with the requisite compatibility and maintenance burdens). |
public void TestConstructorWithSerialization() | ||
{ | ||
string msg = "MESSAGE"; | ||
Exception inner = new ArgumentException("whatever"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: would ArgumentException
still be [Serializable]
and implementing ISerializable
?
We have tests for DataContractSerializer serializing ArgumentException
. I wondered if it's still supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArgumentException isn't marked Serializable, but that test passes. Perhaps DCS is using POCO serialization with it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, interesting.. I just found that you've already removed [Serializable]
from ArgumentException
. I'm not sure why test test still passes. But I think it would fail if we change its GetObjectData
method.
… This makes them behave consistently with exceptions that didn't override GetObjectData.
@stephentoub I agree that throwing from GetObjectData on some exceptions, but not others is problematic. I've switched all of the overrides to simply call base instead. |
@morganbr If a type is |
@shmao in general, yes we are removing That said, we're certainly open to adding individual types if they clearly add user value. Feel free to file issues on types you believe are missing that you have evidence will be serialized. |
@dotnet-bot test Innerloop netfx Windows_NT Debug x86 Build and Test dotnet/roslyn#6358 |
@dotnet-bot test Innerloop Ubuntu14.04 Debug x64 Build and Test |
@dotnet-bot test Portable Linux x64 Release Build |
I'm unclear on why those legs aren't restarting, but I've verified the failures aren't related to this change. |
@dotnet-bot test Portable Linux x64 Release Build please |
@mmitche it won't restart portable leg. |
You can ignore the Nano failures. I fixed them. |
@mmitche also what does it mean that |
Stephen signed off. |
@danmosemsft Different trigger phrase. @dotnet-bot test portable linux debug pipeline. Want me to change the trigger phrases to be the same as the context? |
* Changes to throw PlatformNotSupportedException from ISerializable.GetObjectData and serialization constructors on non-serializable types. Also removes private serialization constructors and some unneeded code that was used to support serializing non-serializable types. A few tests testing GetObjectData implementations are also removed. * Address code review comments. * Change exceptions' GetObjectData to just call base rather than throw. This makes them behave consistently with exceptions that didn't override GetObjectData.
* Changes to throw PlatformNotSupportedException from ISerializable.GetObjectData and serialization constructors on non-serializable types. Also removes private serialization constructors and some unneeded code that was used to support serializing non-serializable types. A few tests testing GetObjectData implementations are also removed. * Address code review comments. * Change exceptions' GetObjectData to just call base rather than throw. This makes them behave consistently with exceptions that didn't override GetObjectData.
Can I ask a question on this? I found this today, when a |
@mgravell As you know BinaryFormatter is a dead-end technology for us because of maintenance and security reasons. We limited Stepping back, can you use a different serialization mechanism? This probably won't be the only way DataSet can fail to serialize this way. |
that's fair, @danmosemsft ; for now, I'm removing the |
Changes to throw PlatformNotSupportedException from ISerializable.GetObjectData and serialization constructors on non-Serializable types. Also removes private serialization constructors and some unneeded code that was used to support serializing non-serializable types. A few tests testing GetObjectData implementations are also removed.
This is progress toward #19119.