MulticastDelegate exception being thrown only in production environment

587 Views Asked by At

I have a very weird issue occurring only in production environment. The exception has the message

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

The method where the exception is being thrown is very simple, and worked for a long time, so the problem must be an obscure dependency in the environment, or something like that...

I'm using ASP.NET Web API, hosted in Azure, and the action method of controller is executed via AJAX.

Here is the code where the exception was thrown:

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);
    }
}

Here is the relevant part of stack trace:

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)

Someone can figure out the possible causes of this exception? Thanks in advance.

3

There are 3 best solutions below

2
On BEST ANSWER

The problem lays with the fact that message is actually null. You can reproduce this quite easily:

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);
}

What happens is that message.Contains is passed to Func<string, bool> constructor via the method group conversion, it looks like this:

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

And that is what causes MulticastDelegate to go bananas. You can also see that in the generated IL:

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

In order for this not to happen, make sure you null check message as well:

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);
}
3
On

Fails when message is null. Can use this

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

The delegate having a null this is the method string.Contains() used towards the end, which uses your message variable as the this pointer. In other words, there is a call made where message is null.