Skip to content
Merged
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
3 changes: 2 additions & 1 deletion sample/ODataRoutingSample/Controllers/PeopleController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class PeopleController : ControllerBase
new Person
{
FirstName = "Goods",
LastName = "Zhangg",
LastName = "Zha/ngg",
},
new Person
{
Expand All @@ -42,6 +42,7 @@ public IActionResult Get(CancellationToken token)
return Ok(_persons);
}

// People(FirstName='Goods',LastName='Zha%2Fngg')
[HttpGet]
[EnableQuery]
public IActionResult Get(string keyFirstName, string keyLastName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
Expand Down Expand Up @@ -172,6 +173,7 @@ public override bool TryTranslate(ODataTemplateTranslateContext context)
IEdmTypeReference edmType = keyProperty.Type;
string strValue = rawValue as string;
string newStrValue = context.GetParameterAliasOrSelf(strValue);
newStrValue = Uri.UnescapeDataString(newStrValue);
if (newStrValue != strValue)
{
updateValues[templateName] = newStrValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static IList<OperationSegmentParameter> Match(ODataTemplateTranslateConte
{
string strValue = rawValue as string;
string newStrValue = context.GetParameterAliasOrSelf(strValue);
newStrValue = Uri.UnescapeDataString(newStrValue);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible with something like an open type for a property to be named with a character that needs to be escaped/unescaped? I'm really wondering if this new unescape logic should be applied to all segments, not just key and function segments

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not possible because the property name is an identifier, and an identifier should be a simple string.

if (newStrValue != strValue)
{
updatedValues[parameterTemp] = newStrValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,5 +370,39 @@ public void TryTranslateFunctionSegmentTemplate_ReturnsODataFunctionSegment_With
Assert.Equal(42, e.Value);
});
}

[Fact]
public void TryTranslateFunctionSegmentTemplate_ReturnsODataFunctionSegment_UsingEscapedString()
{
// Arrange
var primitive = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.String, false);
EdmFunction function = new EdmFunction("NS", "MyFunction", primitive, true, null, false);
function.AddParameter("bindingParameter", primitive);
function.AddParameter("name", primitive);

FunctionSegmentTemplate template = new FunctionSegmentTemplate(function, null);
EdmModel edmModel = new EdmModel();
edmModel.AddElement(function);

RouteValueDictionary routeValue = new RouteValueDictionary(new { name = "'Ji%2FChange%23%20T'" });

ODataTemplateTranslateContext context = new ODataTemplateTranslateContext
{
RouteValues = routeValue,
Model = edmModel
};

// Act
bool ok = template.TryTranslate(context);

// Assert
Assert.True(ok);
ODataPathSegment actual = Assert.Single(context.Segments);
OperationSegment functionSegment = Assert.IsType<OperationSegment>(actual);
Assert.Same(function, functionSegment.Operations.First());
var parameter = Assert.Single(functionSegment.Parameters);
Assert.Equal("name", parameter.Name);
Assert.Equal("Ji/Change# T", parameter.Value.ToString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,53 @@ public void TryTranslateKeySegmentTemplate_WorksWithKeyParametersAlias()
Assert.Equal(42, actualKeys.Value);
}

[Fact]
public void TryTranslateKeySegmentTemplate_WorksWithKeyValue_UsingEscapedString()
{
// Arrange
EdmModel model = new EdmModel();
EdmEntityType customerType = new EdmEntityType("NS", "Customer");
EdmStructuralProperty firstName = customerType.AddStructuralProperty("FirstName", EdmPrimitiveTypeKind.String);
EdmStructuralProperty lastName = customerType.AddStructuralProperty("LastName", EdmPrimitiveTypeKind.String);
customerType.AddKeys(firstName, lastName);
model.AddElement(customerType);
EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
EdmEntitySet customers = container.AddEntitySet("Customers", customerType);
model.AddElement(container);
RouteValueDictionary routeValueDictionary = new RouteValueDictionary(new { First = "'Zhang'", Last = "'Gan%2Fnng%23%20T'" });
IDictionary<string, string> keys = new Dictionary<string, string>
{
{ "FirstName", "{first}" },
{ "LastName", "{last}" }
};
KeySegmentTemplate template = new KeySegmentTemplate(keys, customerType, customers);

ODataTemplateTranslateContext context = new ODataTemplateTranslateContext
{
RouteValues = routeValueDictionary,
Model = model
};

// Act
bool ok = template.TryTranslate(context);

// Assert
Assert.True(ok);
ODataPathSegment actual = Assert.Single(context.Segments);
KeySegment keySegment = Assert.IsType<KeySegment>(actual);
Assert.Collection(keySegment.Keys,
e =>
{
Assert.Equal("FirstName", e.Key);
Assert.Equal("Zhang", e.Value);
},
e =>
{
Assert.Equal("LastName", e.Key);
Assert.Equal("Gan/nng# T", e.Value);
});
}

[Fact]
public void CreateKeySegmentKeySegmentTemplate_ThrowsArgumentNull_EntityType()
{
Expand Down