Throw when deserializing Exceptions by reference, and avoid reference tracking for all Exception-derived types (#8628) #8698
+175
−11
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This adds the two suggestions @ReubenBond makes in this issue.
Throw an exception when deserializing an Exception-derived type by reference
When we have an
Exception
-derived type that has been serialized as a reference, we should throw an exception when trying to deserialize it with theExceptionCodec
, rather than silently returningnull
in it's place.This scenario could (prior to this PR) come about when an exception is serialized using the code-gen serializer - say you add
[GenerateSerializer]
for your custom exception type, which is valid if you have certain fields you need serialized -, but this is stored in a field of typeException
. In that case, the code-gen serializer would by default (absent theSuppressReferenceTrackingAttribute
) serialize the exception as a reference if it appears more than once. However, on deserialization theExceptionCodec
will be used, and will refuse to resolve that reference. This is what made me initially raise #8628.Should that happen, this change just makes it clear in that case why deserialization fails, allowing the user to design around it.
Worth mentioning that I did have a test for this, but the next fix makes it much more difficult to test because it makes it harder to get into this scenario in the first place. I removed the test, as this is simple and exceptional logic, but it depends on how strict you want to be I think. It would be possible, but a pain to test.
Avoid reference tracking for all Exception-derived types in the first place
We take the behaviour that the
ExceptionCodec
has, which is to not serialize as instances of references when there are multiple references to the same Exception-derived object (reference tracking), and extend this for all Exception types, including those that don't use theExceptionCodec
(as described above). This should make less likely for us to get into the scenario above in the first place (that is if the system that serialized the message uses this change, if not then the the above change could still be relevant).The trickier part here was implementing this to also cover exceptions that are using a surrogate type. I didn't want to make the change for exceptions that have
[GenerateSerializer]
, but not have the same support for exceptions that have a surrogate, because I feel like that discrepancy would be more confusing than just not implementing this at all. To account for that, I also had to modify theSurrogateCodec
, as it's responsible for reference tracking for surrogates.I'm not sure how I feel about this change, it feels like it's baking in some knowledge about how the
ExceptionCodec
behaves into theSurrogateCodec
. If we do want to have thisExceptionCodec
behaviour for exceptions that aren't serialized by theExceptionCodec
however, I think this is necessary. I can completely see the argument though that this change adds too much complexity than it's worth. If you think that, then I'm happy to remove this part and just keep the previous change of throwing above instead.Microsoft Reviewers: Open in CodeFlow