当发布dll不起作用但调试dll没有

时间:2008-12-15 13:40:09

标签: .net debugging

在将我们庞大的分布式系统部署到我们的客户之后,我们遇到了意外错误。在调查期间,我们将导致错误的组件替换为我们添加了一些诊断代码的组件。我们使用的DLL是在调试模式下构建的。突然一切都行了!

使用发行版本(使用诊断代码)替换调试dll会使其再次崩溃。

我们的代码中没有预编译器指令,条件调试属性等。在两个不同的安装站点中发现了这个问题,而在其他几个站点中它可以正常工作。

(该项目混合使用C#和VB.NET,麻烦组件是VB.NET ..如果这有什么不同的话)

所以问题是: 你在这样的情况下做了什么?原因可能是什么? 欢迎任何有关调试此问题的建议。

15 个答案:

答案 0 :(得分:12)

对于原因......好吧,一些症状的暗示会有所帮助。一种可能性是你有一个像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);

现在可以在任一模式下调用它。

答案 1 :(得分:5)

您可以尝试在Build Settings中关闭Optimize Code。你得到的实际错误是什么。

您可以做的另一件事是在发布模式下编译,但启用#Debug条件。如果你使用Diagnostics.Debug及其中的代码影响你的应用程序,这将处理这种情况。

答案 2 :(得分:4)

Debug.Assert(ImportantMethod());

答案 3 :(得分:4)

您是否尝试过包含调试文件? (pdbs)

如果您执行项目设置然后编译'选项卡'在顶部附近的下拉列表中选择您的发布版本,然后选择底部附近的高级编译选项,请确保将其设置为创建FULL调试信息,然后重新部署,您现在应该获得有关崩溃原因的更详细信息。

答案 4 :(得分:4)

我已经看到了导致Debug和Release版本之间出现问题的时序。通常,Debug构建比Release构建运行得慢。您可能想要检查代码的时间关键部分。

答案 5 :(得分:3)

如果你没有使用单线程代码,那么你可能会遇到某种竞争条件。例如,如果程序的某些部分需要在其他部分可以访问之前执行某些操作,那么它可能会在发布模式下失败,因为代码的访问过早。我们曾经遇到类似的问题,手机的某些代码在模拟器中运行良好,但在手机上运行较慢,情况根本不同。

答案 6 :(得分:3)

包含为多个客户端应用程序提供的WCF客户端的C#DLL遇到相同的问题。

发现C#客户端库中有一种方法可以访问StackTrace进行日志记录,而在调试中进行编译时会有所不同。

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

GetFrame(2)在发行版中不存在。有关此信息的更多信息,请参见:StackTrace class methods not working in release mode

有趣的是,一个VB.NET客户端受到影响,而在另一个C#.NET客户端中,它正常工作。

希望有帮助。

答案 7 :(得分:1)

我终于遇到了一个问题,终结器比预期的更快,因为我没有完全理解终结器,垃圾收集器之间的相互作用,以及当一个本地对象被认为是可收集的时(提示:它不是在关闭时)块的大括号)。如果您的代码使用终结器,您可能希望查看GC.KeepAlive()。在以下块中:

void MyFunction() 
{ 
  Foo f = new Foo();
  SomeFunction(f.SomeProp);
}
f甚至运行之前,

SomeFunction()才有资格完成定稿!如果终结者做了类似处理任何SomeProp手的事情,你可能会遇到麻烦。在致电GC.KeepAlive(f)后向SomeFunction添加来电可确保f在调用KeepAlive()之后无法完成最终确定。

编辑:毕竟,我忘了指出在发布模式下运行时这个问题更加明显。我不知道Debug构建是否为函数末尾的本地函数放置了隐式KeepAlive以获得调试器的好处,或者垃圾收集是否更具侵略性,或者是什么,但Release模式在我的情况下极大地加剧了这个问题。 / p>

答案 8 :(得分:1)

确保应用程序正在正确的平台目标下构建。这可能是一个问题,尤其是在提供或使用DLL时。查看"项目 - >属性"并选择" Build"标签。 Platform目标选项允许您在Any CPU(默认),x86或x64之间进行选择。

答案 9 :(得分:1)

首先抱歉我的英语。我知道这篇文章已经过时了,但我遇到了同样的问题,我发现在调试模式下,构建是针对 32位操作系统,而发布模式是针对 64位默认情况下。这使得用于32位的dll在发布时不起作用。如果您转到项目属性 - >构建您可以选择您想要的架构。这适合我。 再见。

答案 10 :(得分:0)

你可能知道这个,但是, 变量有时在调试和发布版本中初始化不同。 例如。 我认为变量是在VC6调试版本中自动初始化的,如果你没有初始化某些东西,这可以隐藏问题。我还认为调试阵列可能会使用sentry字节来尝试指示溢出。这也会导致不同的行为。

答案 11 :(得分:0)

我有类似的问题。我的情况是这样的: 我在类库A中定义了一些反射函数。然后我定义了一个WPF用户控件库B,它使用库A中的函数。然后我编写了一个应用程序,它使用库B中的用户控件和库A中的函数。当我使用了库B的调试版,它工作正常。但是当我使用库B的发行版时,反射函数不起作用。我还在库A中定义了其他函数。似乎只有反射函数会引起麻烦。我无法弄清楚原因。最后,我放弃并将反射函数从库A移动到库B.并且它有效。

答案 12 :(得分:0)

你解决了问题吗? 我和你有同样的问题 如果我在调试中编译dll,一切正常 如果我在发布中编译,我会得到一个空引用异常 但是如果我在某些方法调用中包含一些像上面那样的行,那么即使在释放模式下异常也会消失:
System.Diagnostics.EventLog.WriteEntry(“blablabla”,“blablabla”)

希望对你有帮助。

答案 13 :(得分:0)

在我的情况下,我的DLL消费者项目(在VS中)具有x64配置,但解决方案是在任何CPU中。 出于某种原因,在运行应用程序时,这并未与我的x64 DLL挂钩。 我将应用程序配置为x64显式平台,一切正常。

答案 14 :(得分:0)

这可能与原始问题无关,但对于运行使用以下内容的应用程序的任何人

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

该调用有可能在运行时内联到另一个程序集中的方法中,从而获得意外的输出(如MSDN documentation中所述)。

为避免这种情况,您可以将MethodImplAttribute应用于您的方法:

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

,或者您也可以改用Assembly.GetExecutingAssembly()