8000 C# Client fails to deserialize response from action bound to a contained entity · Issue #946 · OData/AspNetCoreOData · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
8000

C# Client fails to deserialize response from action bound to a contained entity #946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
henning-krause opened this issue May 30, 2023 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@henning-krause
Copy link

I have an application that has an entity set ("DataItem") which in turn contains a contained entityset ("NestedItem") (See SampleApplication.zip).

There is also an action bound to a specific DataItem which creates an instance of NestedItem.

My data model looks like this:

        public class BackendDataContext
	{
		private readonly IList<DataItem> _Items = new List<DataItem>();

		public BackendDataContext()
		{
			_Items.Add(new DataItem("Test"));
		}

		public IQueryable<DataItem> DataItems => _Items.AsQueryable();

	}

	public class NestedItem
	{
		private static int _Id;

		[Key]
		public int Id { get; set; }
		public string Name { get; set; }

		public NestedItem(string name)
		{
			Id = ++_Id;
			Name = name;
		}
	}

	public class DataItem
	{
		private static int _Id;

		[Key]
		public int Id { get; set; }
		public string Name { get; set; }
		[Contained] public List<NestedItem> NestedItems { get; set; } = new List<NestedItem>();


		public DataItem(string name)
		{
			Id = ++_Id;
			Name = name;
		}
		
	}

This is my EDM model:

builder.EntitySet<DataItem>("DataItems");
builder.EntityType<NestedItem>();
builder.EntityType<DataItem>()
    .Action("TestAction")
    .ReturnsEntityViaEntitySetPath<NestedItem>("bindingParameter/NestedItems");

My controller looks like this and works returns a new instance:

        public class DataItemsController : ODataController
	{
		protected BackendDataContext Context { get; } = new BackendDataContext();


		[EnableQuery(PageSize = 512, EnsureStableOrdering = false)]
		public IQueryable<DataItem> Get()
		{
			return Context.DataItems;
		}

		[EnableQuery(PageSize = 512, EnsureStableOrdering = false)]
		public SingleResult<DataItem> Get([FromODataUri] int key)
		{
			return SingleResult.Create(Context.DataItems.Where(e => e.Id == key));
		}

		[HttpPost]
		public IHttpActionResult TestAction([FromODataUri] int key, ODataActionParameters parameters)
		{
			return Created(new NestedItem($"Test for {key}"));
		}
	}

When I call the test action with this request:

POST http://localhost:7071/odata/v4/DataItems(0)/Backend.TestAction HTTP/1.1
OData-MaxVersion: 4.0
Accept: application/json;odata.metadata=minimal
Accept-Charset: UTF-8
User-Agent: Microsoft.OData.Client/7.16.0
Host: localhost:7071
Content-Length: 0

I get this response:

HTTP/1.1 201 Created
Content-Length: 124
Content-Type: application/json; odata.metadata=minimal; charset=utf-8
Location: http://localhost:7071/odata/v4/DataItems(0)/NestedItems(1)
Server: Microsoft-HTTPAPI/2.0
OData-Version: 4.0
Date: Tue, 30 May 2023 06:25:07 GMT

{"@odata.context":"http://localhost:7071/odata/v4/$metadata#DataItems/NestedItems/$entity","Id":1,"Name":"Test for 0"}

And the culprit, I think, is that the context is incorrect.

It is:

http://localhost:7071/odata/v4/$metadata#DataItems/NestedItems/$entity

8000

But shouldn't it be this?

http://localhost:7071/odata/v4/$metadata#DataItems(1)/NestedItems/$entity

The client app is complaining:

System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)

This exception is thrown when the method KeysAsSegmentsLiteralParser.TryParseLiteral is called with the value "NestedItem" instead of a key.

The next exception then is this:

Microsoft.OData.Client.DataServiceQueryException: An error occurred while processing this request. ---> System.InvalidOperationException: The response payload is a not a valid response payload. Please make sure that the top level element is a valid Atom or JSON element or belongs to 'http://docs.oasis-open.org/odata/ns/data' namespace.
   at Microsoft.OData.Client.Materialization.ODataMaterializer.CreateODataMessageReader(IODataResponseMessage responseMessage, ResponseInfo responseInfo, ODataPayloadKind& payloadKind)
   at Microsoft.OData.Client.Materialization.ODataMaterializer.CreateMaterializerForMessage(IODataResponseMessage responseMessage, ResponseInfo responseInfo, Type materializerType, QueryComponents queryComponents, ProjectionPlan plan, ODataPayloadKind payloadKind, MaterializerCache materializerCache)
   at Microsoft.OData.Client.MaterializeAtom..ctor(ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind, MaterializerCache materializerCache)
   at Microsoft.OData.Client.QueryResult.CreateMaterializer(ProjectionPlan plan, ODataPayloadKind payloadKind)
   at Microsoft.OData.Client.QueryResult.ProcessResult[TElement](ProjectionPlan plan)
   at Microsoft.OData.Client.DataServiceRequest.Execute[TElement](DataServiceContext context, QueryComponents queryComponents)
   --- End of inner exception stack trace ---
   at Microsoft.OData.Client.DataServiceRequest.Execute[TElement](DataServiceContext context, QueryComponents queryComponents)
   at Microsoft.OData.Client.DataServiceContext.InnerSynchExecute[TElement](Uri requestUri, String httpMethod, Nullable`1 singleResult, OperationParameter[] operationParameters)
   at Microsoft.OData.Client.DataServiceContext.Execute[TElement](Uri requestUri, String httpMethod, Boolean singleResult, OperationParameter[] operationParameters)
   at Microsoft.OData.Client.DataServiceActionQuerySingle`1.GetValue()
   at Frontend.Program.Main() in C:\Users\hkrause\Downloads\SampleApplication\Frontend\Program.cs:line 14

Microsoft.OData.Client 7.16.0

Reproduce steps

The sample application linked obove contains a full repo.

Expected result

The client can deserialize the response from the server

Actual result

The exception mentioned above is thrown.

Additional detail

None

@habbes habbes added the bug Something isn't working label May 30, 2023
@habbes habbes transferred this issue from OData/odata.net May 30, 2023
@habbes
Copy link
Contributor
habbes commented May 30, 2023

This appears to be a bug. We should be able to determine the appropriate context URL since we have information about the parent in the request URL. We seem to be generating the location URL correctly.

@henning-krause
Copy link
Author

Since this was moved to AspNetCoreOData - I'm have this problem on .NET 4.8. It would be nice if this bug is fixed for both projects (WebApi).

@mikepizzo
Copy link
Member

Perhaps related to #691.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants
0