Skip to content

Commit

Permalink
Obsolete and put SerializationFormat.Binary behind an appcontext swit…
Browse files Browse the repository at this point in the history
…ch (#65139)

Part of #39289
  • Loading branch information
roji authored Feb 12, 2022
1 parent 20e8f90 commit bda8c91
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/libraries/Common/src/System/Obsoletions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,8 @@ internal static class Obsoletions

internal const string AssemblyNameMembersMessage = "AssemblyName members HashAlgorithm, ProcessorArchitecture, and VersionCompatibility are obsolete and not supported.";
internal const string AssemblyNameMembersDiagId = "SYSLIB0037";

internal const string SystemDataSerializationFormatBinaryMessage = "SerializationFormat.Binary is obsolete and should not be used. See https://aka.ms/serializationformat-binary-obsolete for more information.";
internal const string SystemDataSerializationFormatBinaryDiagId = "SYSLIB0038";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);SYSLIB0038</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.Data.Common.TypeForwards.cs" />
Expand Down Expand Up @@ -301,6 +302,8 @@
<Compile Include="System\Data\SQLTypes\SQLBytes.cs" />
<Compile Include="System\Data\ProviderBase\DataReaderContainer.cs" />
<Compile Include="System\Data\ProviderBase\SchemaMapping.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs"
Link="Common\System\Obsoletions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CoreLibProject)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,8 @@ public static Exception RemovePrimaryKey(DataTable table) => table.TableName.Len
public static Exception CannotChangeCaseLocale(Exception? innerException) => _Argument(SR.DataSet_CannotChangeCaseLocale, innerException);
public static Exception CannotChangeSchemaSerializationMode() => _InvalidOperation(SR.DataSet_CannotChangeSchemaSerializationMode);
public static Exception InvalidSchemaSerializationMode(Type enumType, string mode) => _InvalidEnumArgumentException(SR.Format(SR.ADP_InvalidEnumerationValue, enumType.Name, mode));
public static Exception InvalidRemotingFormat(SerializationFormat mode) => _InvalidEnumArgumentException<SerializationFormat>(mode);
public static Exception InvalidRemotingFormat(SerializationFormat mode) => _InvalidEnumArgumentException(mode);
public static Exception SerializationFormatBinaryNotSupported() => _InvalidEnumArgumentException(SerializationFormat.Binary);

//
// DataTable and DataTableCollection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ namespace System.Data
public enum SerializationFormat
{
Xml = 0,

[Obsolete(
Obsoletions.SystemDataSerializationFormatBinaryMessage,
DiagnosticId = Obsoletions.SystemDataSerializationFormatBinaryDiagId)]
Binary = 1
}
}
22 changes: 20 additions & 2 deletions src/libraries/System.Data.Common/src/System/Data/DataSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,22 @@ public SerializationFormat RemotingFormat
get { return _remotingFormat; }
set
{
if (value != SerializationFormat.Binary && value != SerializationFormat.Xml)
switch (value)
{
throw ExceptionBuilder.InvalidRemotingFormat(value);
case SerializationFormat.Xml:
break;

case SerializationFormat.Binary:
if (LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
break;
}
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();

default:
throw ExceptionBuilder.InvalidRemotingFormat(value);
}

_remotingFormat = value;
// this property is inherited to DataTable from DataSet.So we set this value to DataTable also
for (int i = 0; i < Tables.Count; i++)
Expand Down Expand Up @@ -255,6 +267,12 @@ protected DataSet(SerializationInfo info, StreamingContext context, bool Constru
}
}

if (remotingFormat == SerializationFormat.Binary &&
!LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();
}

if (schemaSerializationMode == SchemaSerializationMode.ExcludeSchema)
{
InitializeDerivedDataSet();
Expand Down
22 changes: 20 additions & 2 deletions src/libraries/System.Data.Common/src/System/Data/DataTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ protected DataTable(SerializationInfo info, StreamingContext context) : this()
}
}

if (remotingFormat == SerializationFormat.Binary &&
!LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();
}

DeserializeDataTable(info, context, isSingleTable, remotingFormat);
}

