"'HttpRequestMessageProperties' does not contain a definition for 'PathHandler'" despite using System.Web.Odata.Extensions

Viewed 1207

I'm currently learning how to create OData services with MS's ASP.NET web API guide . In the Helpers section, trying to grab the field HttpRequestMessage.ODataProperties().PathHandler or ...Model throws the above error. According to MS's documentation, the import System.Web.OData.Extensions should be right.

Working with 6.13.0 for Odata.Client and 7.0.0 for Odata.Core.

Relevant code, basically 1:1 with the web api guide:

using Microsoft.OData;
using Microsoft.OData.UriParser;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Routing;
using System.Web.OData.Extensions;

namespace WebApiGuide {
public static class Helpers
{
    public static TKey GetKeyFromUri<TKey>(HttpRequestMessage Request, Uri uri)
    {
        if (uri == null)
        {
            throw new ArgumentNullException("uri");
        }

        var urlHelper = Request.GetUrlHelper() ?? new UrlHelper(Request);

        string serviceRoot = urlHelper.CreateODataLink(
            Request.ODataProperties().RouteName,
            Request.ODataProperties().PathHandler, new List<ODataPathSegment>());
        var odataPath = Request.ODataProperties().PathHandler.Parse(
            Request.ODataProperties().Model,
            serviceRoot, uri.LocalPath);

        var keySegment = odataPath.Segments.OfType<KeyValuePathSegment>().FirstOrDefault();
        if (keySegment == null)
        {
            throw new InvalidOperationException("The link does not contain a key");
        }

        var value = ODataUriUtils.ConvertFromUriLiteral(keySegment.Value, ODataVersion.V4);
        return (TKey)value;
    }
}
}

Edit: If it makes the issue any more specific, I have the same issue with KeyValuePathSegment which is in System.Web.OData.Routing

3 Answers

For anyone else ending up here for the same reasons I did, here's my code (apparently keySegment also changed and the Value contains the already converted object):

public static TKey GetKeyFromUri<TKey>(HttpRequestMessage request, Uri uri)
{
    if (uri == null)
    {
        throw new ArgumentNullException(nameof(uri));
    }

    var urlHelper = request.GetUrlHelper() ?? new UrlHelper(request);
    var serviceRoot = urlHelper.CreateODataLink(request.ODataProperties().RouteName, request.GetPathHandler(), new List<ODataPathSegment>());
    var odataPath = request.GetPathHandler().Parse(serviceRoot, uri.LocalPath, request.GetRequestContainer());

    var keySegment = odataPath.Segments.OfType<KeySegment>().FirstOrDefault();
    if (keySegment?.Keys?.FirstOrDefault() == null)
    {
        throw new InvalidOperationException("The link does not contain a key.");
    }

    return (TKey)keySegment.Keys.First().Value;
}

This is an old question, but you can use the GetPathHandler() extension method on the HttpRequestMessage class. So instead of Request.ODataProperties().PathHandler, you can use Request.GetPathHandler().

I hope this helps someone else with this problem.

In case you use the Microsoft.AspNet.OData.ODataController. The ODataController inherits from Microsoft.AspNetCore.Mvc.ControllerBase. In this base controller class you cannot find a HttpRequestMessage but a HttpRequest. So you need to adapt more code:

    public static Microsoft.AspNet.OData.Routing.ODataPath CreateODataPath(this HttpRequest request, Uri uri)
    {
        var pathHandler = request.GetPathHandler();
        var serviceRoot = request.GetUrlHelper().CreateODataLink(
                                request.ODataFeature().RouteName,
                                pathHandler,
                                new List<ODataPathSegment>());

        return pathHandler.Parse(serviceRoot, uri.LocalPath, request.GetRequestContainer());
    }

    public static TKey GetKeyValue<TKey>(this HttpRequest request, Uri uri)
    {
        if (uri == null)
        {
            throw new ArgumentNullException("uri");
        }

        //get the odata path Ex: ~/entityset/key/$links/navigation
        var odataPath = request.CreateODataPath(uri);
        var keySegment = odataPath.Segments.OfType<KeySegment>().LastOrDefault();
        if (keySegment == null)
        {
            throw new InvalidOperationException("This link does not contain a key.");
        }

        return (TKey)keySegment.Keys.First().Value;
    }

Part of this code come from https://stackoverflow.com/a/54111132/196526 where you can get more information. Maybe.

Related