Reputation: 815
I have a simple open type that contains dynamic properties:
public class Person {
[Key]
public string Uid { get; set; }
public IDictionary<string, object> DynamicProperties { get; set; }
}
In my controller, I fill these properties like this:
public IHttpActionResult Get([FromODataUri] string key) {
Person person;
// ...
person.DynamicProperties.Add("foo", "foo_value");
person.DynamicProperties.Add("bar", "bar_value");
// ...
return this.Ok(person);
}
I can figure how to request individually these properties - with an URL like ~/Person('uid')/foo - thanks to their keys and this method:
public IHttpActionResult GetDynamicProperty([FromODataUri] string key, [FromODataUri] string dynamicProperty) {
Person person;
// ...
// (string) for the example
return this.Ok((string)person.DynamicProperties[dynamicProperty]);
}
Result is like that:
{
"@odata.context": "http://myServer/$metadata#Person('uid')/foo",
"value": "foo_value"
}
But I can't figure how to get the raw value of these properties, with an URL like ~/Person('uid')/foo/$value
If I try it, the result is this one:
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'http://myServer/Person('uid')/foo/$value'.",
"innererror": {
"message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/dynamicproperty/$value'.",
"type": "",
"stacktrace": ""
}
}
}
How I should route to have access to these raw values? Or is there a method or something else that could handle it?
-- Edit after Sam Xu's answer
Thanks for your example, it works like a charm. I've followed your samples for points 1 and 2. For the point 3, if it can help someone, this is the adapted version for a classic Web API's Register method:
public static void Register(HttpConfiguration config) {
// Custom routing for dynamic attributes raw values
var routings = ODataRoutingConventions.CreateDefault();
routings.Insert(0, new DynamicRawValueRoutingConvention());
// Our model
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>("Person");
// ...
// Old way
//config.MapODataServiceRoute(
// routeName: "myDefaultRouteName",
// routePrefix: null,
// model: builder.GetEdmModel()
//);
// New way with Sam's samples
config.MapODataServiceRoute(
"myDefaultRouteName",
null,
configureAction =>
configureAction.AddService(ServiceLifetime.Singleton, sp => builder.GetEdmModel()).AddService<IEnumerable<IODataRoutingConvention>>(ServiceLifetime.Singleton, sp => routings)
);
var formatters = ODataMediaTypeFormatters.Create();
foreach (var oDataMediaTypeFormatter in formatters) {
oDataMediaTypeFormatter.MediaTypeMappings.Insert(0, new ODataDynamicValueMediaTypeMapping());
}
config.Formatters.InsertRange(0, formatters);
}
Upvotes: 0
Views: 668
Reputation: 3380
@Max Xapi
OData hasn't the built-in logic to support $value
for dynamic property.
However, you can have workaround by yourself to accomplish it.
It's simple and only several steps:
I created a sample that you can refer to, see the commit here. Please let me know any further problem and hope it can help.
Regards,
-Sam
Upvotes: 2