Search code examples
odataurl-routing

How to EnableCaseInsensitive, EnableEnumPrefixFree and EnableUnqualifiedNameCall in OData v6.0.0


I recently updated OData from (v5.9.1) to the latest stable version (v6.0.0) and in the former one I used to configure my environment like this:

        //Allows calling the Url like {entityAction}/{id}
        config.SetUrlConventions(ODataUrlConventions.KeyAsSegment);

        //Allows urls to be case insensitive
        config.EnableCaseInsensitive(true);

        // Remove the necessity of having to specify the namespace of enums.
        config.EnableEnumPrefixFree(true);

        //This allows call a function without using the full namespace.
        config.EnableUnqualifiedNameCall(true);

        config.MapODataServiceRoute("odata", "api/rest",
        edmModel, new  DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));

Now after the update, how can I achieve the same result as before? None of my routes e.g: 'localhost/odata/people/' are working it shows the following message:

The path template 'people/{parentId}/emails' on the action 'Get' in controller 'PersonEmails' is not a valid OData path template. The operation import overloads matching 'people' are invalid. This is most likely an error in the IEdmModel.

Any ideas? Thanks in advance.


Solution

  • I encountered the same issue. There is an internal class in System.Web.OData called UnqualifiedCallAndEnumPrefixFreeResolver. This in theory would handle both EnumPrefixFree and UnqualifiedNameCall, but as this is internal i had to write my own for now.

    public class UnqualifiedCallAndEnumPrefixFreeResolver : ODataUriResolver
    {
        private readonly StringAsEnumResolver _stringAsEnum = new StringAsEnumResolver();
        private readonly UnqualifiedODataUriResolver _unqualified = new UnqualifiedODataUriResolver();
    
        private bool _enableCaseInsensitive;
    
        public override bool EnableCaseInsensitive
        {
            get { return this._enableCaseInsensitive; }
            set
            {
                this._enableCaseInsensitive = value;
                _stringAsEnum.EnableCaseInsensitive = this._enableCaseInsensitive;
                _unqualified.EnableCaseInsensitive = this._enableCaseInsensitive;
            }
        }
    
        #region UnqualifiedODataUriResolver
    
        public override IEnumerable<IEdmOperation> ResolveBoundOperations(IEdmModel model, string identifier,
            IEdmType bindingType)
        {
            return _unqualified.ResolveBoundOperations(model, identifier, bindingType);
        }
    
        public override IEnumerable<IEdmOperation> ResolveUnboundOperations(IEdmModel model, string identifier)
        {
            return _unqualified.ResolveUnboundOperations(model, identifier);
        }
    
        #endregion
    
        #region StringAsEnumResolver
    
        public override void PromoteBinaryOperandTypes(BinaryOperatorKind binaryOperatorKind,
            ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference)
        {
            _stringAsEnum.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference);
        }
    
        public override IEnumerable<KeyValuePair<string, object>> ResolveKeys(IEdmEntityType type,
            IDictionary<string, string> namedValues, Func<IEdmTypeReference, string, object> convertFunc)
        {
            return _stringAsEnum.ResolveKeys(type, namedValues, convertFunc);
        }
    
        public override IEnumerable<KeyValuePair<string, object>> ResolveKeys(IEdmEntityType type,
            IList<string> positionalValues, Func<IEdmTypeReference, string, object> convertFunc)
        {
            return _stringAsEnum.ResolveKeys(type, positionalValues, convertFunc);
        }
    
        public override IDictionary<IEdmOperationParameter, SingleValueNode> ResolveOperationParameters(
            IEdmOperation operation, IDictionary<string, SingleValueNode> input)
        {
            return _stringAsEnum.ResolveOperationParameters(operation, input);
        }
    
        #endregion
    }
    

    The usage would be as follows:

     configuration.MapODataServiceRoute(
                "ODataRoute",
                null,
                builder =>
                    builder.AddService(ServiceLifetime.Singleton, sp => BuildModel())
                        .AddService<IEnumerable<IODataRoutingConvention>>(ServiceLifetime.Singleton, sp =>
                                ODataRoutingConventions.CreateDefaultWithAttributeRouting("ODataRoute", configuration))
                        .AddService<ODataUriResolver>(ServiceLifetime.Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver
                        {
                            EnableCaseInsensitive = true
                        })
            );          
    

    I also posted this on GitHub as an issue, but for now no answer from the team, this workarround is an alternative until we get something in standard.

    Github link

    Regards, Mihai