when you are doing
BitcoinAddress address1 = **pubKey**.Derive([some client data]).PubKey.GetAddress(Network.Main);
You are getting the bitcoin address, but not the master public key. (ExtPubKey)
A HD pub key have more information than just the pubkey.
The correct code is
string wifStr = **pubkey**.Derive([some client data]).ToString(Network.Main)
Then you can reload it
ExtPubKey key = ExtPubKey.Parse(wifStr)
In fact, the string format of an ExtPubKey have the Network to which it belong, that's why you also have the type "BitcoinExtKey" which represent in object oriented form both : the ExtPubKey AND the Network. If you need it :
BitcoinExtPubKey wif = **pubkey**.GetWif(Network.Main)
Take a look at my book, there is other code samples around HD keys.
Concerning the best practices, there is no silver bullet right now. I created an API called RapidBase which permit you to create wallet and add addresses to monitor in this wallet. (You can find it on github)
You can try it if you want, but it is very unstable for now (API wise), so expect things to change in the future. If you are using blockr, I think your best bet is to request each addresses as you are doing.
If you are using bitcoinq RPC, you can add address, but it takes time since bitcoin core will rescan the blockchain for fetching the relevant transactions each time.
I might be wrong, but for now there is no easy to use solution, exception rapidbase I developed, that is not very stable for now.