Instance annotations are not written by default
When the caller adds instance annotations to a response resource, those annotations are only included in the response payload if the client has provided the Prefer: odata.include-annotations= request header. We should included instance annotations added by the caller by default and honor the Prefer header by filtering out those annotations which do not meet the header.
To add some clarity, the issue is around developer usability. The standard allows the service to return whatever instance annotations it wants. The current ODL implementation will only include the instance annotations if the Prefer header is provided; the implementation will also include instance annotations that OData itself provides.
The usability issue comes when the developer directly adds an instance annotation to a response resource. When they do this, the annotation is only returned if the client includes the Prefer header. This is a case that should be supported, but the more common case is that the developer is adding the instance annotation to the resource because they would like to return the annotation regardless of if the client has asked for it with the header.
I want to add some of the clarifications @corranrogue9 made offline for completeness
Let's say the caller has added annotations to the ODataResource, but there's no Prefer header set, does that mean we should write those annotations?
I think that the developer should have some way to specify this, ideally at each level of processing. So, it would be good if the developer can say "for this annotation, return it even if there's no header" and also say "for this type of annotation, return it even if there's no header" and also say "for my service, always return instance annotations even if there's no header". I think the minimum should be the first though, meaning that at a minimum the developer should be able to specify per-instance-annotation whether that annotation is returned regardless of header status.
Let's say that caller has added annotations to the ODataResource, but there's Prefer: odata.include-annotations= header, does that mean we should omit the annotations added by the caller that are not specified in the odata.include-annotations= preference?
I also think this control should be in the hands of the developer. Take, for example, the graph.tips annotation that's been added recently. It gives the client some information about making more efficient requests to Graph. The graph team may decide that they want to return this annotation even if the client has omitted it from their header, or the graph team may decide that, for this kind of annotation, the prefer header should be honored.
The ODataMessageWriterSettings has a ShouldIncludeAnnotation property, which is a delegate that is called for each annotation. Unfortunately, this property is internal and is generated automatically based on the annotations filter in the Preference-Applied header.
One of the ways the user developer can "force" custom instance annotations to be written is to "inject" them in the response messages Preference-Applied header manually, e.g.:
IODataResponseMessage message = messageFactory(stream);
message.SetHeader("Preference-Applied", "odata.include-annotations=Test.*");
using var messageWriter = new ODataMessageWriter(message, settings, model);
This would require no code change. However, this approach is arguably not an ideal developer experience, especially if the message already has a Preference-Applied header set.
We could add a new property, simple to ShouldIncludeAnnotation but make it public, and write the annotation if either delegate returns true. What do you think @corranrogue9 ?