При выпуске dll не работают, а отладочные dll работают

После развертывания нашей огромной распределенной системы на одном из наших клиентов возникает непредвиденная ошибка. В ходе исследования мы заменяем сборку, вызвавшую ошибку, на ту, в которую добавили какой-то диагностический код. Используемая нами dll построена в режиме отладки. И вдруг все работает!

Замена отладочной dll на версию выпуска (с диагностическим кодом) снова вызывает сбой.

В нашем коде нет директив прекомпилятора, условных атрибутов отладки и т. д. Проблема была обнаружена в двух разных местах установки, в то время как она отлично работает еще на нескольких.

(В проекте используется смесь C# и VB.NET, проблемная сборка - VB.NET .., если это имеет значение)

Итак, вопрос: Что вы делаете в подобных ситуациях? А в чем может быть причина - вообще? Любые советы по отладке этой проблемы приветствуются.

Было бы полезно дать некоторые подробности о проблеме, кроме общих: «она работает при отладке, но не в выпуске». Что такое «это», что «это»?

user1228 15.12.2008 16:53

Я еще не смог это исправить, но это исключение с нулевой ссылкой (так что это действительно не помогает, верно !?).

Torbjørn 15.12.2008 17:22

Может, вместе со стеком вызовов. Изучение стека вызовов - одно из первых действий, которое вы должны сделать.

user1228 15.12.2008 18:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
3
21 402
15

Ответы 15

По причинам ... ну, поможет намек на симптом. Одна из возможностей заключается в том, что у вас есть код для такого метода, как Debug.WriteLine, который имеет побочные эффекты (т.е. заставляет его работать). Вызовы методов, помеченных как [Conditional(...)], не компилируются, если у вас не определены правильные символы, поэтому все, что помечено как [Conditional("DEBUG")], будет автоматически удалено.

Это также может быть ошибка компилятора, но это маловероятно (но не невозможно).

Какой симптом? Как это ломается?

В качестве примера вышеизложенного:

    static string Bar { get; set; }
    static void Main()
    {
        Bar = "I'm broken";
        Debug.WriteLine(Foo());
        Console.WriteLine(Bar);
    }
    // note Foo only called in DEBUG builds
    static string Foo()
    {
        Bar = "I'm working";
        return "mwahahah";
    }

При компиляции в режиме DEBUG выводится «Я работаю»; при компиляции в режиме RELEASE выводится сообщение «Я сломался». Похоже это звучит? Убедитесь, что вы не вызываете какие-либо методы отладки напрямую с вещами, которые имеют побочные эффекты. В большинстве случаев вы можете косвенно исправить:

string foo = Foo();
Debug.WriteLine(foo);

Теперь он вызывается в любом режиме.

Как я уже сказал, я не думаю, что в нашем коде есть какие-либо директивы прекомпилятора, условные атрибуты отладки и т. д. То же самое и с Debug.WriteLine. Но необходимы дополнительные исследования.

Torbjørn 15.12.2008 17:23

Вы можете попробовать отключить оптимизацию кода в настройках сборки. Какую фактическую ошибку вы получаете.

Еще вы можете выполнить компиляцию в режиме выпуска, но включить условие #Debug. Это будет обрабатывать случай, если вы используете Diagnostics.Debug и код в нем влияет на ваше приложение.

Debug.Assert(ImportantMethod());

У вас может быть какое-то состояние гонки, если вы не работаете с однопоточным кодом. Например, если какая-то часть вашей программы должна выполнить некоторые действия, прежде чем другие части смогут получить к ней доступ, она может выйти из строя в режиме выпуска просто потому, что к коду обращаются слишком рано. Однажды у нас была аналогичная проблема с некоторым кодом для мобильных телефонов, который нормально работал в эмуляторе, но на телефоне, который был медленнее, ситуация была совсем другой.

Вы пробовали включать файлы отладки? (PDBS)

Если вы перейдете в настройки проекта, а затем на вкладке компиляции выберите сборку выпуска в раскрывающемся списке вверху, затем выберите расширенные параметры компиляции внизу, обязательно установите для него ПОЛНУЮ отладочную информацию, а затем выполните повторное развертывание, вы должны Теперь получите более подробную информацию о причине сбоя.

Я видел время, которое вызывает проблемы между сборкой отладки и выпуска. Обычно сборка отладки выполняется медленнее, чем сборка выпуска. Возможно, вы захотите проверить критичный по времени участок вашего кода.

Вы, наверное, знаете это, но, переменные иногда инициализируются по-разному в сборках отладки и выпуска. Например. Я думаю, что переменные автоматически инициализируются в отладочных сборках VC6, это может скрыть проблемы, если вы что-то не инициализировали. Я также думаю, что массивы отладки могут использовать сторожевые байты в попытке указать на переполнение. Это тоже может привести к другому поведению.

Я бы поставил +1, если бы спрашивающий не указал, что использует управляемый код. В 9 случаях из 10, когда у меня возникала подобная проблема, она была на С ++, и это было потому, что я забыл правильно инициализировать что-то в .ctor. К счастью для меня, ни одна из этих ошибок так и не была реализована.

Greg D 15.07.2009 19:18

У меня была похожая проблема. Моя ситуация такая: Я определил некоторые функции отражения в библиотеке классов A. Затем я определил библиотеку пользовательских элементов управления WPF B, которая использует функции из библиотеки A. Затем я закодировал приложение, которое использует пользовательский элемент управления из библиотеки B и функции в библиотеке A. Когда я использовал отладочную версию библиотеки B, работает нормально. Но когда я использовал релизную версию библиотеки B, функции отражения не работали. Я также определил другие функции в библиотеке A. Кажется, проблемы вызывают только функции отражения. Не могу понять причину. Наконец, я сдался и переместил функции отражения из библиотеки A в библиотеку B. И это сработало.

В какой-то момент у меня была проблема с тем, что финализаторы сработали раньше, чем ожидалось, потому что я не полностью понимал взаимодействие между финализаторами, сборщиком мусора и тем, когда локальный объект считается собираемым (подсказка: это не закрывающая фигурная скобка блок). Если в вашем коде используются финализаторы, вы можете изучить GC.KeepAlive (). В следующем блоке:

void MyFunction() 
{ 
  Foo f = new Foo();
  SomeFunction(f.SomeProp);
}

f получает право на финализацию еще до запуска SomeFunction()! Если финализатор сделает что-то вроде утилизации того, что раздал SomeProp, у вас могут возникнуть проблемы. Добавление вызова GC.KeepAlive(f) после вызова SomeFunction гарантирует, что f не будет иметь права на финализацию до завершения вызова KeepAlive().

Обновлено: после всего этого я забыл указать, что эта проблема была гораздо более выраженной при работе в режиме выпуска. Я не знаю, помещает ли сборка Debug неявные KeepAlives для локальных пользователей в конце функции в пользу отладчика, или сборка мусора просто менее агрессивна, или что-то еще, но в моем случае режим Release значительно усугубил эту проблему.

Решили проблему?
У меня такая же проблема, как и у вас. Если я скомпилирую dll в отладке, все будет работать нормально. Если я компилирую в выпуске, я получаю исключение с нулевой ссылкой. Но если я включу некоторые строки, подобные приведенной выше, в вызов некоторых методов, исключение исчезнет даже в режиме выпуска:
System.Diagnostics.EventLog.WriteEntry ("блаблабла", "блаблабла")

Надеюсь, это вам поможет.

Убедитесь, что приложение строится в соответствии с правильной целевой платформой. Это может быть проблемой, особенно когда дело доходит до предоставления или использования библиотек DLL. Посмотрите в «Проект-> Свойства» и выберите вкладку «Сборка». Параметр «Целевая платформа» позволит вам выбрать любой процессор (по умолчанию), x86 или x64.

В моей конкретной ситуации я закончил тем, что настроил все проекты для сборки как x86.

dev1998 22.11.2017 21:02

Прежде всего извините за мой английский. Я знаю, что этот пост старый, но у меня такая же проблема, и я понимаю, что в режиме отладки сборка выполняется для 32-битная ОС, а режим выпуска по умолчанию - для 64 бит. Это делает DLL, созданную для 32-битной версии, не работающей в выпуске. Если вы перейдете в Свойства проекта -> построить, вы можете выбрать нужную архитектуру. У меня это работает.

В моем случае это было то, что мой проект потребителя DLL (в VS) имел конфигурацию x64, но решение было в любом процессоре. По какой-то причине при запуске приложения это не связано с моей x64 DLL. Я настроил приложение на платформу x64 явно, и все работало правильно.

Была такая же проблема с C# DLL, содержащей клиент WCF, предоставленный для нескольких клиентских приложений.

Выяснилось, что в клиентской библиотеке C# есть метод доступа к StackTrace для ведения журнала, который при компиляции в отладке отличается.

StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(2).GetMethod();

GetFrame(2) в выпуске не существовало. Более подробную информацию об этом можно найти здесь: Методы класса StackTrace не работают в режиме выпуска

Забавно, что клиент VB.NET пострадал, в то время как в другом клиенте C# .NET он работал правильно.

Надеюсь, поможет.

Вероятно, это не относится к исходному вопросу, но для всех, кто запускает приложение, которое использует

var isThisMyAssembly = System.Reflection.Assembly.GetCallingAssembly();

этот вызов может быть встроен в метод другой сборки во время выполнения и, следовательно, получить неожиданный результат (как указано в Документация MSDN).

Чтобы этого избежать, вы можете применить к своему методу MethodImplAttribute:

[MethodImpl(MethodImplOptions.NoInlining)]
void DoSomeThings()
{
    var isThisMyAssembly = System.Reflection.Assembly.GetCallingAssembly();
    //do stuff
}

или вы можете переключиться на использование Assembly.GetExecutingAssembly().

Другие вопросы по теме