Почему одна функция, запускаемая в SQL Server CLR, может вызвать сбой при нормальной работе в автономном приложении? - PullRequest
3 голосов
/ 03 мая 2011

Эти два метода ниже аналогичны, за исключением того, что один обрабатывает нулевые значения, а другой - нет.Для обработки нулевых значений он использует тип SqlString и проверяет свойство «get_IsNull».

Почему первый может вызывать ошибку "A .NET Framework error occurred during execution of user-defined routine or aggregate "CheckMailingAddress": ." при запуске внутри SQL CLR, а второй - нет?

В частности, ошибка TSQL равна "Msg 10329, Level 16, State 49, Line 1 .Net Framework execution was aborted."

.method public hidebysig static bool CheckMailingAddress(valuetype [System.Data]System.Data.SqlTypes.SqlString param0) cil managed
{
   .maxstack 8
    L_0000: ldarga.s param0
    L_0002: nop 
    L_0003: nop 
    L_0004: call instance bool [System.Data]System.Data.SqlTypes.SqlString::get_IsNull()
    L_0009: brfalse L_0010
    L_000e: ldc.i4.1 
    L_000f: ret 
    L_0010: ldarga.s param0
    L_0012: nop 
    L_0013: nop 
    L_0014: call instance string [System.Data]System.Data.SqlTypes.SqlString::get_Value()
    L_0019: call class DatabaseValues.MailingAddress DatabaseValues.MailingAddress::op_Explicit(string)
    L_001e: pop 
    L_001f: ldc.i4.1 
    L_0020: ret 
}

.method public hidebysig static bool CheckMailingAddress(string param0) cil managed
{
   .maxstack 8
    L_0000: ldarg.0 
    L_0001: call class DatabaseValues.CheckMailingAddress DatabaseValues.CheckMailingAddress::op_Explicit(string)
    L_0006: pop 
    L_0007: ldc.i4.1 
    L_0008: ret 
}

Имейте в виду, MSIL, насколько я знаю, правильный, потому что оба эти метода работают при вызове в автономном приложении,Только при вызове внутри SQL CLR происходит сбой первого из двух.В SQL CLR функция определена с типом «nvarchar (4000)», который, насколько я знаю, должен хорошо работать с SqlString.

Вероятно, я мог бы реализовать и первый метод, используя «строку»и по-прежнему выполнять проверку на нулевое значение, но использует SqlString, чтобы воспользоваться преимуществами свойств интерфейса INullable «IsNull» и «Value», поскольку он является частью универсального генератора кода, в котором могут использоваться другие типы Sql *.

РЕЗЮМЕ ПРОБНОЙ ЗАДАЧИ:

Для тех, кто отвлекается на MSIL в теле метода;игнорируй это.Я перекомпилировал функции, чтобы они вообще ничего не делали, и моя точка зрения заключается в том, что, когда «SqlString», а не «string», является типом ввода, CLR взрывается и завершается без сообщения об ошибке, а возвращаемое значение равно NULL, а неИСТИНА.

//Crashes when input parameter is "SqlString"
.method public hidebysig static bool CheckMailingAddress(valuetype [System.Data]System.Data.SqlTypes.SqlString param0) cil managed
{
   .maxstack 8
    L_001f: ldc.i4.1 
    L_0020: ret 
}

//Doesn't Crash when input parameter is "string"
.method public hidebysig static bool CheckMailingAddress(string param0) cil managed
{
   .maxstack 8 
    L_0007: ldc.i4.1 
    L_0008: ret 
}

1 Ответ

5 голосов
/ 04 мая 2011

Я нашел источник проблемы и смог ее решить, но я не уверен в деталях.

В какой-то момент я переключил свой проект DeployDatabaseAssembly на целевой .NET 4.0, и AssemblyBuilder должен был сгенерировать сборку, которая также нацелена на .NET 4.0. Переключение проекта на целевой .NET 3.5 решило проблему.

Что забавно, так это то, что исходная DLL (database.dll), содержащая все мои типы данных, все еще нацелена на .NET 3.5, и была оставлена ​​намеренно, потому что я знал, что SQL Server поддерживает только CLR 2.0 прямо сейчас, что фактически делает ее несовместимой с .NET 4.0, потому что .NET 4.0, кажется, требует CLR 4.0. Используя ILMerge, я комбинировал динамическую сборку, содержащую сгенерированные функции, с моей существующей (.NET 3.5) database.dll. В конечном итоге это привело к гибридной сборке .NET 4.0, которая была основана главным образом на функциях и классах .NET 3.5. Странно, что мне удалось заставить работать функции, использующие базовые параметры типа «String» и «int», но тип SqlString вызывал сбои ... очевидно, потому что он был извлечен из .NET 4.0 System.Data.dll , так как он упоминался как "typeof (SqlString)" в моей DeployDatabaseAssembly, которая предназначалась для .NET 4.0. Просто странно, как это происходило со сбоями без каких-либо сообщений об ошибках или без каких-либо предупреждений о том, что они несовместимы с загруженными модулями SQL CLR.

Хотелось бы, чтобы я знал, как заставить AssemblyBuilder, работающий в приложении .NET 4.0, генерировать сборку, нацеленную на .NET 3.5 ...

Обновление: проблема полностью решена

Я сосредоточился на выводе ILMerge и пошел дальше и переключил DeployDatabaseAssembly обратно на .NET 4.0. Кстати, в своем проекте я использую ILMerge, поскольку это сборка .NET.

Установив опцию ILMerge следующим образом:

ILMerge merger = new ILMerge();
merger.SetTargetPlatform( "v2", @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client");

Полученная DLL развертывается на SQL Server (как и раньше), но на этот раз она фактически работает без ошибок.

Интересно, что если я заменим только «v3.5» в пути целевой платформы на «v4.0» и попытаюсь развернуть сборку на SQL Server, то я получу полезное сообщение об ошибке сразу во время развертывания » CREATE ASSEMBLY для сборки «мое имя сборки» не удалось, так как сборка создана для неподдерживаемой версии среды CLR. ". Странно, что когда я вообще не устанавливал какую-либо целевую платформу, она нормально работала, но вылетала без какого-либо сообщения об ошибке.

Эта таблица суммирует вышеприведенные комбинации конфигурации и результаты: http://oi53.tinypic.com/muee0z.jpg

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...