How could that be? Your internal ReadAsync is probably awaiting on an asynchronous operation to be complete, while you're blocking a thread. If this thread is for example, the UI message loop thread, it's currently blocked. When your await completes (assuming you didn't use ConfigureAwait(false) internally), it would deadlock when trying to marshal back the continuations onto it.

When writing async code, you will have some amount of code duplication, there is no getting around that. Attempt to reuse as much as you can. for example, if both code methods have a synchronous part at the beginning, you can extract that to a third method which both async and sync versions will consume.