我正在尝试创建一个SQL CLR示例,其中取决于processorClass,表示为字符串,我将能够返回处理请求的具体处理程序类型。当我添加这一行时:
MessageProcessorBase messageProcessor = MessageProcessorResolver.Create(MessageProcessorAssemblyName, processorClass);
导致以下错误:
消息6522,级别16,状态1,过程MessageProcessorTrigger,第1行 在执行用户定义的例程或聚合“MessageProcessorTrigger”期间发生.NET Framework错误: System.IO.FileNotFoundException:无法加载文件或程序集“MyNamespace.MessageProcessor”或其依赖项之一。该系统找不到指定的文件。 System.IO.FileNotFoundException:找不到 在System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName,String codeBase,Evidence assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark& stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks) 在System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName,String codeBase,Evidence assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark& stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks) 在System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef,Evidence assemblySecurity,RuntimeAssembly reqAssembly,StackCrawlMark& stackMark,IntPtr pPrivHostBinder,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks) 在System.Activator.CreateInstance(String assemblyString,String typeName,Boolean ignoreCase,BindingFlags bindingAttr,Binder binder,Object [] args,CultureInfo culture,Object [] activationAttributes,Evidence securityInfo,StackCrawlMark& stackMark) 在System.Activator.CreateInstance(String assemblyName,String typeName) at MyNamespace.MessageProcessorFactory.Create(String assemblyName,String handler) 在MyNamespace.Triggers.MessageProcessorTrigger()
步骤
表格
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 Method的实例。
public class MessageProcessorResolver
{
public static MessageProcessorBase Create(string assemblyName, string handler)
{
return (MessageProcessorBase)Activator.CreateInstance(assemblyName, handler).Unwrap();
}
}
我使用Permission Set UNSAFE创建程序集,只是为了启用事件记录,因为这是当前处理程序执行的唯一操作。
它似乎是调用Activator.CreateInstance的问题,因为当我在Create方法中将返回类型设置为CustomerMessageHandler时,一切都按预期工作。我知道在SQLCLR中不允许使用Reflection,并且错误似乎指向了这个方向,但我已经看到了这个使用here的例子,这让我想到也许我只是遗漏了一些东西。
为了完整性,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");
}
}
请原谅这篇文章的篇幅,我尽量做到尽可能完整。