2

I'm unit testing a piece of code that uses a nested using statement. I've changed it to a using statement in a try/finally block. When I try to call the Dispose method in the finally block I get an EntryPointNotFoundException. I've tried a lot of things but I'm not sure how to solve this problem. Here is my code:

var memoryStream = new MemoryStream(message.FileContent);

try
{
    using (var sftpClient = this.GetSftpClientFromId(message.CustomerId))
    {
        return sftpClient.UploadFileAsync(memoryStream, message.FileName, true);
    }
}
finally
{
    memoryStream?.Dispose();
}

How can I solve this issue?

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Ronald Rozema
  • 236
  • 3
  • 16
  • 3
    Shouldn't you await the result? – Patrick Hofman Mar 22 '17 at 08:34
  • have you tried to use another using block for the stream? – Sebastian L Mar 22 '17 at 08:36
  • 3
    The code is not good, because after you do `return UploadFileAsync` everything is disposed (client, stream) but file is still uploading after that (I mean your upload Task is in progress when this happens). Though it should not throw EntryPointNotFoundException anyway... Some other exception - sure, but this one I doubt that. – Evk Mar 22 '17 at 08:36
  • @PatrickHofman No the surrounding function also returns a Task – Ronald Rozema Mar 22 '17 at 08:38
  • @SebastianL yes , I have tried a nested using statement. It results in the same error – Ronald Rozema Mar 22 '17 at 08:39
  • Still, you should await it. – Patrick Hofman Mar 22 '17 at 08:40
  • The memory stream is disposed before it is used. If you wait for the upload to occur then it will work. FYI you don't really need to dispose a memory stream, Stream implements disposable, but all Dispose in memory stream does is render it useless. – satnhak Mar 22 '17 at 08:45
  • @Evk Are you saying that I do not need to Dispose the memorystream because it is already disposed? Documentation said only the variable declared in the using is disposed. How would you change this code? – Ronald Rozema Mar 22 '17 at 08:47
  • 3
    Well it was said multiple times - you need to await the result (easiest solution here). You start UploadFileAsync task but you don't wait for it to complete. Instead you return from method. return executes all using\finally blocks and so your stream and client are disposed **before** UploadFileAsync had a chance to complete. – Evk Mar 22 '17 at 08:48
  • 1
    Yes, you don't need to dispose the memory stream, it is just a wrapper around a byte array. Nothing bad will happen if you don't dispose it: the garbage collector will completely clean it up. However, as everyone has said the "right" way to fix this is to await the upload. – satnhak Mar 22 '17 at 08:51
  • https://referencesource.microsoft.com/mscorlib/system/io/memorystream.cs.html#https://referencesource.microsoft.com/mscorlib/system/io/memorystream.cs.html,396b4b852ac5e9eb,references – satnhak Mar 22 '17 at 08:51
  • Okay thanks for the help all! if someone makes an answer out of it I will accept it – Ronald Rozema Mar 22 '17 at 09:04
  • 1
    I've got no idea why someone down-voted your question. It was well asked and you added the code snipped that demonstrated the problem. Some of the people on this site just baffle me. – satnhak Mar 22 '17 at 09:22
  • The exception just does not have anything to do with the snippet. If the Dispose() method would be missing then you'd get a MissingMethodException. Well, you know that can't be it, it isn't missing. EntryPointNotFoundException is a completely different kettle of fish, it does not know where to start running the program. It probably has something to do with the unit test runner, we don't know anything about it. – Hans Passant Mar 22 '17 at 10:35
  • @HansPassant The problem was resolved by adding the await statement, so it wasn't the unit test runner – Ronald Rozema Mar 22 '17 at 10:51

1 Answers1

2

Just had this happen.

The problem ended up being:

Short version:

An assembly had a reference to an object that implemented IDisposable in a future version, but an old version was loaded at runtime. So when it tried to call Dispose(), which didn't exist in the old version, it goes ummmmm EntryPointNotFoundException!

Long version:

  • In version 1 of ThirdPartyComponent, Thing did not implement IDisposable.
  • In version 2 of ThirdPartyComponent, Thing did implement IDisposable.
  • ProjectA was built referencing version 2 of ThirdPartyComponent. IDisposable is valid, and the "using" gets compiled just fine.
  • ProjectA loaded version 1 of ThirdPartyComponent, and tries to call "Dispose()". It freaks out because there is no "Dispose()" in version 1. Of course, it should have loaded version 2, but sometimes the world isn't fair (in my case, a custom assembly loader messed up).
NightShovel
  • 3,032
  • 1
  • 31
  • 35