You can add the namespaces as part of a custom Message implementation, which includes a OnWriteStartEnvelope() method you can override and add any custom namespaces to. You then hook up the Message to a MessageFormatter and then use a MessageFormatAttribute to attach the behavior to specific methods.
The key method that adds the namespaces are on the overridden Message implementation where you can add namespaces to the Envelope:
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartElement("soapenv", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "oas", null, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
Once attached to the Envelope the rest of the document will then reuse these top level declared namespaces and not inline the namepsaces.
I wrote up a blog post that describes the full process which involves Message, MessageFormatter and FormatMessageAttribute implementations:
http://weblog.west-wind.com/posts/2016/Apr/02/Custom-Message-Formatting-in-WCF-to-add-all-Namespaces-to-the-SOAP-Envelope