I am building a Service Layer in Web API OData that exposes a file management API. I have a problem with composable functions. Consider the following scenario. Particular files can be accessed in two ways: through an ID
or through a complex Path
. My original design concept was to have two URLS:
/File({IdAsGuid})
/Repositories({RepositoryName})/Libraries({libName})/Path({path})/api.getFileByName(name={fileName})
This worked pretty well using the ODataRoute
attributes. The next step was to support versions, which would use URL's like:
/File({IdAsGuid})/Versions({versionNumber})
/Repositories({RepositoryName})/Libraries({libName})/Path({path})/api.getFileByName(name={fileName})/Versions({versionNumber})
Using an EntitySet
"Versions" as a path segment was no problem or the first URL. However, OData refused to validate the EntitySet
used after the function call. The error:
The segment 'eBesNg.getContentByName' must be the last segment in the URI because it is one of the following: $ref, $batch, $count, $value, $metadata, a named media resource, an action, a noncomposable function, an action import, a noncomposable function import, an operation with void return type, or an operation import with void return type.
After some research, I realized that the function is defined as follows:
builder.Namespace = "api";
var function = builder.EntityType<Path>().Function("getFileByName");
function.Parameter<string>("name");
function.ReturnsFromEntitySet<File>("Files");
And may additionally require:
function.IsComposable = true;
However, this created a different issue. Now, during the OData validation, I receive a NullReferenceException
:
[NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreatePropertySegment(ODataPathSegment previous, IEdmProperty property, String queryPortion) +205
Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateNextSegment(String text) +405
Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection'1 segments) +244
Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection'1 segments, ODataUriParserConfiguration configuration) +96
Microsoft.OData.Core.UriParser.ODataUriParser.ParsePathImplementation() +205
What am I missing? Is it not possible to use functions for navigation and continue to navigate on results in OData?
You should properly set the
EntitySetPath
of your function. That is, replace:With
Here is a complete sample: