1

I am working with an ASP.NET Core 3.1x API that is using the Microsoft.AspNetCore.Odata v7.4.0 NuGet, and I have an ASP.NET Core 3.1v web client that is using the Simple.OData.V4.Client v5.12.0

I am trying to Post an Order object with related LineItem objects (a master/detail) from the Simple.Odata client. The Order object is being passed to the API correctly but the related LineItem collection is not.

Here is my Order class;

public class Order
{
    public Guid Id { get; set; }
    public DateTimeOffset DateOfOrder { get; set; }
    public string PurchaseOrderNumber { get; set; }
    public decimal Subtotal { get; set; }
    public decimal Discount { get; set; }
    public decimal Shipping { get; set; }
    public decimal SalesTax { get; set; }
    public decimal Total { get; set; }
    public List<OrderLineItem> OrderLineItems { get; set; } = new List<OrderLineItem>();
}

Here is my OrderLineItem class;

public class OrderLineItem : BaseModel
{
    public Guid Id { get; set; }
    public Guid OrderId { get; set; }
    public Order Order { get; set; }
    public Guid ProductId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal Discount { get; set; }
    public decimal Total { get; set; }
}

Here is the method in my ODataService of the client website application;

public async Task<Result<Order>> CreateOrderAsync(Order req, CancellationToken cancellationToken)
{
    try
    {
        var baseUrl = cdUtilities.GetBaseApiUrl();
        var accessToken = await GetAccessToken();
        var client = new ODataClient(SetODataToken(baseUrl, accessToken));
        var response = await client.For<Order>()
            .Set(req).InsertEntryAsync(cancellationToken);
        return Result.Ok(response);
    }
    catch (WebRequestException badRequest)
    {
        var odataErrorResponse = JsonConvert.DeserializeObject<ExceptionResponse>(badRequest.Response);

        var errorMessage = $"Bad Request: The API returned an HTTP Status Code 400.{Environment.NewLine}";

        if (odataErrorResponse.Error != null)
        {
            foreach (var errorDetail in odataErrorResponse.Error.Details)
            {
                errorMessage = $"{errorMessage}  {errorDetail.Message}{Environment.NewLine}";
            }
        }

        logger.LogError(badRequest, errorMessage);
        return Result.Fail<Order>(errorMessage);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, ex.Message);
        return Result.Fail<Order>(ex.Message);
    }
}

Here is the json of the Order object and the related OrderLineItem objects I am using in Postman that works correctly with my API.

{
    "@odata.context": "https://localhost:44367/v1/$metadata#Orders",
    "DateOfOrder": "2020-05-14T08:00:43.511Z",
    "PurchaseOrderNumber": "P051420200001",
    "Subtotal": 450.00,
    "Discount": 0.00,
    "Shipping": 3.45,
    "SalesTax": 28.00,
    "Total": 495.89,
    "OrderLineItems": [
        {
            "ProductId": "BF43F1C7-6796-4C92-B4DD-08D7DBE4BBCC",
            "ProductName": "Test Product 2",
            "Quantity": 6,
            "UnitPrice": 53.00,
            "Discount": 0.00,
            "Total": 318.00,
            "Length": 10.0,
            "Width": 4.0,
            "Height": 7.0,
            "Weight": 0.302,
            "DimUnit": "Inch",
            "WeightUnit": "Pound",
            "Status": "Active",
            "DeleteFlag": false
       }
    ]
}

When I post a new Order with related OrderLineItems using Postman, My API creates the Order and the related OrderLineItem records just fine. However, when I post using the Simple.OData.V4.Client the Order record gets created but not the related OrderLineItem records.

When I look at the OData API controller when Posting the record via Postman, I can see that the Order object being passed in with the included OrderLineItems.

However, when I look at the OData API controller when using the Simple.OData.V4.Client from my web application, I see that the OrderLineItems has a count of 0, so the Simple OData client is not sending the related OrderLineItem records, even though I can see them in the Order object that is passed into the CreatreOrderAsync method in the OData service of the web application.

So, I have to assume that I am missing something needed by Simple OData client to allow it to include the related records but after reviewing the Simple OData Client documentation, I cannot find an example of a master/detail type client Post method.

What am I missing here?

***** UPDATE 05/14/20 *****

Simple.Odata.Client does not support deep linking (models with realted data in a single operation). Microsoft has an OData client that is being actively updated and it does support related data. It is more complex but also seems to be more flexible (ie ODataClientFactory and DI support). Here is a link to the documentation.

The Microsoft client reminds me of what we had to do in WCF, in that we set up a proxy using Connected Services and link to the APIs meta data in Visual Studio. I do like that they support LINQ queries and I like the IOdataClientFactory so that we can unit test without an actual network call.

whiskytangofoxtrot
  • 927
  • 1
  • 13
  • 41
  • hi, you might want to follow this github issue https://github.com/simple-odata-client/Simple.OData.Client/issues/127 – Michael Schönbauer May 15 '20 at 11:23
  • Well, as it turns out, Simple.OData.Clint does not support deep linking for related data and it doesn't look like it will be added anytime soon. It does seem that Microsoft is maintaining their OData client and it does support related data. @MichaelSchönbauer if you want to post as an answer, I will mark it as such for the points – whiskytangofoxtrot May 15 '20 at 15:22
  • thanks but too much honor (and paperworks ;) – Michael Schönbauer May 15 '20 at 17:11

0 Answers0