仅在生产环境中抛出 MulticastDelegate 异常

MulticastDelegate exception being thrown only in production environment

我有一个非常奇怪的问题只发生在生产环境中。 异常包含消息

"Delegate to an instance method cannot have null 'this'".

抛异常的方法很简单,搞了半天,所以 问题一定是环境中的一个模糊的依赖关系,或者类似的东西...

我正在使用 ASP.NET Web API,托管在 Azure 中,控制器的操作方法是通过 AJAX 执行的。

这里是抛出异常的代码:

public class BlacklistService : IBlacklistService
{
    public bool Verify(string blacklist, string message)
    {
        if (string.IsNullOrEmpty(blacklist)) return true;
        var split = blacklist.ToLower().Split(';'); // exception is thrown here
        return !split.Any(message.Contains);
    }
}

这里是堆栈跟踪的相关部分:

at System.MulticastDelegate.ThrowNullThisInDelegateToInstance() 
at System.MulticastDelegate.CtorClosed(Object target, IntPtr methodPtr) 
at MyApp.Business.Services.BlacklistService.Verify(String blacklist, String message)
at MyApp.Business.Services.ContactMessageFactory.GetVerifiedStatus(String mensagem)
at MyApp.Business.Services.ContactMessageFactory.GetMailMessage(ContactForm contactForm)
at MyApp.Business.ContactEmailService.Send(ContactForm contactForm)

有人能找出这个异常的可能原因吗?提前致谢。

消息为空时失败。可以用这个

return !split.Any(part => (message != null && message.Contains(part)));

问题在于 message 实际上是 null。您可以很容易地重现它:

void Main()
{
    Verify("hello", null);
}

public bool Verify(string blacklist, string message)
{
    if (string.IsNullOrEmpty(blacklist)) return true;
    var split = blacklist.ToLower().Split(';'); // exception is thrown here
    return !split.Any(message.Contains);
}

发生的事情是 message.Contains 通过方法组转换传递给 Func<string, bool> 构造函数,它看起来像这样:

Func<string, bool> func = ((string)null).Contains;
return !split.Any(func);

这就是导致 MulticastDelegate 发疯的原因。在生成的IL中也可以看到:

IL_0028:  ldftn       System.String.Contains
IL_002E:  newobj      System.Func<System.String,System.Boolean>..ctor
IL_0033:  call        System.Linq.Enumerable.Any

为了避免这种情况发生,请确保您也对消息进行空检查:

public bool Verify(string blacklist, string message)
{
    if (string.IsNullOrEmpty(blacklist)) return true;
    if (string.IsNullOrEmpty(message)) return false;

    var split = blacklist.ToLower().Split(';'); // exception is thrown here
    return !split.Any(message.Contains);
}

具有空 this 的委托是最后使用的方法 string.Contains(),它使用您的 message 变量作为 this 指针。换句话说,在 message 为空的地方进行了调用。