Skip to content

Commit 2fb544c

Browse files
author
Prashanth Govindarajan
authored
BinaryFormatter deprecation for System.Configuration.ConfigurationManager (#50531)
* First cut of deprecating BF usage * Address comments * sq
1 parent 05a8c76 commit 2fb544c

10 files changed

+117
-13
lines changed

src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,7 @@ public enum SettingsSerializeAs
12131213
{
12141214
String = 0,
12151215
Xml = 1,
1216+
[System.ObsoleteAttribute(System.Obsoletions.BinaryFormatterMessage + @". Consider using Xml instead.", false)]
12161217
Binary = 2,
12171218
ProviderSpecific = 3,
12181219
}

src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</PropertyGroup>
1010
<ItemGroup>
1111
<Compile Include="System.Configuration.ConfigurationManager.cs" />
12+
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
1213
</ItemGroup>
1314
<ItemGroup>
1415
<ProjectReference Include="..\..\System.Security.Permissions\ref\System.Security.Permissions.csproj" />

src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@
250250
<Compile Include="System\UriIdnScope.cs" />
251251
<Compile Include="$(CommonPath)System\IO\TempFileCollection.cs"
252252
Link="Common\System\IO\TempFileCollection.cs" />
253+
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
253254
</ItemGroup>
254255
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
255256
<ProjectReference Include="$(LibrariesProjectRoot)System.Security.Cryptography.ProtectedData\src\System.Security.Cryptography.ProtectedData.csproj" />

src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/LocalFileSettingsProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,9 @@ private XmlNode SerializeToXmlElement(SettingsProperty setting, SettingsProperty
462462

463463
string serializedValue = value.SerializedValue as string;
464464

465+
#pragma warning disable CS0618 // Type or member is obsolete
465466
if (serializedValue == null && setting.SerializeAs == SettingsSerializeAs.Binary)
467+
#pragma warning restore CS0618 // Type or member is obsolete
466468
{
467469
// SettingsPropertyValue returns a byte[] in the binary serialization case. We need to
468470
// encode this - we use base64 since SettingsPropertyValue understands it and we won't have

src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SettingsProperty.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ namespace System.Configuration
55
{
66
public class SettingsProperty
77
{
8+
internal static bool EnableUnsafeBinaryFormatterInPropertyValueSerialization { get; } = AppContext.TryGetSwitch("System.Configuration.ConfigurationManager.EnableUnsafeBinaryFormatterInPropertyValueSerialization", out bool isEnabled) ? isEnabled : false;
9+
810
public virtual string Name { get; set; }
911
public virtual bool IsReadOnly { get; set; }
1012
public virtual object DefaultValue { get; set; }
@@ -37,7 +39,19 @@ public SettingsProperty(
3739
Provider = provider;
3840
IsReadOnly = isReadOnly;
3941
DefaultValue = defaultValue;
40-
SerializeAs = serializeAs;
42+
#pragma warning disable CS0618 // Type or member is obsolete
43+
if (serializeAs == SettingsSerializeAs.Binary)
44+
#pragma warning restore CS0618 // Type or member is obsolete
45+
{
46+
if (EnableUnsafeBinaryFormatterInPropertyValueSerialization)
47+
{
48+
SerializeAs = serializeAs;
49+
}
50+
else
51+
{
52+
throw new NotSupportedException(Obsoletions.BinaryFormatterMessage);
53+
}
54+
}
4155
Attributes = attributes;
4256
ThrowOnErrorDeserializing = throwOnErrorDeserializing;
4357
ThrowOnErrorSerializing = throwOnErrorSerializing;

src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SettingsPropertyValue.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ private object Deserialize()
8888
// Attempt 1: Try creating from SerializedValue
8989
if (SerializedValue != null)
9090
{
91+
bool throwBinaryFormatterDeprecationException = false;
9192
try
9293
{
9394
if (SerializedValue is string)
@@ -96,10 +97,16 @@ private object Deserialize()
9697
}
9798
else
9899
{
99-
using (MemoryStream ms = new MemoryStream((byte[])SerializedValue))
100+
if (SettingsProperty.EnableUnsafeBinaryFormatterInPropertyValueSerialization)
100101
{
101-
// Issue https://github.com/dotnet/runtime/issues/39295 tracks finding an alternative to BinaryFormatter
102-
value = (new BinaryFormatter()).Deserialize(ms);
102+
using (MemoryStream ms = new MemoryStream((byte[])SerializedValue))
103+
{
104+
value = (new BinaryFormatter()).Deserialize(ms);
105+
}
106+
}
107+
else
108+
{
109+
throwBinaryFormatterDeprecationException = true;
103110
}
104111
}
105112
}
@@ -124,6 +131,11 @@ private object Deserialize()
124131
}
125132
}
126133

134+
if (throwBinaryFormatterDeprecationException)
135+
{
136+
throw new NotSupportedException(Obsoletions.BinaryFormatterMessage);
137+
}
138+
127139
if (value != null && !Property.PropertyType.IsAssignableFrom(value.GetType())) // is it the correct type
128140
value = null;
129141
}
@@ -192,12 +204,20 @@ private static object GetObjectFromString(Type type, SettingsSerializeAs seriali
192204
// Convert based on the serialized type
193205
switch (serializeAs)
194206
{
207+
#pragma warning disable CS0618 // Type or member is obsolete
195208
case SettingsSerializeAs.Binary:
196-
byte[] buffer = Convert.FromBase64String(serializedValue);
197-
using (MemoryStream ms = new MemoryStream(buffer))
209+
#pragma warning restore CS0618 // Type or member is obsolete
210+
if (SettingsProperty.EnableUnsafeBinaryFormatterInPropertyValueSerialization)
211+
{
212+
byte[] buffer = Convert.FromBase64String(serializedValue);
213+
using (MemoryStream ms = new MemoryStream(buffer))
214+
{
215+
return (new BinaryFormatter()).Deserialize(ms);
216+
}
217+
}
218+
else
198219
{
199-
// Issue https://github.com/dotnet/runtime/issues/39295 tracks finding an alternative to BinaryFormatter
200-
return (new BinaryFormatter()).Deserialize(ms);
220+
throw new NotSupportedException(Obsoletions.BinaryFormatterMessage);
201221
}
202222
case SettingsSerializeAs.Xml:
203223
StringReader sr = new StringReader(serializedValue);
@@ -218,15 +238,25 @@ private object SerializePropertyValue()
218238
if (_value == null)
219239
return null;
220240

241+
#pragma warning disable CS0618 // Type or member is obsolete
221242
if (Property.SerializeAs != SettingsSerializeAs.Binary)
243+
#pragma warning restore CS0618 // Type or member is obsolete
244+
{
222245
return ConvertObjectToString(_value, Property.PropertyType, Property.SerializeAs, Property.ThrowOnErrorSerializing);
246+
}
223247

224-
using (MemoryStream ms = new MemoryStream())
248+
if (SettingsProperty.EnableUnsafeBinaryFormatterInPropertyValueSerialization)
249+
{
250+
using (MemoryStream ms = new MemoryStream())
251+
{
252+
BinaryFormatter bf = new BinaryFormatter();
253+
bf.Serialize(ms, _value);
254+
return ms.ToArray();
255+
}
256+
}
257+
else
225258
{
226-
// Issue https://github.com/dotnet/runtime/issues/39295 tracks finding an alternative to BinaryFormatter
227-
BinaryFormatter bf = new BinaryFormatter();
228-
bf.Serialize(ms, _value);
229-
return ms.ToArray();
259+
throw new NotSupportedException(Obsoletions.BinaryFormatterMessage);
230260
}
231261
}
232262

@@ -255,7 +285,9 @@ private static string ConvertObjectToString(object propertyValue, Type type, Set
255285

256286
xs.Serialize(sw, propertyValue);
257287
return sw.ToString();
288+
#pragma warning disable CS0618 // Type or member is obsolete
258289
case SettingsSerializeAs.Binary:
290+
#pragma warning restore CS0618 // Type or member is obsolete
259291
Debug.Fail("Should not have gotten here with Binary formatting");
260292
break;
261293
}

src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SettingsSerializeAs.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
5+
46
namespace System.Configuration
57
{
68
public enum SettingsSerializeAs
79
{
810
String = 0,
911
Xml = 1,
12+
[Obsolete(Obsoletions.BinaryFormatterMessage + @". Consider using Xml instead.", false)]
1013
Binary = 2,
1114
ProviderSpecific = 3
1215
}

src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Compile Include="System\Configuration\ApplicationSettingsBaseTests.cs" />
6363
<Compile Include="System\Configuration\AppSettingsReaderTests.cs" />
6464
<Compile Include="System\Configuration\AppSettingsTests.cs" />
65+
<Compile Include="System\Configuration\BinaryFormatterDeprecationTests.cs" />
6566
<Compile Include="System\Configuration\CallBackValidatorAttributeTests.cs" />
6667
<Compile Include="System\Configuration\ConfigPathUtilityTests.cs" />
6768
<Compile Include="System\Configuration\ConfigurationElementCollectionTests.cs" />

src/libraries/System.Configuration.ConfigurationManager/tests/System/Configuration/ApplicationSettingsBaseTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,9 @@ public void Reload_SimpleSettings_Ok()
213213
[ReadOnly(false)]
214214
[SettingsGroupName("TestGroup")]
215215
[SettingsProvider(typeof(TestProvider))]
216+
#pragma warning disable CS0618 // Type or member is obsolete
216217
[SettingsSerializeAs(SettingsSerializeAs.Binary)]
218+
#pragma warning restore CS0618 // Type or member is obsolete
217219
private class SettingsWithAttributes : ApplicationSettingsBase
218220
{
219221
[ApplicationScopedSetting]
@@ -243,7 +245,9 @@ public void SettingsProperty_SettingsWithAttributes_Ok()
243245
Assert.Equal(1, settings.Properties.Count);
244246
SettingsProperty property = settings.Properties["StringProperty"];
245247
Assert.Equal(typeof(TestProvider), property.Provider.GetType());
248+
#pragma warning disable CS0618 // Type or member is obsolete
246249
Assert.Equal(SettingsSerializeAs.Binary, property.SerializeAs);
250+
#pragma warning restore CS0618 // Type or member is obsolete
247251
}
248252

249253
[Fact]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Configuration;
6+
using Microsoft.DotNet.RemoteExecutor;
7+
using Xunit;
8+
9+
namespace System.ConfigurationTests
10+
{
11+
public class BinaryFormatterDeprecationTests
12+
{
13+
private static bool AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform => PlatformDetection.IsBinaryFormatterSupported && RemoteExecutor.IsSupported;
14+
15+
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "SettingsSerializeAs.Binary is deprecated only on Core")]
16+
[Fact]
17+
public void ThrowOnSettingsPropertyConstructorWithSettingsSerializeAsBinary()
18+
{
19+
#pragma warning disable CS0618 // Type or member is obsolete
20+
Assert.Throws<NotSupportedException>(() => new SettingsProperty("Binary", typeof(byte[]), null, false,"AString", SettingsSerializeAs.Binary, new SettingsAttributeDictionary(), true, true));
21+
#pragma warning restore CS0618 // Type or member is obsolete
22+
}
23+
24+
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "SettingsSerializeAs.Binary is deprecated only on Core")]
25+
[ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))]
26+
public void SerializeAndDeserializeWithSettingsSerializeAsBinary()
27+
{
28+
RemoteInvokeOptions options = new RemoteInvokeOptions();
29+
options.RuntimeConfigurationOptions.Add("System.Configuration.ConfigurationManager.EnableUnsafeBinaryFormatterInPropertyValueSerialization", bool.TrueString);
30+
RemoteExecutor.Invoke(() =>
31+
{
32+
#pragma warning disable CS0618 // Type or member is obsolete
33+
SettingsProperty property = new SettingsProperty("Binary", typeof(string), null, false, "AString", SettingsSerializeAs.Binary, new SettingsAttributeDictionary(), true, true);
34+
#pragma warning restore CS0618 // Type or member is obsolete
35+
SettingsPropertyValue value = new SettingsPropertyValue(property);
36+
value.PropertyValue = "AString"; // To force _changedSinceLastSerialized to true to allow for serialization in the next call
37+
object serializedValue = value.SerializedValue;
38+
Assert.NotNull(serializedValue);
39+
value.Deserialized = false;
40+
object deserializedValue = value.PropertyValue;
41+
Assert.Equal("AString", deserializedValue);
42+
}, options).Dispose();
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)