$id and $ref are required. This is a given. When serialising an object graph you need them to deal with circular references. The only way to deal with a circular reference is to add a $ref pointing to the $id of the circular ref'd object.
However, we can remove all instances of $id which do not have a corresponding $ref, since they are redundant. From #696 (comment)
IMO you should serialize directly to LINQ to JSON objects, navigate through the object tree and remove the $id properties that don't have a corresponding $ref, then ToString() to get the JSON and print it.