Expand Down Expand Up @@ -1127,10 +1133,22 @@ public SerializationFormat RemotingFormat
get { return _remotingFormat; }
set
{
if (value != SerializationFormat.Binary && value != SerializationFormat.Xml)
switch (value)
{
throw ExceptionBuilder.InvalidRemotingFormat(value);
case SerializationFormat.Xml:
break;

case SerializationFormat.Binary:
if (LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
break;
}
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();

default:
throw ExceptionBuilder.InvalidRemotingFormat(value);
}

// table can not have different format than its dataset, unless it is stand alone datatable
if (DataSet != null && value != DataSet.RemotingFormat)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ namespace System
internal static partial class LocalAppContextSwitches
{
private static int s_allowArbitraryTypeInstantiation;
private static int s_allowUnsafeSerializationFormatBinary;

public static bool AllowArbitraryTypeInstantiation
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetCachedSwitchValue("Switch.System.Data.AllowArbitraryDataSetTypeInstantiation", ref s_allowArbitraryTypeInstantiation);
}

public static bool AllowUnsafeSerializationFormatBinary
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetCachedSwitchValue("Switch.System.Data.AllowUnsafeSerializationFormatBinary", ref s_allowUnsafeSerializationFormatBinary);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<NoWarn>$(NoWarn),0168,0169,0414,0219,0649</NoWarn>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>
<ItemGroup>
<Compile Include="System\Data\Common\DataColumnMappingTest.cs" />
Expand Down
38 changes: 38 additions & 0 deletions src/libraries/System.Data.Common/tests/System/Data/DataSetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System.ComponentModel;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
Expand All @@ -36,6 +37,7 @@
using System.Globalization;
using System.Text;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
using System.Tests;
Expand Down Expand Up @@ -1579,6 +1581,42 @@ public void WriteXmlEscapeName()
writer.GetStringBuilder().ToString()));
}

[Fact]
public void SerializationFormat_Binary_does_not_work_by_default()
{
DataSet ds = new DataSet();
Assert.Throws<InvalidEnumArgumentException>(() => ds.RemotingFormat = SerializationFormat.Binary);
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void SerializationFormat_Binary_works_with_appconfig_switch()
{
RemoteExecutor.Invoke(RunTest).Dispose();

static void RunTest()
{
AppContext.SetSwitch("Switch.System.Data.AllowUnsafeSerializationFormatBinary", true);

DataSet ds = new DataSet();
DataTable dt = new DataTable("MyTable");
DataColumn dc = new DataColumn("dc", typeof(int));
dt.Columns.Add(dc);
ds.Tables.Add(dt);
ds.RemotingFormat = SerializationFormat.Binary;

DataSet dsDeserialized;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, ds);
ms.Seek(0, SeekOrigin.Begin);
dsDeserialized = (DataSet)bf.Deserialize(ms);
}

Assert.Equal(dc.DataType, dsDeserialized.Tables[0].Columns[0].DataType);
}
}

#region DataSet.CreateDataReader Tests and DataSet.Load Tests

private DataSet _ds;
Expand Down
40 changes: 28 additions & 12 deletions src/libraries/System.Data.Common/tests/System/Data/DataTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Globalization;
Expand Down Expand Up @@ -376,23 +377,38 @@ public void SelectOperators()

}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBinaryFormatterSupported), nameof(PlatformDetection.IsNotInvariantGlobalization))]
public void DataColumnTypeSerialization()
[Fact]
public void SerializationFormat_Binary_does_not_work_by_default()
{
DataTable dt = new DataTable("MyTable");
DataColumn dc = new DataColumn("dc", typeof(int));
dt.Columns.Add(dc);
dt.RemotingFormat = SerializationFormat.Binary;
Assert.Throws<InvalidEnumArgumentException>(() => dt.RemotingFormat = SerializationFormat.Binary);
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void SerializationFormat_Binary_works_with_appconfig_switch()
{
RemoteExecutor.Invoke(RunTest).Dispose();

DataTable dtDeserialized;
using (MemoryStream ms = new MemoryStream())
static void RunTest()
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, dt);
ms.Seek(0, SeekOrigin.Begin);
dtDeserialized = (DataTable)bf.Deserialize(ms);
AppContext.SetSwitch("Switch.System.Data.AllowUnsafeSerializationFormatBinary", true);

DataTable dt = new DataTable("MyTable");
DataColumn dc = new DataColumn("dc", typeof(int));
dt.Columns.Add(dc);
dt.RemotingFormat = SerializationFormat.Binary;

DataTable dtDeserialized;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, dt);
ms.Seek(0, SeekOrigin.Begin);
dtDeserialized = (DataTable)bf.Deserialize(ms);
}

Assert.Equal(dc.DataType, dtDeserialized.Columns[0].DataType);
}
Assert.Equal(dc.DataType, dtDeserialized.Columns[0].DataType);
}

[Fact]
Expand Down

0 comments on commit bda8c91

Please sign in to comment.