Skip to content

Commit

Permalink
Throw PlatformNotSupportedException in netstandard1.3 (#396)
Browse files Browse the repository at this point in the history
- stop trying to use DCS in the JSON and XML formatters
- if `UseDataContractSerializer` or `!UseXmlSerializer`:
  - `CanReadType(...)` and `CanWriteType(...)` always return `false`
  - `ReadFromStreamAsync(...)` and `WriteToStreamAsync(...)` always `throw`
- change default XML formatter configuration to use `XmlSerializer`
- adjust and disable tests in reaction
- add tests of new `netstandard1.3` behavior
- nits:
  - correct namespace of `SerializerConsistencyTests`; was alone in previous namespace
  - s/DataContractFormatter/XmlSerializerFormatter/ to reflect actual `XmlMediaTypeFormatter` test actions
  • Loading branch information
dougbu authored Mar 7, 2023
1 parent cb7628f commit 6451d77
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 53 deletions.
39 changes: 23 additions & 16 deletions src/System.Net.Http.Formatting/Formatting/JsonMediaTypeFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
using System.Diagnostics.Contracts;
using System.IO;
using System.Net.Http.Headers;
#if !NETSTANDARD1_3 // Unnecessary when targeting netstandard1.3.
using System.Net.Http.Internal;
#endif
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -214,20 +216,15 @@ public override object ReadFromStream(Type type, Stream readStream, Encoding eff
{
DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type);

// JsonReaderWriterFactory is internal, CreateTextReader only supports auto-detecting the encoding
// and auto-detection fails in some cases for the netstandard1.3 project. In addition, DCS encodings are
// limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read.
Stream innerStream = string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ?
#if NETSTANDARD1_3 // Unreachable when targeting netstandard1.3. Return just to satisfy the compiler.
return null;
#else
// DCS encodings are limited to UTF8, UTF16BE, and UTF16LE. Convert to UTF8 as we read.
Stream innerStream =
string.Equals(effectiveEncoding.WebName, Utf8Encoding.WebName, StringComparison.OrdinalIgnoreCase) ?
new NonClosingDelegatingStream(readStream) :
new TranscodingStream(readStream, effectiveEncoding, Utf8Encoding, leaveOpen: true);

#if NETSTANDARD1_3
using (innerStream)
{
// Unfortunately, we're ignoring _readerQuotas.
return dataContractSerializer.ReadObject(innerStream);
}
#else
// XmlDictionaryReader will always dispose of innerStream when we dispose of the reader.
using XmlDictionaryReader reader =
JsonReaderWriterFactory.CreateJsonReader(innerStream, Utf8Encoding, _readerQuotas, onClose: null);
Expand Down Expand Up @@ -314,10 +311,8 @@ private void WriteObject(Stream stream, Type type, object value)
{
DataContractJsonSerializer dataContractSerializer = GetDataContractSerializer(type);

#if !NETSTANDARD1_3 // Unreachable when targeting netstandard1.3.
// Do not dispose of the stream. WriteToStream handles that where it's needed.
#if NETSTANDARD1_3
dataContractSerializer.WriteObject(stream, value);
#else
using XmlWriter writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Utf8Encoding, ownsStream: false);
dataContractSerializer.WriteObject(writer, value);
#endif
Expand All @@ -328,15 +323,26 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool
{
Contract.Assert(type != null);

#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3
if (throwOnError)
{
throw new PlatformNotSupportedException(Error.Format(
Properties.Resources.JsonMediaTypeFormatter_DCS_NotSupported,
nameof(UseDataContractJsonSerializer)));
}
else
{
return null;
}
#else

DataContractJsonSerializer serializer = null;
Exception exception = null;

try
{
#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3
// Verify that type is a valid data contract by forcing the serializer to try to create a data contract
FormattingUtilities.XsdDataContractExporter.GetRootElementName(type);
#endif

serializer = CreateDataContractSerializer(type);
}
Expand All @@ -362,6 +368,7 @@ private DataContractJsonSerializer CreateDataContractSerializer(Type type, bool
}

return serializer;
#endif
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,11 @@ private static IEnumerable<MediaTypeFormatter> CreateDefaultFormatters()
return new MediaTypeFormatter[]
{
new JsonMediaTypeFormatter(),
new XmlMediaTypeFormatter(),
new XmlMediaTypeFormatter()
#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3. Cannot use DCS.
{ UseXmlSerializer = true }
#endif
,
new FormUrlEncodedMediaTypeFormatter()
};
}
Expand Down
22 changes: 19 additions & 3 deletions src/System.Net.Http.Formatting/Formatting/XmlMediaTypeFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,23 @@ public object InvokeGetSerializer(Type type, object value, HttpContent content)
private object CreateDefaultSerializer(Type type, bool throwOnError)
{
Contract.Assert(type != null, "type cannot be null.");

#if NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3
if (!UseXmlSerializer)
{
if (throwOnError)
{
throw new PlatformNotSupportedException(Error.Format(
Properties.Resources.XmlMediaTypeFormatter_DCS_NotSupported,
nameof(UseXmlSerializer)));
}
else
{
return null;
}
}
#endif

Exception exception = null;
object serializer = null;

Expand All @@ -522,13 +539,12 @@ private object CreateDefaultSerializer(Type type, bool throwOnError)
}
else
{
#if !NETSTANDARD1_3 // XsdDataContractExporter is not supported in netstandard1.3
// REVIEW: Is there something comparable in WinRT?
#if !NETSTANDARD1_3 // Unreachable when targeting netstandard1.3.
// Verify that type is a valid data contract by forcing the serializer to try to create a data contract
FormattingUtilities.XsdDataContractExporter.GetRootElementName(type);
#endif

serializer = CreateDataContractSerializer(type);
#endif
}
}
catch (Exception caught)
Expand Down
18 changes: 18 additions & 0 deletions src/System.Net.Http.Formatting/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/System.Net.Http.Formatting/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,10 @@
<data name="ObjectDisposed_StreamClosed" xml:space="preserve">
<value>Cannot access a closed stream.</value>
</data>
<data name="JsonMediaTypeFormatter_DCS_NotSupported" xml:space="preserve">
<value>Unable to validate types on this platform when {0} is 'true'. Please reset {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable.</value>
</data>
<data name="XmlMediaTypeFormatter_DCS_NotSupported" xml:space="preserve">
<value>Unable to validate types on this platform when {0} is 'false'. Please set {0} or move to a supported platform, one where the 'netstandard2.0' assembly is usable.</value>
</data>
</root>
Loading

0 comments on commit 6451d77

Please sign in to comment.