从SQLCLR调用Activator.CreateInstance会导致异常

时间:2015-03-23 01:10:21

标签: c# sql-server sqlclr

我正在尝试创建一个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()

步骤

  1. 将数据插入表MessageQueue。
  2. SQL CLR触发器调用Create方法来获取处理程序的实例(失败点)。
  3. 调用实例上的Handle方法。
  4. 表格

    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");
        }
    }
    

    请原谅这篇文章的篇幅,我尽量做到尽可能完整。

0 个答案:

没有答案