According to OData-CSDL, section 14.4.4 services can define client-side functions outside the odata namespace.
- Can they be defined like server-side functions, through edm:Function? (I think yes, because the client should be able to delegate their execution to the server.)
- Does edm:Function need an attribute ClientSide="true"? (I think yes, if this means: can only be executed by the client.)
- Or perhaps a new core annotation (no need to wait for the next CSDL version):
<Term Name="ClientSideOnly" AppliesTo="Function" Type="Core.Tag" Nullable="false" DefaultValue="true"> <Annotation Term="Core.Description" String="Client-side function as in [OData-CSDL, section 14.4.4](https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_ApplyClientSideFunction) that cannot be executed by the server"/> <Annotation Term="Core.LongDescription" String="A function without this tag can also occur as a client-side function in an apply expression for an annotation. The client can then delegate the execution to the server by `$compute`-ing the function."/> </Term>
But such a tag is dangerous, since clients that do not understand might wrongly invoke the function on the server.
A function without this tag can occur in an annotation that is contributed by a proxy between OData client and server. Continuing the example from ODATA-1420, assume the proxy contributes the following annotation:
<Schema Namespace="SalesOrderServer"> <EntityType Name="SalesOrderItem"> <Property Name="Pieces" Type="Edm.Int"/> <Property Name="Price" Type="Edm.Decimal"/> <Annotation Term="PAngV.PriceSection2"> <Apply Function="SalesOrderServer.PricePerPiece"> <Path>Price</Path> <Path>Pieces</Path> </Apply> </Annotation> </EntityType> </Schema>
The proxy would then convert the request
GET ~/SalesOrderItems?$select=ItemNo,@PAngV.PriceSection2
into
GET ~/SalesOrderItems?$select=ItemNo &$compute=SalesOrderServer.PricePerPiece(Price=Price,Pieces=Pieces) as PriceSection2
forward the converted request to the SalesOrderServer and rename JSON property PriceSection2 to @PAngV.PriceSection2 in the response, effectively handling the instance annotation @PAngV.PriceSection2 like an additional property.
This examples assumes that the SalesOrderServer.PricePerPiece function is implemented on the server. If the server declared that function ClientSideOnly, or if the function was contributed by the proxy instead, then the proxy would send the following metadata to the client:
<Schema Namespace="SalesOrderServer"> <!-- namespace of server --> <EntityType Name="SalesOrderItem"> <Property Name="Pieces" Type="Edm.Int"/> <Property Name="Price" Type="Edm.Decimal"/> <Annotation Term="PAngV.PriceSection2"> <Apply Function="PAngV.PricePerPiece"> <Path>Price</Path> <Path>Pieces</Path> </Apply> </Annotation> </EntityType> </Schema> <Schema Namespace="PAngV"> <!-- namespace of proxy --> <Function Name="PricePerPiece"> <Annotation Term="Core.ClientSideOnly" Bool="false"/> ... </Function> </Schema>
and the proxy would request
GET ~/SalesOrderItems?$select=ItemNo,Price,Pieces
from the server and perform the computation of @PAngV.PriceSection2 itself.