CLR函数中的反序列化失败

时间:2016-09-28 14:23:51

标签: c# tsql sqlclr

我已经为C#中的文本语音转换编写了一些例程。这些例程需要一堆定义的转换规则(search-string / replace-string)。我们的想法是将规则存储为程序集中的嵌入式资源,然后从中读取规则。反序列化的起点如下

public static phonet42n.Core.Rules Deserialize(phonet42n.Core.Rules.Ressources ressource)
{
    string ressourceName;
    phonet42n.Core.Rules returnValue;
    System.Xml.XmlReader reader;
    System.Xml.Serialization.XmlSerializer xmlSerializer;
    phonet42n.Core.SerializableRules serializeableRules;

    returnValue = new phonet42n.Core.Rules();

    switch (ressource)
    {
        case Ressources.German_01:
            ressourceName = RESSOURCE_XML_GERMAN_01;
            break;
        case Ressources.German_02:
            ressourceName = RESSOURCE_XML_GERMAN_02;
            break;
        default:
            ressourceName = RESSOURCE_XML_GERMAN_01;
            break;
    }

    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ressourceName))
    {
        using (reader = System.Xml.XmlReader.Create(stream))
        {
            xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(phonet42n.Core.SerializableRules));
            serializeableRules = (phonet42n.Core.SerializableRules)xmlSerializer.Deserialize(reader);
        }
    }

    foreach (phonet42n.Core.Rule entry in serializeableRules.Rules)
    {
        if (entry.SearchString != null && entry.SearchString.Length > 0)
        {
            returnValue.Add(entry.Index, entry);
        }
    }
    return returnValue;
}

在常规可执行文件中执行时,应用程序正常工作。

在SQL Server中执行注册函数时,出现以下错误:

SELECT [dbo].[Phonet42n]('mayer', 1)

...产生

  Meldung 6522,Ebene 16,Status 1,Zeile 22
  .NET Framework-FehlerbeimAusführenderbenutzerdefinierten Routine oder des benutzerdefinierten Aggregats'Phonet42n':
  System.InvalidOperationException:Fehler im XML-Dokument(3,4)。 ---> System.MethodAccessException:Fehler beim Versuch der Methode“Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read8_SerializableRules(Boolean,Boolean)”,auf Methode“phonet42n.Core.Rule..ctor()”zuzugreifen。
  System.MethodAccessException:
  bei System.RuntimeTypeHandle.CreateInstance(RuntimeType type,Boolean publicOnly,Boolean noCheck,Boolean& canBeCached,RuntimeMethodHandleInternal& ctor,Boolean& bNeedSecurityCheck)
  bei System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark& stackMark)
  bei System.Activator.CreateInstance(Type type,Boolean nonPublic)
  bei System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr,Binder binder,Object [] args,CultureInfo culture,Object [] activationAttributes,StackCrawlMark& stackMark)
  bei System.Activator.CreateInstance(Type type,BindingFlags bindingAttr,Binder binder,Object [] args,CultureInfo culture,Object [] activationAttributes)
  bei System.Activator.CreateInstance(Type type,BindingFlags bindingAttr,Binder binder,Object [] args,CultureInfo culture)
  bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read8_SerializableRules(Boolean isNullable,Boolean checkType)
  bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read19_Rules()
  System.InvalidOperationException:
  bei System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader,String encodingStyle,XmlDeserializationEvents事件)
  bei System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
  bei phonet42n.Core.Rules.Deserialize(Ressources ressource)
  bei phonet42n.Core.Rules..ctor(Ressources ressource,Characters characters)
  bei phonet42n.Core.HashTable..ctor(Ressources ressource)
  bei phonet42n.Core.Match..ctor(Re ...

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

每当有安全例外情况时,您可以先尝试将程序集设置为PERMISSION_SET = EXTERNAL_ACCESS,如果这不起作用,您可以尝试UNSAFE。但是,如果有人试图动态加载程序集,那么即使对于标记为UNSAFE的程序集,也应禁止该程序集。

由于此处的问题是想要包含一组规则,这可能可以在另一个程序集中完成。然后主程序集可以引用包含规则的那个,然后只需将包含规则的规则加载到SQL Server中。这将允许两个程序集保持标记为SAFE

当然,如果没有迫切需要将规则分开,那么您也可以直接将它们放入类中的集合中。

答案 1 :(得分:1)

我对evreything做了一个撤消,除了构造函数部分(私有/公共)。无论是否签署程序集,我都会收到以下消息(10327):

  

为程序集“phonet42n.Core”创建程序集失败,因为程序集   'phonet42n.Core'未获得PERMISSION_SET =的授权   EXTERNAL_ACCESS。当任何一个组件被授权时,组件被授权   以下是真实的:数据库所有者(DBO)具有EXTERNAL ACCESS   ASSEMBLY权限和数据库具有TRUSTWORTHY数据库   财产;或者使用证书或证书签署程序集   具有EXTERNAL ACCESS的相应登录的非对称密钥   大会许可。

不幸的是我不熟悉签署程序集:我刚刚检查了项目属性的属性页中的复选框:

screenshot

不知道是否缺少其他步骤。

无论如何,正如消息中所建议的那样,我尝试使用以下语句创建非对称密钥:

USE master; 
GO  

IF EXISTS (SELECT * FROM [sys].[syslogins] WHERE [sid] = SUSER_SID('SQLCLRTestLogin'))
   BEGIN
      PRINT 'Dropping Login...'
      DROP LOGIN [SQLCLRTestLogin]
      PRINT 'End'
   END

GO
IF EXISTS (SELECT * FROM [sys].[asymmetric_keys] WHERE [name] = 'SQLCLRTestKey')
   BEGIN
      PRINT 'Dropping Asymmetric Key...'
      DROP ASYMMETRIC KEY [SQLCLRTestKey]
      PRINT 'End'
   END
GO

BEGIN
   PRINT 'Creating Login...'
   CREATE ASYMMETRIC KEY [SQLCLRTestKey] FROM EXECUTABLE FILE = 'D:\phonet42n.net\Core\bin\Debug\phonet42n.Core.dll' 
   PRINT 'End'

   PRINT 'Creating Asymmetric Key...'
   CREATE LOGIN [SQLCLRTestLogin] FROM ASYMMETRIC KEY [SQLCLRTestKey]   
   PRINT 'End'

   PRINT 'Granting Access...'
   GRANT EXTERNAL ACCESS ASSEMBLY TO [SQLCLRTestLogin]; 
   PRINT 'End'
END
GO 

如果已签名的程序集,这些语句会成功,而在无符号程序集的情况下,我会收到以下错误消息(15208):

  

证书,非对称密钥或私钥文件不存在或   格式无效。

顺便说一句..不知道这是否重要。组件的目标.NET Framework是4.5。最后......出现初始错误消息:Adwaenyth对于缺少的公共默认构造者是正确的。该消息到目前为止具有误导性,因为缺少的构造函数不会影响程序集的注册。只有在运行时成功注册后,才能调用phonet42n函数。

我真的不知道,这是否是设计的解决方案。我不知道是否为任何可能的线程打开了门。

我可以强调Stairway series articles特别是在SQLCLR上。优秀!它有助于理解SQLCLR如何工作以及它有什么用处。

而且(真的)最后:对我来说,总体结果是,我将从XML中提取规则并通过填充srutzky建议的集合来直接加载它们。可能会更高效。