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; + } + } +}