#c# #odata
#c# #odata
Вопрос:
Я использую открытые типы:
public class Student
{
public Guid Id { get; set; }
public string Name { get; set; }
public IBackpack Backpack
{
get
{
return new Backpack() { Id = Guid.NewGuid() };
}
set
{
}
}
Dictionary<string, object> interfaces;
public Dictionary<string, object> Interfaces
{
get
{
if (interfaces == null)
{
interfaces = new Dictionary<string, object>
{
{ "Backpack", this.Backpack as Backpack }
};
}
return interfaces;
}
set
{
}
}
}
Моя модель:
static IEdmModel GetEdmModel(ODataConventionModelBuilder builder)
{
builder.EntityType<IEntity>().Abstract().HasKey(s => s.Id);
var entity = builder.EntityType<Student>();
entity.Ignore(s => s.Backpack);
builder.EntityType<Backpack>();
builder.EntitySet<Student>("Student");
var model = builder.GetEdmModel();
return model;
}
Когда я делаю запрос, подобный https://localhost:44383/odata/Student ?$select=XYZ возвращает пустое значение:
{
"@odata.context": "https://localhost:44383/OData/$metadata#Student/ODataCoreTest.EntityBase(XYZ)",
"value": [
{}
]
}
Как вернуть ошибку, если свойство не существует в словаре открытых типов?
Ответ №1:
Итак, проблема была создана в Github: https://github.com/OData/WebApi/issues/2392 Однако они говорят, что это ожидаемо. Я нашел обходной путь для решения этой проблемы:
Я добавил пользовательский сериализатор ресурсов и проверил существующие свойства в методе createResource:
public class CustomODataResourceSerializer : ODataResourceSerializer
{
public CustomODataResourceSerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider)
{
}
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
var resource = base.CreateResource(selectExpandNode, resourceContext);
if (selectExpandNode.SelectedDynamicProperties?.Any() == true)
{
foreach (var dynamicProperty in selectExpandNode.SelectedDynamicProperties)
{
if (!resource.Properties.Any(s => s.Name == dynamicProperty) amp;amp; resourceContext.DynamicComplexProperties?.Any(s => s.Key == dynamicProperty) != true)
{
throw new InvalidOperationException($"Cannot find property '{dynamicProperty}' on '{resource.TypeName}' entity");
}
}
}
return resource;
}
public override void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
if (selectExpandNode.SelectedDynamicProperties?.Any() == true)
{
base.AppendDynamicProperties(resource, selectExpandNode, resourceContext);
}
}
}
Он работал нормально, но в запросах фильтра у меня были проблемы такого рода. Итак, я добавил метод проверки:
void ValidateOpenType(QueryNode expression)
{
if (expression is BinaryOperatorNode operatorNode)
{
ValidateOpenType(operatorNode.Left);
ValidateOpenType(operatorNode.Right);
}
else if (expression is ConvertNode convertNode)
{
ValidateOpenType(convertNode.Source);
}
else if (expression is SingleValueFunctionCallNode functionCallNode)
{
foreach (var queryNode in functionCallNode.Parameters)
{
ValidateOpenType(queryNode);
}
}
else if (expression is SingleValuePropertyAccessNode singleValueProperty amp;amp; !string.IsNullOrEmpty(singleValueProperty.Property?.Name))
{
if (singleValueProperty.Source is SingleNavigationNode navigationNode)
{
ThrowExceptionWhenPropertyDoesNotExists(singleValueProperty.Property.Name, navigationNode.NavigationSource.Name);
}
else
{
ThrowExceptionWhenPropertyDoesNotExists(singleValueProperty.Property.Name, typeof(TEntity).Name);
}
}
else if (expression is SingleValueOpenPropertyAccessNode valueOpenPropertyAccessNode)
{
if (valueOpenPropertyAccessNode.Source is SingleNavigationNode navigationNode)
{
ThrowExceptionWhenPropertyDoesNotExists(valueOpenPropertyAccessNode.Name, navigationNode.NavigationSource.Name);
}
else
{
ThrowExceptionWhenPropertyDoesNotExists(valueOpenPropertyAccessNode.Name, typeof(TEntity).Name);
}
}
}
void ThrowExceptionWhenPropertyDoesNotExists(string propertyName, string entityName)
{
if (ModelClasses.Any(t => t.Name == entityName amp;amp; t.GetProperty(propertyName) == null))
{
throw new InvalidOperationException($"Could not find a property named '{propertyName}' on '{entityName}' entity");
}
}
Получение классов:
List<Type> modelClasses;
public List<Type> ModelClasses
{
get
{
if (modelClasses == null)
{
modelClasses = GetClasses("ODataCoreTest");
}
return modelClasses;
}
}
static List<Type> GetClasses(string nameSpace)
{
Assembly asm = Assembly.GetExecutingAssembly();
List<Type> namespacelist = new List<Type>();
List<Type> classlist = new List<Type>();
foreach (Type type in asm.GetTypes())
{
if (type.Namespace == nameSpace)
namespacelist.Add(type);
}
foreach (Type classType in namespacelist)
classlist.Add(classType);
return classlist;
}
Использование:
[HttpGet]
public IActionResult Get(ODataQueryOptions<TEntity> queryOptions, CancellationToken cancellationToken)
{
if (queryOptions.Filter?.FilterClause != null)
{
ValidateOpenType(queryOptions.Filter.FilterClause.Expression);
}
var res = new List<Student>() { CreateNewStudent() };
return Ok(res);
}