在OData客户端扩展dataservicquery时出现错误



我正在测试OData .Net客户端如下:

static void Main(string[] args)
    {
        var dataServiceContext = new Container(new Uri("http://localhost.fiddler:6851/"));
        var selectedOrders = from order in dataServiceContext.Orders.Expand("OrderDetails")
                                where order.OrderId==1
                                select order;
        DataServiceCollection<Order> orders = new DataServiceCollection<Order>(selectedOrders);        
        // Update Navigation
        orders[0].OrderDetails[0].Quantity=9999;
        dataServiceContext.SaveChanges();
    }

我得到了一个异常

"When writing a JSON response, a user model must be specified and the entity set and entity type must be passed to the ODataMessageWriter.CreateODataEntryWriter method or the ODataFeedAndEntrySerializationInfo must be set on the ODataEntry or ODataFeed that is being written."

我还用

在浏览器中测试了相同的服务
http://localhost:6851/Orders(1)?$expand=OrderDetails
然后,服务返回
{ "@odata.context":"http://localhost:6851/$metadata#Orders/$entity","OrderId":1,"CustomerId":"KKKK9","OrderDetails":[
   {
      "OrderDetailId":1,"OrderId":1,"ProductId":1,"UnitPrice":10.00,"Quantity":1
   },
   {
      "OrderDetailId":2,"OrderId":1,"ProductId":2,"UnitPrice":20.00,"Quantity":2
   },
   {
      "OrderDetailId":6,"OrderId":1,"ProductId":3,"UnitPrice":30.00,"Quantity":33
   }
]}

Fiddler也捕获相同的json数据到客户端程序,但客户端模块不读取它并引发异常。

如果我删除"expand",它会正常工作。

我做错了什么

我可以在。net Core 3.1中使用TripPin OData V4示例服务重现问题,如下所示:

using System;
using System.Net.Http;
using Simple.OData.Client;
namespace odata_simpleclient
{
    class Program
    {
        static async System.Threading.Tasks.Task Main(string[] args)
        {
            HttpClientHandler clientHandler = new HttpClientHandler();
            clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
            HttpClient httpClient = new HttpClient(clientHandler);
            var settings = new ODataClientSettings(httpClient);
            settings.BaseUri = new Uri("https://services.odata.org/TripPinRESTierService/(S(juqvmnem2qpijynyewk4pld5))/");
            var client = new ODataClient(settings);
            var result = await client
                .For("People")
                .Key("russellwhyte")
                .NavigateTo("Trips")
                .FindEntriesAsync();
            Console.WriteLine(result);
        }
    }
}

异常发生:CLR/Microsoft.OData.ODataException在编写JSON响应时,必须指定用户模型,并指定实体集和实体类型必须传递给ODataMessageWriter。方法或ODataResourceSerializationInfo必须在ODataResource或ODataResourceSet

:

这个问题影响了我们在实体集中没有NavigationPropertyBinding

当尝试另一个服务端点时,它可以工作。

settings.BaseUri = new Uri("https://services.odata.org/v4/TripPinServiceRW/");

与后者的区别在于ContainsTarget="true" NavigationProperty。

<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.Service.Sample.TrippinInMemory.Models.Trip)" />
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" ContainsTarget="true" />

这可以通过用Contained属性注释数据模型来添加:

[Contained]
public List<Trip> Trips { get; set; }

作为备选方案,还可以使用odatacontionmodelbuilder添加包含关系。

var modelBuilder = new ODataConventionModelBuilder();
modelBuilder
    .EntityType<Person>()
    .ContainsMany(p => p.Trips);

最新更新