It depends, of course, on your goals. In our application, most (not all, we have many developers and not everyone does it the same -- but we try) of the message contracts are entirely interface-only data types.
For instance, List<T> is mutable, so we use T[] (arrays). And we typically drop the IXxx convention since they are behavior-free data bags, it just makes it cleaner and easier to read.
So we have:
public interface Order {
OrderLine[] Lines {get;}
}
public interface OrderLine {
string ItemId {get;}
string Description {get;}
decimal UnitPrice {get;}
}
Notice that there are no {set;} methods on the properties, that would allow a consumer to modify the message content.
In a large application (easily 100+ decoupled services, coordinated through Courier routing slips, with over 200 consumers for various events and state machines) this has worked very well.