As you indicated, professional attackers can see and decode VB.Net applications, and hence, as an initial conclusion, you cannot reliably protect your code. In the first step, you must encrypt your code by using several encryption techniques such as the one mentioned by @Always_a_learner. However, this will not 100% protect your code from reverse-engineering (A good discussion could be found here).
A good trick in such cases is to make some intentional dependencies. For example, some core calculations should be done by the server (if possible) and only the result should be returned to the client. More explanation, for core calculations, the client should send a request to the server, and the server first verifies the requester (the sender) validity state, and if she is a valid user, then runs calculations and returns results to the user.
This solution is fine only if you can trade-off between speed and security.