Skip to content

Commit 5059372

Browse files
authored
Support writing nested entities without a navigation source. (#996)
* Support writing nested entities without a navigation source. * Added Tests * Apply suggested improvements for disposing resources in tests.
1 parent c2b19f3 commit 5059372

File tree

2 files changed

+92
-7
lines changed

2 files changed

+92
-7
lines changed

src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataResourceSerializer.cs

+10-7
Original file line numberDiff line numberDiff line change
@@ -1179,22 +1179,25 @@ public virtual ODataNestedResourceInfo CreateNavigationLink(IEdmNavigationProper
11791179
IEdmNavigationSource navigationSource = writeContext.NavigationSource;
11801180
ODataNestedResourceInfo navigationLink = null;
11811181

1182-
if (navigationSource != null && navigationProperty.Type != null)
1182+
if (navigationProperty.Type != null)
11831183
{
11841184
IEdmTypeReference propertyType = navigationProperty.Type;
1185-
IEdmModel model = writeContext.Model;
1186-
NavigationSourceLinkBuilderAnnotation linkBuilder = EdmModelLinkBuilderExtensions.GetNavigationSourceLinkBuilder(model, navigationSource);
1187-
Uri navigationUrl = linkBuilder.BuildNavigationLink(resourceContext, navigationProperty, writeContext.MetadataLevel);
1188-
11891185
navigationLink = new ODataNestedResourceInfo
11901186
{
11911187
IsCollection = propertyType.IsCollection(),
11921188
Name = navigationProperty.Name,
11931189
};
11941190

1195-
if (navigationUrl != null)
1191+
if (navigationSource != null)
11961192
{
1197-
navigationLink.Url = navigationUrl;
1193+
IEdmModel model = writeContext.Model;
1194+
NavigationSourceLinkBuilderAnnotation linkBuilder = EdmModelLinkBuilderExtensions.GetNavigationSourceLinkBuilder(model, navigationSource);
1195+
Uri navigationUrl = linkBuilder.BuildNavigationLink(resourceContext, navigationProperty, writeContext.MetadataLevel);
1196+
1197+
if (navigationUrl != null)
1198+
{
1199+
navigationLink.Url = navigationUrl;
1200+
}
11981201
}
11991202
}
12001203

test/Microsoft.AspNetCore.OData.Tests/Formatter/Serialization/ODataResourceSerializerTests.cs

+82
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
using System;
99
using System.Collections.Generic;
10+
using System.IO;
1011
using System.Linq;
12+
using System.Reflection.Metadata;
13+
using System.Runtime.CompilerServices;
1114
using System.Runtime.Serialization;
1215
using System.Threading.Tasks;
1316
using Microsoft.AspNetCore.OData.Abstracts;
@@ -20,6 +23,7 @@
2023
using Microsoft.AspNetCore.OData.Tests.Edm;
2124
using Microsoft.AspNetCore.OData.Tests.Extensions;
2225
using Microsoft.AspNetCore.OData.Tests.Models;
26+
using Microsoft.AspNetCore.Rewrite;
2327
using Microsoft.Extensions.DependencyInjection;
2428
using Microsoft.Net.Http.Headers;
2529
using Microsoft.OData;
@@ -2249,6 +2253,78 @@ public async Task WriteObjectInlineAsync_SetsParentContext_ForExpandedNavigation
22492253
It.Is<ODataSerializerContext>(c => c.ExpandedResource.SerializerContext == _writeContext)));
22502254
}
22512255

2256+
[Fact]
2257+
public async Task WriteObjectInlineAsync_Writes_Nested_Entities_Without_NavigationSource()
2258+
{
2259+
// Arrange
2260+
ODataModelBuilder builder = new ODataConventionModelBuilder();
2261+
builder.Namespace = "Default";
2262+
builder.EntityType<Product>();
2263+
builder.ComplexType<Result>();
2264+
var model = builder.GetEdmModel();
2265+
2266+
var result = new Result
2267+
{
2268+
Title = "myResult",
2269+
Products = new Product[]
2270+
{
2271+
new Product
2272+
{
2273+
ProductID = 1
2274+
},
2275+
new Product
2276+
{
2277+
ProductID = 2
2278+
}
2279+
}
2280+
};
2281+
2282+
var resultType = model.FindType("Default.Result") as IEdmComplexType;
2283+
var resultTypeReference = new EdmComplexTypeReference(resultType as IEdmComplexType, false);
2284+
var titleProperty = resultTypeReference.FindProperty("Title") as IEdmStructuralProperty;
2285+
var productsProperty = resultTypeReference.FindNavigationProperty("Products");
2286+
var selectExpand = new SelectExpandClause(new SelectItem[]
2287+
{
2288+
new PathSelectItem(new ODataSelectPath(new PropertySegment(titleProperty))),
2289+
new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(productsProperty, null)),null,null)
2290+
},
2291+
false);
2292+
2293+
var writeContext = new ODataSerializerContext()
2294+
{
2295+
Model = model,
2296+
SelectExpandClause = selectExpand
2297+
};
2298+
2299+
using (var stream = new MemoryStream())
2300+
{
2301+
IODataResponseMessage responseMessage = new ODataMessageWrapper(stream);
2302+
ODataUri uri = new ODataUri { ServiceRoot = new Uri("http://myService", UriKind.Absolute) };
2303+
ODataMessageWriterSettings settings = new ODataMessageWriterSettings
2304+
{
2305+
ODataUri = uri
2306+
};
2307+
2308+
using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, settings))
2309+
{
2310+
ODataWriter writer = await messageWriter.CreateODataResourceWriterAsync(null, resultType as IEdmComplexType);
2311+
ODataResourceSerializer serializer = new ODataResourceSerializer(_serializerProvider);
2312+
2313+
// Act
2314+
await serializer.WriteObjectInlineAsync(result, resultTypeReference, writer, writeContext);
2315+
2316+
// Assert
2317+
stream.Position = 0;
2318+
using (StreamReader reader = new StreamReader(stream))
2319+
{
2320+
string response = reader.ReadToEnd();
2321+
Assert.Contains(@"""ProductID"":1", response);
2322+
Assert.Contains(@"""ProductID"":2", response);
2323+
}
2324+
}
2325+
}
2326+
}
2327+
22522328
[Fact]
22532329
public void CreateSelectExpandNode_Caches_SelectExpandNode()
22542330
{
@@ -2487,6 +2563,12 @@ private class Order
24872563
public Customer Customer { get; set; }
24882564
}
24892565

2566+
private class Result
2567+
{
2568+
public string Title { get; set; }
2569+
public IList<Product> Products { get; set; }
2570+
}
2571+
24902572
private class SpecialOrder
24912573
{
24922574
public SpecialCustomer SpecialCustomer { get; set; }

0 commit comments

Comments
 (0)