Вызов Activator.CreateInstance из SQLCLR вызывает исключение

Я пытаюсь создать пример SQLCLR, в котором в зависимости от processorClass, представленного в виде строки, я смогу вернуть конкретный тип обработчика для обслуживания запроса. Когда я добавляю строку:

MessageProcessorBase messageProcessor = MessageProcessorResolver.Create(MessageProcessorAssemblyName, processorClass);

Это приводит к следующей ошибке:

Сообщение 6522, уровень 16, состояние 1, процедура MessageProcessorTrigger, строка 1 Произошла ошибка.NET Framework во время выполнения пользовательской подпрограммы или агрегата "MessageProcessorTrigger": System.IO.FileNotFoundException: не удалось загрузить файл или сборку "MyNamespace.MessageProcessor" или одна из его зависимостей. Система не может найти указанный файл. System.IO.FileNotFoundException: в System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence AssemblySecurity, LocationtimeSsembly locationHint, StackCrawlMark& ​​stackMark, IntPtr pPrivHostBinder. Boolean (AssemblyName имя_файла, строка CodeBase, фактические данные assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& ​​stackMark, IntPtr pPrivHostBinder, булева throwOnFileNotFound, булева forIntrospection, булевы suppressSecurityChecks) при System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Доказательства assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& ​​stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) в System.Activator.CreateInstance(String assemblyString, String typeName, логическое ignoreCase, BindingFlags bindingAttr, BinderFlags связыватель, аргументы Object[], культура CultureInfo, атрибуты активации Object[], атрибуты securityAfo, Evidence securityInfo, StackCrawlMark& ​​stackMark) в System.Activator.CreateInstance(String assemblyName, String typeName) в MyNamespace.MessageProcessorFactory.Create(String assemblyName, String assemblyName, String assemblyName, String assemblyName, String AssemblyName, String assemblyName, String AssemblyName, String assemblyName, String assemblyName, String assemblyNamering), Triggers.MessageProcessorTrigger()

меры

  1. Данные вставляются в таблицу MessageQueue.
  2. Триггер SQL CLR вызывает метод Create, чтобы получить экземпляр обработчика (точка сбоя).
  3. Вызван метод Handle экземпляра.

Таблица

CREATE TABLE MessageProcessor.MessageQueue
(
    Id             INT IDENTITY(1,1) PRIMARY KEY NOT NULL
,   Name           NVARCHAR(50) NOT NULL
,   MessageType    INT  NOT NULL
,   StatusId       INT
,   ProcessorClass NVARCHAR(50)
)

ALTER DATABASE MYBD SET TRUSTWORTHY ON;
GO

exec sp_configure 'clr enabled', 1
GO

reconfigure
GO

Триггер (SQL CLR)

public partial class Triggers
{
    private const string MessageProcessorAssemblyName = "MyProcessor.MessageProcessor";
    // Enter existing table or view for the target and uncomment the attribute line
    //[SqlTrigger(Name = "MessageProcessorTrigger", Target = "MessageProcessor.MessageQueue", Event = "FOR INSERT")]
    public static void MessageProcessorTrigger()
    {
        SqlTriggerContext triggerContext = SqlContext.TriggerContext;
        string processorClass = string.Empty;

        if (triggerContext == null) return;
        if (triggerContext.TriggerAction == TriggerAction.Insert)
        {
            using (SqlConnection conn = new SqlConnection(" context connection=true"))
            {
                conn.Open();
                SqlCommand command = conn.CreateCommand();
                SqlPipe sqlP = SqlContext.Pipe;

                command.Connection = conn;
                command.CommandText = "SELECT ProcessorClass FROM INSERTED";

                processorClass = command.ExecuteScalar().ToString();
                sqlP.Send(string.Format("Called MessageProcessor {0}", processorClass));

                //var handle = Activator.CreateInstance(MessageProcessorAssemblyName, processorClass);

                MessageProcessorBase messageProcessor = MessageProcessorFactory.Create(MessageProcessorAssemblyName,
                    processorClass);
                messageProcessor.HandleMessage(string.Empty);
            }
        }
    }
}

И, наконец, вызов Resolver для получения экземпляра для вызова метода Handle.

public class MessageProcessorResolver
{
    public static MessageProcessorBase Create(string assemblyName, string handler)
    {
        return (MessageProcessorBase)Activator.CreateInstance(assemblyName, handler).Unwrap();
    }
}

Я создаю сборку с набором разрешений UNSAFE только для того, чтобы включить ведение журнала событий, поскольку в настоящее время это единственная операция, которую выполняет обработчик.
Кажется, что это вызов Activator.CreateInstance, где начинается проблема, как, например, когда я устанавливаю тип возвращаемого значения CustomerMessageHandler в методе Create, все работает как ожидалось. Я знаю, что использование отражения не разрешено в SQLCLR, и ошибка, кажется, указывает в этом направлении, но я видел примеры использования этого здесь, что заставило меня задуматься, может быть, я просто что-то упустил.

Для полноты MessageProcessorBase - это просто абстрактный класс с единственным методом, Handle

public abstract class MessageProcessorBase
{
    public virtual void HandleMessage(string messageDetails)
    {
        Console.WriteLine("Handled by Message Processor Base Method");
    }
}

и CustomerMessageHandler просто:

public class CustomerMessageHandler : MessageProcessorBase
{
    public override void HandleMessage(string messageDetails)
    {
        const string source = "Message Processor SQLCLR";
        const string log = "Application";
        const string logEvent = "Customer Processor";

        if (!EventLog.SourceExists(source))
            EventLog.CreateEventSource(source, log);

        EventLog.WriteEntry(source, logEvent);
        Console.WriteLine("Handled by Customer Handler");
    }
}

Пожалуйста, извините за длину этого поста, я постарался быть как можно более полным.

0 ответов

Другие вопросы по тегам