Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
continue;
}

IODataRoutingMetadata metadata = candidate.Endpoint.Metadata.OfType<IODataRoutingMetadata>().FirstOrDefault();
if (metadata == null)
IODataRoutingMetadata[] metadataItems = candidate.Endpoint.Metadata.OfType<IODataRoutingMetadata>().ToArray();
if (metadataItems.Length == 0)
{
continue;
}
Expand All @@ -96,14 +96,28 @@ public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
continue;
}

ODataTemplateTranslateContext translatorContext =
new ODataTemplateTranslateContext(httpContext, candidate.Endpoint, candidate.Values, metadata.Model);
IODataRoutingMetadata matchedMetadata = null;
ODataTemplateTranslateContext translatorContext = null;
ODataPath odataPath = null;

foreach (IODataRoutingMetadata metadata in metadataItems)
{
ODataTemplateTranslateContext currentContext =
new ODataTemplateTranslateContext(httpContext, candidate.Endpoint, candidate.Values, metadata.Model);

odataPath = _translator.Translate(metadata.Template, currentContext);
if (odataPath != null)
{
matchedMetadata = metadata;
translatorContext = currentContext;
break;
}
}

ODataPath odataPath = _translator.Translate(metadata.Template, translatorContext);
if (odataPath != null)
{
odataFeature.RoutePrefix = metadata.Prefix;
odataFeature.Model = metadata.Model;
odataFeature.RoutePrefix = matchedMetadata.Prefix;
odataFeature.Model = matchedMetadata.Model;
odataFeature.Path = odataPath;

MergeRouteValues(translatorContext.UpdatedValues, candidate.Values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.OData.Extensions;
using Microsoft.AspNetCore.OData.Routing;
using Microsoft.AspNetCore.OData.Routing.Template;
using Microsoft.AspNetCore.Routing;
Expand Down Expand Up @@ -89,6 +90,94 @@ public async Task ApplyAsync_PrefersEndpointsWithODataRoutingMetadata()
Assert.False(candidateSet.IsValidCandidate(2));
}

[Fact]
public async Task ApplyAsync_UsesFirstRoutingMetadataThatTranslates()
{
// Arrange
IEdmModel firstModel = new EdmModel();
IEdmModel secondModel = new EdmModel();
IEdmModel thirdModel = new EdmModel();
ODataPathTemplate firstTemplate = new ODataPathTemplate();
ODataPathTemplate secondTemplate = new ODataPathTemplate();
ODataPathTemplate thirdTemplate = new ODataPathTemplate();
IODataRoutingMetadata firstMetadata = new ODataRoutingMetadata("first", firstModel, firstTemplate);
IODataRoutingMetadata secondMetadata = new ODataRoutingMetadata("second", secondModel, secondTemplate);
IODataRoutingMetadata thirdMetadata = new ODataRoutingMetadata("third", thirdModel, thirdTemplate);
ODataPath expectedPath = new ODataPath();

var translator = new Mock<IODataTemplateTranslator>();
translator
.Setup(a => a.Translate(firstTemplate, It.IsAny<ODataTemplateTranslateContext>()))
.Returns((ODataPath)null);
translator
.Setup(a => a.Translate(secondTemplate, It.IsAny<ODataTemplateTranslateContext>()))
.Returns((ODataPathTemplate _, ODataTemplateTranslateContext context) =>
{
context.UpdatedValues["key"] = "updated";
return expectedPath;
});

Endpoint[] endpoints = new[]
{
CreateEndpoint("/", firstMetadata, secondMetadata, thirdMetadata)
};
CandidateSet candidateSet = CreateCandidateSet(endpoints);
HttpContext httpContext = CreateHttpContext("GET");
ODataRoutingMatcherPolicy policy = CreatePolicy(translator.Object);

// Act
await policy.ApplyAsync(httpContext, candidateSet);

// Assert
Assert.True(candidateSet.IsValidCandidate(0));
Assert.Equal("second", httpContext.ODataFeature().RoutePrefix);
Assert.Same(secondModel, httpContext.ODataFeature().Model);
Assert.Same(expectedPath, httpContext.ODataFeature().Path);
Assert.Equal("updated", candidateSet[0].Values["key"]);
translator.Verify(
a => a.Translate(firstTemplate, It.Is<ODataTemplateTranslateContext>(c => c.Model == firstModel)),
Times.Once);
translator.Verify(
a => a.Translate(secondTemplate, It.Is<ODataTemplateTranslateContext>(c => c.Model == secondModel)),
Times.Once);
translator.Verify(
a => a.Translate(thirdTemplate, It.IsAny<ODataTemplateTranslateContext>()),
Times.Never);
}

[Fact]
public async Task ApplyAsync_InvalidatesCandidateWhenAllRoutingMetadataFailToTranslate()
{
// Arrange
IODataRoutingMetadata firstMetadata =
new ODataRoutingMetadata("first", new EdmModel(), new ODataPathTemplate());
IODataRoutingMetadata secondMetadata =
new ODataRoutingMetadata("second", new EdmModel(), new ODataPathTemplate());

var translator = new Mock<IODataTemplateTranslator>();
translator
.Setup(a => a.Translate(It.IsAny<ODataPathTemplate>(), It.IsAny<ODataTemplateTranslateContext>()))
.Returns((ODataPath)null);

Endpoint[] endpoints = new[]
{
CreateEndpoint("/", firstMetadata, secondMetadata)
};
CandidateSet candidateSet = CreateCandidateSet(endpoints);
HttpContext httpContext = CreateHttpContext("GET");
ODataRoutingMatcherPolicy policy = CreatePolicy(translator.Object);

// Act
await policy.ApplyAsync(httpContext, candidateSet);

// Assert
Assert.False(candidateSet.IsValidCandidate(0));
Assert.Null(httpContext.ODataFeature().Path);
translator.Verify(
a => a.Translate(It.IsAny<ODataPathTemplate>(), It.IsAny<ODataTemplateTranslateContext>()),
Times.Exactly(2));
}

private static RouteEndpoint CreateEndpoint(string template, IODataRoutingMetadata odataMetadata, params object[] more)
{
var metadata = new List<object>();
Expand Down Expand Up @@ -122,14 +211,18 @@ private static CandidateSet CreateCandidateSet(Endpoint[] endpoints)
return candidateSet;
}

private static ODataRoutingMatcherPolicy CreatePolicy()
private static ODataRoutingMatcherPolicy CreatePolicy(IODataTemplateTranslator translator = null)
{
var translator = new Mock<IODataTemplateTranslator>();
translator
.Setup(a => a.Translate(It.IsAny<ODataPathTemplate>(), It.IsAny<ODataTemplateTranslateContext>()))
.Returns(new ODataPath());
if (translator == null)
{
var translatorMock = new Mock<IODataTemplateTranslator>();
translatorMock
.Setup(a => a.Translate(It.IsAny<ODataPathTemplate>(), It.IsAny<ODataTemplateTranslateContext>()))
.Returns(new ODataPath());
translator = translatorMock.Object;
}

return new ODataRoutingMatcherPolicy(translator.Object);
return new ODataRoutingMatcherPolicy(translator);
}

private static HttpContext CreateHttpContext(string httpMethod)
Expand Down