Как получить подробную ошибку из хранимой процедуры CLR, вызванной в транзакции DTC, из пакета служб SSIS - PullRequest
2 голосов
/ 10 ноября 2011

Всякий раз, когда в хранимой процедуре CLR, вызываемой из пакета служб SSIS, возникает исключение, в рамках транзакции DTC возвращаемая клиенту ошибка (пакет служб SSIS) относится к DTC, а не к базовому исключению.

Можно ли вернуть информацию об основной ошибке клиенту?

Примечание. Когда хранимая процедура запускается из среды SQL Server Management Studio, вне распределенной транзакции, возвращается подробная информация об основной ошибке.

Ошибка: не удалось выполнить запрос «StoredProcedure» со следующим ошибка: «Координатор распределенных транзакций Microsoft (MS DTC) имеет отменил распределенную транзакцию ». Возможные причины: проблемы при запросе свойство ResultSet установлено неправильно, параметры не установлены установлен правильно, или соединение установлено неправильно.

Весь код работает на одном экземпляре SQL Server 2008.

SSIS Package
---> Sequence Container (TransactionOption = Required )
---> Execute SQL Task (ADO.NET Connection Manager, SQLClient DataProvider)
---> SQL Server CLR Stored Procedure (No exception handling code)
---> TransactionScope(TransactionScopeOption.Required)

Код, который воспроизводит проблему

Следующий код иллюстрирует проблему, но отличается от сценария, описанного в заголовке, тем, что клиент является консольным приложением C #, а не пакетом служб SSIS

CLR хранимая процедура

using System;
using System.Transactions;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void ExceptionStoredProcedure()
    {
        using (TransactionScope scope = new TransactionScope())
        {
            throw new Exception(@"Test exception thrown from ""ExceptionStoredProcedure""");
        }
    }
};

Клиент консольного приложения C #

using System;
using System.Data.SqlClient;
using System.Transactions;

namespace SQLCLRTester
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    string connectionString = "Data Source=.; Initial Catalog=Experiments; Integrated Security=Yes";

                    using (SqlConnection noOpConnection = new     SqlConnection(connectionString))
                    {
                        noOpConnection.Open();

                        using (SqlConnection connection = new SqlConnection(connectionString))
                        {
                            SqlCommand command =
                                new SqlCommand()
                                {
                                    CommandText = "ExceptionStoredProcedure",
                                    CommandType = System.Data.CommandType.StoredProcedure,
                                    Connection = connection
                                };
                            connection.Open();
                            command.ExecuteNonQuery();
                        }

                    } scope.Complete();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception caught: {0}", ex.Message);
            }
        }

    }
}

Сообщение, напечатанное клиентом

Обнаружено исключение: координатор распределенных транзакций Microsoft (MS DTC) отменил распределенную транзакцию

Примечания:

  1. InnerException равно нулю
  2. Если область транзакции в C # консольное приложение или в хранимой процедуре CLR удаляется затем DTC транзакция не создана и информация для основной ошибки возвращается.

1 Ответ

0 голосов
/ 22 ноября 2011

Найден обходной путь, который использует SqlContext.Pipe.Send () благодаря ссылкам, предоставленным Боб Боучемин (Партнер, MVP). Смотрите код ниже.

Примечания: SqlClient добавляет «информационные сообщения», отправленные SQL Server, в SqlException.Message, поэтому клиентскому коду, использующему SqlClient, не нужно изменять

CLR Хранимая процедура

using System;
using System.Transactions;
using Microsoft.SqlServer.Server;
using System.Data.SqlClient;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void ExceptionStoredProcedure()
    {
        using (TransactionScope scope = new TransactionScope())
        {
            try
            {
                throw new Exception(@"Test exception thrown from     ""ExceptionStoredProcedure""");
                scope.Complete();
            }
            catch (Exception ex)
            {
                if (Transaction.Current.TransactionInformation.DistributedIdentifier != Guid.Empty)
                    SqlContext.Pipe.Send(ex.Message);

                throw;
            }
        }
    }


};

Сообщение, напечатанное клиентом

Произошло исключение: координатор распределенных транзакций Microsoft (MS DTC) отменил распределенную транзакцию.

Тестовое исключение, выданное из "ExceptionStoredProcedure"

Возможное объяснение

Основываясь на найденных Бобом ссылках на статьи об отмене транзакции DTC и T-SQL TRY / CATCH, я думаю, что наблюдаемое поведение может разворачиваться следующим образом:

  1. Исключение в области транзакции в хранимой процедуре CLR вызывает Голос отмены транзакции для отправки в DTC.
  2. DTC отправляет запрос на прерывание всем зачисленным менеджерам ресурсов включая SQL Server
  3. SQL Server преобразует запрос на прерывание в сигнал внимания Сеанс SQL Server, в котором выполняется хранимая процедура CLR
  4. Сигнал внимания изменяет отношение к коду размещения SQL Server CLR необработанное исключение CLR, которое в свою очередь приводит к сообщению об исключении не включается в результат, возвращенный клиенту

Ссылки на статьи:

http://connect.microsoft.com/SQLServer/feedback/details/414969/uncatchable-error-when-distributed-transaction-is-aborted

http://msdn.microsoft.com/en-us/library/ms179296(SQL.90).aspx

...