diff --git a/src/csharp/Extensions/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest.csproj b/src/csharp/Extensions/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest.csproj
index 5128070fb..d3c63bd22 100644
--- a/src/csharp/Extensions/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest.csproj
+++ b/src/csharp/Extensions/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest/Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest.csproj
@@ -3,7 +3,6 @@
net8.0
Microsoft.Spark.Extensions.DotNet.Interactive.UnitTest
- true
diff --git a/src/csharp/Microsoft.Spark.E2ETest.ExternalLibrary/ExternalClass.cs b/src/csharp/Microsoft.Spark.E2ETest.ExternalLibrary/ExternalClass.cs
index db525172d..086a38e4a 100644
--- a/src/csharp/Microsoft.Spark.E2ETest.ExternalLibrary/ExternalClass.cs
+++ b/src/csharp/Microsoft.Spark.E2ETest.ExternalLibrary/ExternalClass.cs
@@ -9,11 +9,11 @@ namespace Microsoft.Spark.E2ETest.ExternalLibrary
[Serializable]
public class ExternalClass
{
- private string _s;
+ private string s;
public ExternalClass(string s)
{
- _s = s;
+ this.s = s;
}
public static string HelloWorld()
@@ -23,7 +23,7 @@ public static string HelloWorld()
public string Concat(string s)
{
- return _s + s;
+ return this.s + s;
}
}
}
diff --git a/src/csharp/Microsoft.Spark.E2ETest/IpcTests/BroadcastTests.cs b/src/csharp/Microsoft.Spark.E2ETest/IpcTests/BroadcastTests.cs
index e0443f04c..e9e5f98a5 100644
--- a/src/csharp/Microsoft.Spark.E2ETest/IpcTests/BroadcastTests.cs
+++ b/src/csharp/Microsoft.Spark.E2ETest/IpcTests/BroadcastTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using MessagePack;
using Microsoft.Spark.Sql;
using Xunit;
using static Microsoft.Spark.Sql.Functions;
@@ -12,10 +13,11 @@ public class TestBroadcastVariable
public int IntValue { get; private set; }
public string StringValue { get; private set; }
- public TestBroadcastVariable(int intVal, string stringVal)
+ [SerializationConstructor]
+ public TestBroadcastVariable(int intValue, string stringValue)
{
- IntValue = intVal;
- StringValue = stringVal;
+ IntValue = intValue;
+ StringValue = stringValue;
}
}
diff --git a/src/csharp/Microsoft.Spark.E2ETest/Microsoft.Spark.E2ETest.csproj b/src/csharp/Microsoft.Spark.E2ETest/Microsoft.Spark.E2ETest.csproj
index e242da0d0..8af2fae53 100644
--- a/src/csharp/Microsoft.Spark.E2ETest/Microsoft.Spark.E2ETest.csproj
+++ b/src/csharp/Microsoft.Spark.E2ETest/Microsoft.Spark.E2ETest.csproj
@@ -1,7 +1,6 @@
net8.0
- true
diff --git a/src/csharp/Microsoft.Spark.UnitTest/BinarySerDeTests.cs b/src/csharp/Microsoft.Spark.UnitTest/BinarySerDeTests.cs
new file mode 100644
index 000000000..7c0a2642a
--- /dev/null
+++ b/src/csharp/Microsoft.Spark.UnitTest/BinarySerDeTests.cs
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using MessagePack;
+using Microsoft.Spark.Utils;
+using Xunit;
+
+namespace Microsoft.Spark.UnitTest;
+
+[Collection("Spark Unit Tests")]
+public class BinarySerDeTests
+{
+ [Theory]
+ [InlineData(42)]
+ [InlineData("Test")]
+ [InlineData(99.99)]
+ public void Serialize_ShouldWriteObjectToStream(object input)
+ {
+ using var memoryStream = new MemoryStream();
+ BinarySerDe.Serialize(memoryStream, input);
+ memoryStream.Position = 0;
+
+ var deserializedObject = MessagePackSerializer.Typeless.Deserialize(memoryStream);
+
+ Assert.Equal(input, deserializedObject);
+ }
+
+ [Fact]
+ public void Deserialize_ShouldReturnExpectedObject_WhenTypeMatches()
+ {
+ var employee = new Employee { Id = 101, Name = "John Doe" };
+ using var memoryStream = new MemoryStream();
+ MessagePackSerializer.Typeless.Serialize(memoryStream, employee);
+ memoryStream.Position = 0;
+
+ var result = BinarySerDe.Deserialize(memoryStream);
+
+ Assert.Equal(employee.Id, result.Id);
+ Assert.Equal(employee.Name, result.Name);
+ }
+
+ [Fact]
+ public void Deserialize_ShouldThrowInvalidCastEx_WhenTypeDoesNotMatch()
+ {
+ var employee = new Employee { Id = 101, Name = "John Doe" };
+ using var memoryStream = new MemoryStream();
+ MessagePackSerializer.Typeless.Serialize(memoryStream, employee);
+ memoryStream.Position = 0;
+
+ var action = () => BinarySerDe.Deserialize(memoryStream);
+
+ Assert.Throws(action);
+ }
+
+ [Fact]
+ public void Serialize_CustomFunctionAndObject_ShouldBeSerializable()
+ {
+ var department = new Department { Name = "HR", EmployeeCount = 27 };
+ var employeeStub = new Employee
+ {
+ EmbeddedObject = department,
+ Id = 11,
+ Name = "Derek",
+ };
+ using var memoryStream = new MemoryStream();
+ MessagePackSerializer.Typeless.Serialize(memoryStream, employeeStub);
+ memoryStream.Position = 0;
+
+ var deserializedCalculation = BinarySerDe.Deserialize(memoryStream);
+
+ Assert.IsType(deserializedCalculation.EmbeddedObject);
+ Assert.Equal(27, ((Department)deserializedCalculation.EmbeddedObject).EmployeeCount);
+ Assert.Equal("HR", ((Department)deserializedCalculation.EmbeddedObject).Name);
+ }
+
+ [Fact]
+ public void Serialize_ClassWithoutSerializableAttribute_ShouldThrowException()
+ {
+ var nonSerializableClass = new NonSerializableClass { Value = 123 };
+ using var memoryStream = new MemoryStream();
+ BinarySerDe.Serialize(memoryStream, nonSerializableClass);
+ memoryStream.Position = 0;
+
+ Assert.Throws(() => BinarySerDe.Deserialize(memoryStream));
+ }
+
+ [Fact]
+ public void Serialize_CollectionAndDictionary_ShouldBeSerializable()
+ {
+ var list = new List { 1, 2, 3 };
+ var dictionary = new Dictionary { { "one", 1 }, { "two", 2 } };
+
+ using var memoryStream = new MemoryStream();
+ BinarySerDe.Serialize(memoryStream, list);
+ memoryStream.Position = 0;
+ var deserializedList = MessagePackSerializer.Typeless.Deserialize(memoryStream) as List;
+
+ Assert.Equal(list, deserializedList);
+
+ memoryStream.SetLength(0);
+ BinarySerDe.Serialize(memoryStream, dictionary);
+ memoryStream.Position = 0;
+ var deserializedDictionary = MessagePackSerializer.Typeless.Deserialize(memoryStream) as Dictionary;
+
+ Assert.Equal(dictionary, deserializedDictionary);
+ }
+
+ [Fact]
+ public void Serialize_PolymorphicObject_ShouldBeSerializable()
+ {
+ Employee manager = new Manager { Id = 1, Name = "Alice", Role = "Account manager" };
+ using var memoryStream = new MemoryStream();
+ BinarySerDe.Serialize(memoryStream, manager);
+ memoryStream.Position = 0;
+
+ var deserializedEmployee = BinarySerDe.Deserialize(memoryStream);
+
+ Assert.IsType(deserializedEmployee);
+ Assert.Equal("Alice", deserializedEmployee.Name);
+ Assert.Equal("Account manager", ((Manager)deserializedEmployee).Role);
+ }
+
+ [Serializable]
+ private class Employee
+ {
+ public int Id { get; set; }
+
+ public string Name { get; set; }
+
+ public object EmbeddedObject { get; set; }
+ }
+
+ [Serializable]
+ private class Department
+ {
+ public string Name { get; set; }
+ public int EmployeeCount { get; set; }
+ }
+
+ [Serializable]
+ private class Manager : Employee
+ {
+ public string Role { get; set; }
+ }
+
+ private class NonSerializableClass
+ {
+ public int Value { get; init; }
+ }
+}
diff --git a/src/csharp/Microsoft.Spark.UnitTest/Microsoft.Spark.UnitTest.csproj b/src/csharp/Microsoft.Spark.UnitTest/Microsoft.Spark.UnitTest.csproj
index e635434ae..deb63cd3d 100644
--- a/src/csharp/Microsoft.Spark.UnitTest/Microsoft.Spark.UnitTest.csproj
+++ b/src/csharp/Microsoft.Spark.UnitTest/Microsoft.Spark.UnitTest.csproj
@@ -3,7 +3,6 @@
net8.0
Microsoft.Spark.UnitTest
- true
diff --git a/src/csharp/Microsoft.Spark.UnitTest/UdfSerDeTests.cs b/src/csharp/Microsoft.Spark.UnitTest/UdfSerDeTests.cs
index b655fdf1b..ba6ebc0b9 100644
--- a/src/csharp/Microsoft.Spark.UnitTest/UdfSerDeTests.cs
+++ b/src/csharp/Microsoft.Spark.UnitTest/UdfSerDeTests.cs
@@ -5,7 +5,6 @@
using System;
using System.IO;
using System.Reflection;
-using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Spark.Utils;
using Xunit;
@@ -17,21 +16,21 @@ public class UdfSerDeTests
[Serializable]
private class TestClass
{
- private readonly string _str;
+ private readonly string str;
- public TestClass(string s)
+ public TestClass(string str)
{
- _str = s;
+ this.str = str;
}
public string Concat(string s)
{
- if (_str == null)
+ if (str == null)
{
return s + s;
}
- return _str + s;
+ return str + s;
}
public override bool Equals(object obj)
@@ -43,7 +42,7 @@ public override bool Equals(object obj)
return false;
}
- return _str == that._str;
+ return str == that.str;
}
public override int GetHashCode()
@@ -149,16 +148,13 @@ private Delegate SerDe(Delegate udf)
return Deserialize(Serialize(udf));
}
-#pragma warning disable SYSLIB0011 // Type or member is obsolete
- // TODO: Replace BinaryFormatter with a new, secure serializer.
private byte[] Serialize(Delegate udf)
{
UdfSerDe.UdfData udfData = UdfSerDe.Serialize(udf);
using (var ms = new MemoryStream())
{
- var bf = new BinaryFormatter();
- bf.Serialize(ms, udfData);
+ BinarySerDe.Serialize(ms, udfData);
return ms.ToArray();
}
}
@@ -167,11 +163,9 @@ private Delegate Deserialize(byte[] serializedUdf)
{
using (var ms = new MemoryStream(serializedUdf, false))
{
- var bf = new BinaryFormatter();
- UdfSerDe.UdfData udfData = (UdfSerDe.UdfData)bf.Deserialize(ms);
+ var udfData = BinarySerDe.Deserialize(ms);
return UdfSerDe.Deserialize(udfData);
}
}
-#pragma warning restore
}
}
diff --git a/src/csharp/Microsoft.Spark.Worker.UnitTest/CommandExecutorTests.cs b/src/csharp/Microsoft.Spark.Worker.UnitTest/CommandExecutorTests.cs
index cc43b9f37..e3082d8db 100644
--- a/src/csharp/Microsoft.Spark.Worker.UnitTest/CommandExecutorTests.cs
+++ b/src/csharp/Microsoft.Spark.Worker.UnitTest/CommandExecutorTests.cs
@@ -8,7 +8,6 @@
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Threading.Tasks;
using Apache.Arrow;
@@ -1049,10 +1048,8 @@ public void TestRDDCommandExecutor(Version sparkVersion, IpcOptions ipcOptions)
using var inputStream = new MemoryStream();
using var outputStream = new MemoryStream();
-#pragma warning disable SYSLIB0011 // Type or member is obsolete
+
// Write test data to the input stream.
- var formatter = new BinaryFormatter();
-#pragma warning restore SYSLIB0011 // Type or member is obsolete
var memoryStream = new MemoryStream();
var inputs = new int[] { 0, 1, 2, 3, 4 };
@@ -1061,10 +1058,7 @@ public void TestRDDCommandExecutor(Version sparkVersion, IpcOptions ipcOptions)
foreach (int input in inputs)
{
memoryStream.Position = 0;
-#pragma warning disable SYSLIB0011 // Type or member is obsolete
- // TODO: Replace BinaryFormatter with a new, secure serializer.
- formatter.Serialize(memoryStream, input);
-#pragma warning restore SYSLIB0011 // Type or member is obsolete
+ BinarySerDe.Serialize(memoryStream, input);
values.Add(memoryStream.ToArray());
}
@@ -1094,12 +1088,9 @@ public void TestRDDCommandExecutor(Version sparkVersion, IpcOptions ipcOptions)
for (int i = 0; i < inputs.Length; ++i)
{
Assert.True(SerDe.ReadInt32(outputStream) > 0);
-#pragma warning disable SYSLIB0011 // Type or member is obsolete
- // TODO: Replace BinaryFormatter with a new, secure serializer.
Assert.Equal(
mapUdf(i),
- formatter.Deserialize(outputStream));
-#pragma warning restore SYSLIB0011 // Type or member is obsolete
+ BinarySerDe.Deserialize