所以,情况就是这样:我有一个来自数据库的复杂对象。我有第二个对象(实际上是一个对象列表),我想向用户提供他们可以扩展的东西,但实际上只是我在应用程序中的运行时对象..
因此,我要做的是创建一个自定义ODataResourceSerializer,将模型附加到正在序列化的数据上。我猜我需要覆盖AppendDynamicProperties,CreateStructuralProperty,CreateResource或CreateSelectExpandNode,但我只是不知道哪一个以及如何。
因此在上图中,正常的EF / OData设置在扩展到“RelatedPosts”时返回左侧b / c数据库中没有任何内容,但我希望基本上在序列化时插入数据。 / p>
可能的?
对于某些历史记录,在重写AppendDynamicProperties时,我已经能够添加一个全新属性,您可以在上面的屏幕截图中看到“MyCustomProp”。但我还没弄明白如何添加整个对象。这是我的类扩展ODataResourceSerializer
的代码using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.OData.Formatter.Serialization;
using Microsoft.OData;
using System.Web.OData;
using Microsoft.OData.Edm;
namespace Boomerang.OData
{
public class CustomODataResourceSerializer : ODataResourceSerializer
{
public CustomODataResourceSerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider)
{
}
public override Microsoft.OData.ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, ResourceContext resourceContext)
{
Microsoft.OData.ODataProperty property = base.CreateStructuralProperty(structuralProperty, resourceContext);
return property;
}
public override void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
// add property
var list = resource.Properties.ToList();
list.Add(new ODataProperty() { Name = "MyCustomProp", Value = "This Thing" });
resource.Properties = list.AsEnumerable();
base.AppendDynamicProperties(resource, selectExpandNode, resourceContext);
}
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
return base.CreateResource(selectExpandNode, resourceContext);
}
public override SelectExpandNode CreateSelectExpandNode(ResourceContext resourceContext)
{
return base.CreateSelectExpandNode(resourceContext);
}
public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
{
base.WriteObject(graph, type, messageWriter, writeContext);
}
}
}
答案 0 :(得分:0)
感谢 user326608 为我们指出有关 ODataMediaTypeFormatter 的 SO 答案:https://stackoverflow.com/a/36976343
我的问题与 OP 有点不同,但是它显示了一个扩展点,您可以在其中有效地构建自己的输出,而不管 OData 在元数据中知道什么结构。
以下解决方案完全忽略了复杂类型序列化的 SelectExpandNode
,您可能可以构造 SelectExpandNode 以包含必要的元数据,但只需将值强制输入输出即可。
在您的 ODataResourceSerializer
中只需覆盖 CreateResource
:
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
var resource = base.CreateResource(selectExpandNode, resourceContext);
// Check for conditions where you want to Augment the output
// for me (CS) I don't want to allow partial complex types.
if (resourceContext.StructuredType.TypeKind == EdmTypeKind.Complex)
{
// I want ALL the properties from the complex type, if there are NONE, then generate them all!
// This shows how to add properties to the existing output,
// The data I want is already available to me in the data query (ResourceInstance) that we are serializing, but you could go get it now if you need to.
// the only caveate for manipulating existing resources is that you need to include any existing properties if you want them
if (!resource.Properties.Any())
{
var type = resourceContext.ResourceInstance.GetType();
PropertyInfo[] complex_properties = type.GetProperties();
List<ODataProperty> child_properties = new List<ODataProperty>();
foreach (PropertyInfo property in complex_properties)
{
ODataProperty child_property = CreateProperty(property.Name, property.GetValue(resourceContext.ResourceInstance));
child_properties.Add(child_property);
}
resource.Properties = child_properties;
}
}
return resource;
}
public static ODataResource CreateComplexValue(Type type, object value)
{
ODataResource complex_value = new ODataResource();
// Not sure this name will work, we probably need to lookup the name of this type from the OData metadata,
// but I'm not sure that we can have complex value properties on a complex value anyway.
complex_value.TypeName = type.ToString();
PropertyInfo[] complex_properties = type.GetProperties();
List<ODataProperty> child_properties = new List<ODataProperty>();
foreach (PropertyInfo property in complex_properties)
{
ODataProperty child_property = CreateProperty(property.Name, property.GetValue(value));
if(child_property != null)
child_properties.Add(child_property);
}
complex_value.Properties = child_properties;
return complex_value;
}
public static bool IsPrimitiveType(Type t)
{
if (!t.IsPrimitive && t != typeof(Decimal) && t != typeof(String) && t != typeof(Guid) && t != typeof(DateTime)) // todo
{
return false;
}
return true;
}
public static ODataProperty CreateProperty(string name, object value)
{
object property_value = value;
if (value != null)
{
Type t = value.GetType();
if (!IsPrimitiveType(t))
{
property_value = CreateComplexValue(t, value);
}
else if (t == typeof(DateTime) || t == typeof(DateTime?))
{
DateTime dt = (DateTime)value;
dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
DateTimeOffset dto = dt;
property_value = dto;
}
}
ODataProperty new_property = new ODataProperty()
{
Name = name,
Value = property_value
};
return new_property;
}