Как встраивать типы взаимодействия из ADODB? - PullRequest
0 голосов
/ 13 декабря 2018

Мой COM-класс, расположенный в сборке .NET, foo.dll создает ADODB.Recordset из .NET IDataReader, а затем возвращает его вызывающей стороне, в моем случае классической устаревшей странице ASP.Однако мы определили узкое место в производительности, которое, похоже, является вызовом new ADODB.Recordset(), и выяснили, что установка Embed interop types в adodb.dll значительно повышает производительность.К сожалению, это вызывает исключение в классическом ASP:

System.TypeLoadException: Could not load type 'ADODB.FieldsToInternalFieldsMarshaler' from assembly 'foo ...'.
  at System.StubHelpers.StubHelpers.CreateCustomMarshalerHelper(IntPtr pMD, Int32 paramToken, IntPtr hndManagedType)
  at ADODB._Recordset.get_Fields()

На разных страницах написано, что исправление для этой проблемы - НЕ встраивать типы взаимодействия из adodb.dll, но производительность затем идет на юг ... Улучшения производительности были провереныс помощью другого приложения .NET, ссылающегося на foo.dll со встроенным adodb.dll, а не встроенным.Кроме того, почему наши тестовые приложения .NET могут работать с foo.dll со встроенными типами взаимодействия, а классический ASP - нет?Спасибо за любые советы.

РЕДАКТИРОВАТЬ:

Проблема производительности была отслежена до выхода компилятора при внедрении, а не встраивания типов взаимодействия из adodb.dll.Repro:

  1. Создать новую библиотеку c #,
  2. Добавить ссылку на adodb.dll
  3. Пометить ее как Embed interop types false
  4. Добавьте код и скомпилируйте:

    using System;
    
    namespace cax_test
    {
        public class Class1
        {
            public static ADODB.Recordset Get()
            {
                return new ADODB.Recordset();
            }
        }
    }
    
  5. Откройте полученный dll, например, в ILSpy, и обратите внимание, что конструктор ADODB.Recordset был переписан в:

    return new ADODB.RecordsetClass();
    
  6. Измените Embed interop types на true и перекомпилируйте

  7. Снова откройте в ILSpy и обратите внимание, что конструктор:

    return (ADODB.Recordset)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("00000535-0000-0010-8000-00AA006D2EA4")));
    

При ссылкетакая сборка из консольного приложения и вызов метода Class1.Get() 1000x не имеет значения, если ссылаться на него из веб-приложения и делать то же самое, версия с RecordsetClass будет в несколько раз медленнее версии с CreateInstance.Пример такого приложения, которое будет размещено в IIS, можно загрузить с здесь , затем просто нажать http://localhost/test_app/t2.ashx и увидеть разницу между активатором и версией конструктора.Чтобы увидеть реализацию методов cax_test.dll, просто откройте его в ILSpy, это выглядит так:

using ADODB;
using System;
using System.Runtime.InteropServices;

namespace cax_test
{
    public class Class1
    {
        public static Recordset GetViaActivator()
        {
            return (Recordset)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("00000535-0000-0010-8000-00AA006D2EA4")));
        }

        public static Recordset GetViaConstructor()
        {
            return new RecordsetClass();
        }
    }
}

Для меня измеренные времена:

activator: 00:00:00.1475626
constructor: 00:00:01.3152554
...