CLR 函数中的反序列化失败

Deserialization in a CLR Function fails

我用C#写了一些文字的音标转换的例程。这些例程需要一堆 aof 定义的转换规则 (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 服务器中执行注册函数时出现以下错误:

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

产生...

Meldung 6522, Ebene 16, Status 1, Zeile 22
.NET Framework-Fehler beim Ausführen der benutzerdefinierten 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 events)
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...

有什么想法吗?

每当出现安全异常时,您可以先尝试将 Assembly 设置为 PERMISSION_SET = EXTERNAL_ACCESS,如果这不起作用,您可以尝试 UNSAFE。但是,如果有人试图动态加载程序集,那么即使对于标记为 UNSAFE.

的程序集,也应该禁止这样做

由于这里的问题是想要包含一套规则,这可能会在另一个大会上完成。然后主程序集可以引用包含规则的程序集,您只需先将包含规则的程序集加载到 SQL 服务器即可。这将允许两个程序集保持标记为 SAFE.

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

除了构造函数部分 (private/public),我对所有内容都进行了撤消。无论是否签署程序集,我都会收到以下消息 (10327):

CREATE ASSEMBLY for assembly 'phonet42n.Core' failed because assembly 'phonet42n.Core' is not authorized for PERMISSION_SET = EXTERNAL_ACCESS. The assembly is authorized when either of the following is true: the database owner (DBO) has EXTERNAL ACCESS ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with EXTERNAL ACCESS ASSEMBLY permission.

不幸的是,我不熟悉签署程序集:我只是选中了项目属性 属性 页面中的复选框:

不知道是否缺少额外的步骤。

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

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 ):

The certificate, asymmetric key, or private key file does not exist or has invalid format.

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

我真的不知道,这是否是设计使然的解决方案。而且我不知道我是否为任何潜在线程打开了大门。

我只能强调 Stairway series articles 尤其是在 SQLCLR 上。出色的!它有助于了解 SQLCLR 的工作原理及其用途。

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