I can't add anything much to Hans' answer except to say that one of the biggest traps I have seen is that people tend to expect that when the DataReceived event fires, all of the bytes they would like to receive are all present.
e.g. if your message protocol is 20 bytes long, the DataReceived event fires and you try to read 20 bytes. They may all be there, they may not. Pretty likely that they won't be, depending on your baud rate.
You need to check the BytesToRead property of the port you are reading from, and Read that amount into your buffer. If and when more bytes are available, the DataReceived event will fire again.
Note that the DataReceived event will fire when the number of bytes to receive is at least equal to the ReceivedBytesThreshold property of the serial port. By default I believe this is set to a value of 1.
If you set this to 10 for example, the event will fire when there are 10 or more bytes waiting to be received, but not fewer. This may or may not cause problems, and it is my personal preference to leave this property value set to 1, so that all data received will fire the event, even if only 1 byte is received.
Do not make the mistake that this will cause the event to fire for every single byte received - it won't do that.