Вызов 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()
меры
- Данные вставляются в таблицу MessageQueue.
- Триггер SQL CLR вызывает метод Create, чтобы получить экземпляр обработчика (точка сбоя).
- Вызван метод 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");
}
}
Пожалуйста, извините за длину этого поста, я постарался быть как можно более полным.