1

I'm trying to access OData from C# using this VS extension this VS extension (which seems to be the recommended way). It generates a Connected service inside the project, to access (in my case) a Business Central API.

When I create an object (here a vendor), through this kind of code,

var context = new BCNS.NAV(new Uri(_serviceRoot));
var vendor = Vendor.CreateVendor(Guid.NewGuid());
context.AddToVendors(vendor);
context.SaveChanges();

it fails because 2 of the properties of vendore are read-only; the context sends every property in the serialized json and it fails. (if I remove them by hand it succeeds)

These 2 properties don't look different in the $metadata:

<Property Name="balance" Type="Edm.Decimal" Scale="Variable" /> 
<Property Name="lastModifiedDateTime" Type="Edm.DateTimeOffset" />

Don't jnow how it could guess they are readonly.

I've seen here how to send a partial payload during an update request, and I am desperately trying to make similar thing for a creation.

I saw there is a possible parameter "PostOnlySetProperties" for context.SaveChanges that "can only be used when using DataServiceCollection", but I fail trying to add an object through it. It seems to handle only objects it's tracking, not new ones.

Would someone know how to send a partial payload when creating a new item ?

Thanks in advance.

Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
Poc
  • 109
  • 10
  • Pls don' t take it personaly, i give this advice to anybody. IMHO OData was popular 10 years ago and I don' t know anybody who uses it now. So just forget about OData and select another technology if it is not too late – Serge Jul 12 '21 at 11:53
  • You should change to the OData Connected service implementation instead. Otherwise you could either manually override the generated proxies or edit the T4 templates that generate the classes. Please post the $metadata document fragment that corresponds to the `vendore` and the class with the readonly properties, it's not usually this hard. – Chris Schaller Jul 12 '21 at 11:56
  • 1
    @serge OData is just as relevant today, perhaps even more so, but in this case the server api is driving the requirement, in this situation you don't get a lot of options, but OP is following very old and out of date guidance on implementing an OData client. – Chris Schaller Jul 12 '21 at 11:59
  • @ChrisSchaller I just mean there is no an ideal thechnology. Otherwse only this technology wil be used. Any tech has places and munuces. I can assume that OData can save some time and money in some special casses, but in the most cases it has more minuses then pluses. It is just my humble opinion and maybe I am wrong. – Serge Jul 12 '21 at 12:20
  • @ChrisSchaller These 2 properties are the ones that are readonly (as I see nothing that says they are, I can guess why the generator does nothing about that): Actually when I search "OData Connected service implementation", google gives me the same link as the one I give for the extension. It generates code in the connected services, which I'm trying to call in my code excerpt. If there is a more modern way to do it, I'm open to it. – Poc Jul 12 '21 at 14:06
  • _you should respond to requests like that by editing your post, it's took hard to format the code correctly in comments_ – Chris Schaller Jul 12 '21 at 14:11
  • @ChrisSchaller I added them – Poc Jul 12 '21 at 14:17
  • OData Connected Service https://learn.microsoft.com/en-us/odata/connectedservice/getting-started is the current **standard** for .Net OData Clients. It has support for .Net FX and Core clients and is an actively maintained open source project that originated from the bingl implementation but has since supassed it. It fixes the issues discussed by @lokusking in your linked article and may very well fix your issue as well. You issue sounds interesting, but if you are only just starting, it will be better to start with the latest as you can get active support from the community. – Chris Schaller Jul 12 '21 at 14:17
  • I used to just edit the generator when I found issues like this, but also why not just go make the properties writeable? At least in the new project, if you find bugs and can fix them everyone benefits. – Chris Schaller Jul 12 '21 at 14:20
  • @ChrisSchaller Ok, but your link is what I'm using already, and maybe it fixes the issue for an update (I don't know), but it does not for an addition. I can't make the property writeable, it's readonly on the server, I just would like to avoid sending the useless parts of the json. I'm surprised it's so difficult. I see there is a possible parameter "PostOnlySetProperties" that "can only be used when using DataServiceCollection", but I fail trying to add an object through it. – Poc Jul 12 '21 at 14:25
  • Sounds like the $metadata is not well formed then, if it's difficult then it usually means the API is not fully compliant. You should uninstall the client code generator if you are using the connected service, there is a generational difference between the two implementations, your original post clearly states that you are using the code generator. – Chris Schaller Jul 12 '21 at 14:36
  • If its just one call that you want to _augment_ why not just write that one manually, or serilize using JSON.Net, remove the offending properties and send to the API via HttpClient? Once you've written the code its easy to reuse. – Chris Schaller Jul 12 '21 at 14:39
  • @ChrisSchaller well I wouldn't like to loose all the flexibility of the generated context. But... I downloaded the extension like last week (the one from "marketplace", but coming from MS), how could it be the wrong one ? It looks maintained, and is still in the link you gave me. Should I get "Unchase Odata Connected Service" instead ? I feel a bit dumb here, as what I did matches what you recommend but I don't get the good result. – Poc Jul 12 '21 at 15:04
  • What .Net framework are you using? legacy FX, Core 3.1 or 5? – Chris Schaller Jul 13 '21 at 00:02
  • @ChrisSchaller I added the ConnectedService into a .net standard 2.0 library. – Poc Jul 13 '21 at 02:59

1 Answers1

2

Ok, found it.

I let this answer here, cause it was so difficult to find that maybe some day it can help.

I had to use the DataServiceCollection, which, correctly initialized, works also for new elements. New elements seem to have to be initialized after (for obvious tracking reasons I guess). The following code worked.

var context = CreateContext("vendors");

DataServiceCollection<Vendor> vendors = new DataServiceCollection<Vendor>(context, "Vendor", null, null);

var vendor = new Vendor();
vendors.Add(vendor);
vendor.Id = Guid.NewGuid();
vendor.DisplayName = "Attempt to create vendor 03";

context.SaveChanges(SaveChangesOptions.PostOnlySetProperties);`

A partial payload is then sent.

Poc
  • 109
  • 10
  • Well done, a better API would not mix readonly properties like that in the payload or would simply ignore their values when the data is received. – Chris Schaller Jul 13 '21 at 13:25
  • Thank you @ChrisSchaller. I'm glad I don't have to deep dive into the Odata client source to solve this issue. – Poc Jul 14 '21 at 00:41