diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
index 2488451cec..27318ba3ef 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -277,6 +277,9 @@
Microsoft\Data\SqlClient\SqlEnums.cs
+
+ Microsoft\Data\SqlClient\SqlError.cs
+
Microsoft\Data\SqlClient\SqlErrorCollection.cs
@@ -570,7 +573,6 @@
-
Microsoft\Data\SqlClient\SqlEnclaveSession.cs
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlError.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlError.cs
deleted file mode 100644
index 967cf6acf8..0000000000
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlError.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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;
-
-namespace Microsoft.Data.SqlClient
-{
- ///
- public sealed class SqlError
- {
- internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, uint win32ErrorCode, Exception exception = null)
- : this(infoNumber, errorState, errorClass, server, errorMessage, procedure, lineNumber, exception)
- {
- Win32ErrorCode = (int)win32ErrorCode;
- }
-
- internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, Exception exception = null)
- {
- Number = infoNumber;
- State = errorState;
- Class = errorClass;
- Server = server;
- Message = errorMessage;
- Procedure = procedure;
- LineNumber = lineNumber;
- Win32ErrorCode = 0;
- Exception = exception;
- if (errorClass != 0)
- {
- SqlClientEventSource.Log.TryTraceEvent("SqlError.ctor | ERR | Info Number {0}, Error State {1}, Error Class {2}, Error Message '{3}', Procedure '{4}', Line Number {5}", infoNumber, (int)errorState, (int)errorClass, errorMessage, procedure ?? "None", (int)lineNumber);
- }
- }
-
- ///
- // There is no exception stack included because the correct exception stack is only available
- // on SqlException, and to obtain that the SqlError would have to have backpointers all the
- // way back to SqlException. If the user needs a call stack, they can obtain it on SqlException.
- public override string ToString()
- {
- return typeof(SqlError).ToString() + ": " + Message; // since this is sealed so we can change GetType to typeof
- }
-
- ///
- public string Source { get; private set; } = TdsEnums.SQL_PROVIDER_NAME;
-
- ///
- public int Number { get; private set; }
-
- ///
- public byte State { get; private set; }
-
- ///
- public byte Class { get; private set; }
-
- ///
- public string Server { get; private set; }
-
- ///
- public string Message { get; private set; }
-
- ///
- public string Procedure { get; private set; }
-
- ///
- public int LineNumber { get; private set; }
-
- internal int Win32ErrorCode { get; private set; }
-
- internal Exception Exception { get; private set; }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
index 2746f9c688..023c6cc22b 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj
@@ -366,6 +366,9 @@
Microsoft\Data\SqlClient\SqlEnums.cs
+
+ Microsoft\Data\SqlClient\SqlError.cs
+
Microsoft\Data\SqlClient\SqlErrorCollection.cs
@@ -562,7 +565,6 @@
-
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlError.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlError.cs
deleted file mode 100644
index 1a50bbe2d5..0000000000
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlError.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-// 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;
-
-namespace Microsoft.Data.SqlClient
-{
- ///
- [Serializable]
- public sealed class SqlError
- {
- // bug fix - MDAC 48965 - missing source of exception
- private readonly string _source = TdsEnums.SQL_PROVIDER_NAME;
- private readonly int _number;
- private readonly byte _state;
- private readonly byte _errorClass;
- [System.Runtime.Serialization.OptionalField(VersionAdded = 2)]
- private readonly string _server;
- private readonly string _message;
- private readonly string _procedure;
- private readonly int _lineNumber;
- [System.Runtime.Serialization.OptionalField(VersionAdded = 4)]
- private readonly int _win32ErrorCode;
-
- internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, uint win32ErrorCode)
- : this(infoNumber, errorState, errorClass, server, errorMessage, procedure, lineNumber)
- {
- _win32ErrorCode = (int)win32ErrorCode;
- }
-
- internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber)
- {
- _number = infoNumber;
- _state = errorState;
- _errorClass = errorClass;
- _server = server;
- _message = errorMessage;
- _procedure = procedure;
- _lineNumber = lineNumber;
- if (errorClass != 0)
- {
- SqlClientEventSource.Log.TryTraceEvent(" infoNumber={0}, errorState={1}, errorClass={2}, errorMessage='{3}', procedure='{4}', lineNumber={5}", infoNumber, (int)errorState, (int)errorClass, errorMessage, procedure, (int)lineNumber);
- }
- _win32ErrorCode = 0;
- }
-
- ///
- // bug fix - MDAC #49280 - SqlError does not implement ToString();
- // I did not include an exception stack because the correct exception stack is only available
- // on SqlException, and to obtain that the SqlError would have to have backpointers all the
- // way back to SqlException. If the user needs a call stack, they can obtain it on SqlException.
- public override string ToString()
- {
- //return GetType().ToString() + ": " + message;
- return typeof(SqlError).ToString() + ": " + _message; // since this is sealed so we can change GetType to typeof
- }
-
- ///
- // bug fix - MDAC #48965 - missing source of exception
- public string Source
- {
- get { return _source; }
- }
-
- ///
- public int Number
- {
- get { return _number; }
- }
-
- ///
- public byte State
- {
- get { return _state; }
- }
-
- ///
- public byte Class
- {
- get { return _errorClass; }
- }
-
- ///
- public string Server
- {
- get { return _server; }
- }
-
- ///
- public string Message
- {
- get { return _message; }
- }
-
- ///
- public string Procedure
- {
- get { return _procedure; }
- }
-
- ///
- public int LineNumber
- {
- get { return _lineNumber; }
- }
-
- internal int Win32ErrorCode
- {
- get { return _win32ErrorCode; }
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlError.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlError.cs
new file mode 100644
index 0000000000..2fc7dd605e
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlError.cs
@@ -0,0 +1,91 @@
+// 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;
+
+namespace Microsoft.Data.SqlClient
+{
+ ///
+ [Serializable]
+ public sealed class SqlError
+ {
+ // bug fix - MDAC 48965 - missing source of exception
+ private readonly string _source = TdsEnums.SQL_PROVIDER_NAME;
+ private readonly int _number;
+ private readonly byte _state;
+ private readonly byte _errorClass;
+ [System.Runtime.Serialization.OptionalField(VersionAdded = 2)]
+ private readonly string _server;
+ private readonly string _message;
+ private readonly string _procedure;
+ private readonly int _lineNumber;
+ [System.Runtime.Serialization.OptionalField(VersionAdded = 4)]
+ private readonly int _win32ErrorCode;
+ [System.Runtime.Serialization.OptionalField(VersionAdded = 5)]
+ private readonly Exception _exception;
+
+ internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, uint win32ErrorCode, Exception exception = null)
+ : this(infoNumber, errorState, errorClass, server, errorMessage, procedure, lineNumber, exception)
+ {
+ _server = server;
+ _win32ErrorCode = (int)win32ErrorCode;
+ }
+
+ internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, Exception exception = null)
+ {
+ _number = infoNumber;
+ _state = errorState;
+ _errorClass = errorClass;
+ _server = server;
+ _message = errorMessage;
+ _procedure = procedure;
+ _lineNumber = lineNumber;
+ _win32ErrorCode = 0;
+ _exception = exception;
+ if (errorClass != 0)
+ {
+ SqlClientEventSource.Log.TryTraceEvent("SqlError.ctor | ERR | Info Number {0}, Error State {1}, Error Class {2}, Error Message '{3}', Procedure '{4}', Line Number {5}", infoNumber, (int)errorState, (int)errorClass, errorMessage, procedure ?? "None", (int)lineNumber);
+ }
+ }
+
+ ///
+ // bug fix - MDAC #49280 - SqlError does not implement ToString();
+ // There is no exception stack included because the correct exception stack is only available
+ // on SqlException, and to obtain that the SqlError would have to have backpointers all the
+ // way back to SqlException. If the user needs a call stack, they can obtain it on SqlException.
+ public override string ToString()
+ {
+ return typeof(SqlError).ToString() + ": " + Message; // since this is sealed so we can change GetType to typeof
+ }
+
+ ///
+ // bug fix - MDAC #48965 - missing source of exception
+ public string Source => _source;
+
+ ///
+ public int Number => _number;
+
+ ///
+ public byte State => _state;
+
+ ///
+ public byte Class => _errorClass;
+
+ ///
+ public string Server => _server;
+
+ ///
+ public string Message => _message;
+
+ ///
+ public string Procedure => _procedure;
+
+ ///
+ public int LineNumber => _lineNumber;
+
+ internal int Win32ErrorCode => _win32ErrorCode;
+
+ internal Exception Exception => _exception;
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
index bc3e64f9f1..cec77e9ca1 100644
--- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj
@@ -44,6 +44,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs
new file mode 100644
index 0000000000..7c9208ac2a
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs
@@ -0,0 +1,71 @@
+// 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.IO;
+using System.Reflection;
+using System.Runtime.Serialization.Formatters.Binary;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.Tests
+{
+ public class SqlErrorTest
+ {
+ private const string SQLMSF_FailoverPartnerNotSupported =
+ "Connecting to a mirrored SQL Server instance using the MultiSubnetFailover connection option is not supported.";
+ private const byte FATAL_ERROR_CLASS = 20;
+
+#if !NET50_OR_LATER
+ [Fact]
+ public static void SqlErrorSerializationTest()
+ {
+ var formatter = new BinaryFormatter();
+ SqlError expected = CreateError();
+ SqlError actual = null;
+ using (var stream = new MemoryStream())
+ {
+ try
+ {
+ formatter.Serialize(stream, expected);
+ stream.Position = 0;
+ actual = (SqlError)formatter.Deserialize(stream);
+ }
+ catch (Exception ex)
+ {
+ Assert.False(true, $"Unexpected Exception occurred: {ex.Message}");
+ }
+ }
+
+ Assert.Equal(expected.Message, actual.Message);
+ Assert.Equal(expected.Number, actual.Number);
+ Assert.Equal(expected.State, actual.State);
+ Assert.Equal(expected.Class, actual.Class);
+ Assert.Equal(expected.Server, actual.Server);
+ Assert.Equal(expected.Procedure, actual.Procedure);
+ Assert.Equal(expected.LineNumber, actual.LineNumber);
+ Assert.Equal(expected.Source, actual.Source);
+ }
+#endif
+
+
+ private static SqlError CreateError()
+ {
+ string msg = SQLMSF_FailoverPartnerNotSupported;
+
+ Type sqlErrorType = typeof(SqlError);
+
+ // SqlError only has internal constructors, in order to instantiate this, we use reflection
+ SqlError sqlError = (SqlError)sqlErrorType.Assembly.CreateInstance(
+ sqlErrorType.FullName,
+ false,
+ BindingFlags.Instance | BindingFlags.NonPublic,
+ null,
+ new object[] { 100, (byte)0x00, FATAL_ERROR_CLASS, "ServerName", msg, "ProcedureName", 10, null },
+ null,
+ null);
+
+ return sqlError;
+ }
+ }
+}