As many articles point out it is important to load dynamic control in the Init event of the life cycle. This is important if you want to preserve the view state.
Another thing I found out… you need to instantiate the control, add it to a ControlCollection and then set the properties of the control. If you set the properties before it is added to a ControlCollection. The view state does not work.
This is wrong
BaseProductControl control = (BaseProductControl)this.Page.LoadControl(product.ViewControl);
control.ProductId = productId;
ProductViewPlaceHolder.Controls.Add(control);
This will work
BaseProductControl control = (BaseProductControl)this.Page.LoadControl(product.ViewControl);
ProductViewPlaceHolder.Controls.Add(control);
control.ProductId = productId;