Skip to content

Commit

Permalink
Add Instance annotations to WebAPI (#2219)
Browse files Browse the repository at this point in the history
* InstanceAnnotationChanges

InstanceAnnotationChanges

* Update ODataResourceDeserializerTests.cs

* Add review comments

* Review comment fix

* Code review changes

Code review changes

* updates

* Update ODataResourceSerializer.cs

* changes after rebase

* InstanceAnnotationChanges

InstanceAnnotationChanges

* Add review comments

* Review comment fix

* Code review changes

Code review changes

* Update Microsoft.AspNet.OData.PublicApi.bsl

* public api

* public api change

* Address comments

* Changes

* Update ODataResourceSerializer.cs

* changes

* Comment changes

* Update ODataResourceSerializer.cs

* publi api

* comment chantes

* extra test

* Update GlobalSuppressions.cs

* name change

* changes

* changes and test

* Update ODataResourceValueSerializer.cs

* changes

* Update ODataResourceValueSerializer.cs

* changes

* changes

* updates

* Update ODataInstanceAnnotationContainer.cs
  • Loading branch information
Sreejithpin authored Sep 18, 2020
1 parent e812738 commit 1f48bed
Show file tree
Hide file tree
Showing 43 changed files with 3,482 additions and 166 deletions.
13 changes: 13 additions & 0 deletions src/Microsoft.AspNet.OData.Shared/Builder/EdmModelHelperMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ private static Dictionary<Type, IEdmType> AddTypes(this EdmModel model, EdmTypeM
// add dynamic dictionary property annotation for open types
model.AddDynamicPropertyDictionaryAnnotations(edmTypeMap.OpenTypes);

// add instance annotation dictionary property annotations
model.AddInstanceAnnotationsContainer(edmTypeMap.InstanceAnnotatableTypes);

return edmTypes;
}

Expand Down Expand Up @@ -554,6 +557,16 @@ private static void AddDynamicPropertyDictionaryAnnotations(this EdmModel model,
}
}

private static void AddInstanceAnnotationsContainer(this EdmModel model,
Dictionary<IEdmStructuredType, PropertyInfo> instanceAnnotations)
{
foreach (KeyValuePair<IEdmStructuredType, PropertyInfo> instanceAnnotation in instanceAnnotations)
{
IEdmStructuredType edmStructuredType = instanceAnnotation.Key;
PropertyInfo propertyInfo = instanceAnnotation.Value;
model.SetAnnotationValue(edmStructuredType, new ODataInstanceAnnotationContainerAnnotation(propertyInfo));
}
}
private static void AddPropertiesQuerySettings(this EdmModel model,
Dictionary<IEdmProperty, ModelBoundQuerySettings> edmPropertiesQuerySettings)
{
Expand Down
19 changes: 18 additions & 1 deletion src/Microsoft.AspNet.OData.Shared/Builder/EdmTypeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal class EdmTypeBuilder
private readonly Dictionary<IEdmStructuredType, ModelBoundQuerySettings> _structuredTypeQuerySettings = new Dictionary<IEdmStructuredType, ModelBoundQuerySettings>();
private readonly Dictionary<Enum, IEdmEnumMember> _members = new Dictionary<Enum, IEdmEnumMember>();
private readonly Dictionary<IEdmStructuredType, PropertyInfo> _openTypes = new Dictionary<IEdmStructuredType, PropertyInfo>();
private readonly Dictionary<IEdmStructuredType, PropertyInfo> _instanceAnnotableTypes = new Dictionary<IEdmStructuredType, PropertyInfo>();

internal EdmTypeBuilder(IEnumerable<IEdmTypeConfiguration> configurations)
{
Expand All @@ -44,6 +45,7 @@ private Dictionary<Type, IEdmType> GetEdmTypes()
_members.Clear();
_openTypes.Clear();
_propertyConfigurations.Clear();
_instanceAnnotableTypes.Clear();

// Create headers to allow CreateEdmTypeBody to blindly references other things.
foreach (IEdmTypeConfiguration config in _configurations)
Expand Down Expand Up @@ -91,6 +93,13 @@ private void CreateEdmTypeHeader(IEdmTypeConfiguration config)
// add a mapping between the open complex type and its dynamic property dictionary.
_openTypes.Add(complexType, complex.DynamicPropertyDictionary);
}

if (complex.SupportsInstanceAnnotations)
{
// add a mapping between the complex type and its instance annotation dictionary.
_instanceAnnotableTypes.Add(complexType, complex.InstanceAnnotationsContainer);
}

edmType = complexType;
}
else if (config.Kind == EdmTypeKind.Entity)
Expand All @@ -116,6 +125,13 @@ private void CreateEdmTypeHeader(IEdmTypeConfiguration config)
// add a mapping between the open entity type and its dynamic property dictionary.
_openTypes.Add(entityType, entity.DynamicPropertyDictionary);
}

if (entity.SupportsInstanceAnnotations)
{
// add a mapping between the entity type and its instance annotation dictionary.
_instanceAnnotableTypes.Add(entityType, entity.InstanceAnnotationsContainer);
}

edmType = entityType;
}
else
Expand Down Expand Up @@ -551,7 +567,8 @@ public static EdmTypeMap GetTypesAndProperties(IEnumerable<IEdmTypeConfiguration
builder._structuredTypeQuerySettings,
builder._members,
builder._openTypes,
builder._propertyConfigurations);
builder._propertyConfigurations,
builder._instanceAnnotableTypes);
}

/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion src/Microsoft.AspNet.OData.Shared/Builder/EdmTypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public EdmTypeMap(
Dictionary<IEdmStructuredType, ModelBoundQuerySettings> edmStructuredTypeQuerySettings,
Dictionary<Enum, IEdmEnumMember> enumMembers,
Dictionary<IEdmStructuredType, PropertyInfo> openTypes,
Dictionary<IEdmProperty, PropertyConfiguration> propertyConfigurations)
Dictionary<IEdmProperty, PropertyConfiguration> propertyConfigurations,
Dictionary<IEdmStructuredType, PropertyInfo> instanceAnnotatableTypes )
{
EdmTypes = edmTypes;
EdmProperties = edmProperties;
Expand All @@ -29,6 +30,7 @@ public EdmTypeMap(
EnumMembers = enumMembers;
OpenTypes = openTypes;
EdmPropertyConfigurations = propertyConfigurations;
InstanceAnnotatableTypes = instanceAnnotatableTypes;
}

public Dictionary<Type, IEdmType> EdmTypes { get; private set; }
Expand All @@ -46,5 +48,7 @@ public EdmTypeMap(
public Dictionary<Enum, IEdmEnumMember> EnumMembers { get; private set; }

public Dictionary<IEdmStructuredType, PropertyInfo> OpenTypes { get; private set; }

public Dictionary<IEdmStructuredType, PropertyInfo> InstanceAnnotatableTypes { get; private set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.AspNet.OData.Builder
{
/// <summary>
/// Interface to used as a Container for holding Instance Annotations, An default implementation is provided
/// Custoer can implement the interface and can have their own implementation.
/// </summary>
public interface IODataInstanceAnnotationContainer
{
/// <summary>
/// Method to Add an Instance Annotation to the CLR type
/// </summary>
/// <param name="annotationName">Name of Annotation</param>
/// <param name="value">Value of Annotation</param>
void AddResourceAnnotation(string annotationName, object value);

/// <summary>
/// Method to Add an Instance Annotation to a property
/// </summary>
/// <param name="propertyName">Name of the property</param>
/// <param name="annotationName">Name of Annotation</param>
/// <param name="value">Value of Annotation</param>
void AddPropertyAnnotation(string propertyName, string annotationName, object value);

/// <summary>
/// Get an Instance Annotation from CLR Type
/// </summary>
/// <param name="annotationName">Name of Annotation</param>
/// <returns>Get Annotation value for the given annotation</returns>
object GetResourceAnnotation(string annotationName);

/// <summary>
/// Get an Instance Annotation from the Property
/// </summary>
/// <param name="propertyName">Name of the Property</param>
/// <param name="annotationName">Name of the Annotation</param>
/// <returns>Get Annotation value for the given annotation and property</returns>
object GetPropertyAnnotation(string propertyName, string annotationName);

/// <summary>
/// Get All Annotations from CLR Type
/// </summary>
/// <returns>Dictionary of string(annotation name) and object value(annotation value)</returns>
IDictionary<string,object> GetResourceAnnotations();

/// <summary>
/// Get all Annotations for a Property
/// </summary>
/// <param name="propertyName">Name of Property</param>
/// <returns>Dictionary of string(annotation name) and object value(annotation value)</returns>
IDictionary<string, object> GetPropertyAnnotations(string propertyName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System.Reflection;
using Microsoft.AspNet.OData.Common;
using Microsoft.OData.Edm;

namespace Microsoft.AspNet.OData.Builder
{
/// <summary>
/// This annotation indicates the mapping from a <see cref="IEdmStructuredType"/> to a <see cref="PropertyInfo"/>.
/// The <see cref="IEdmStructuredType"/> is a type of IODataInstanceAnnotationContainer and the <see cref="PropertyInfo"/> is the specific
/// property which is used to save/retrieve the instance annotations.
/// </summary>
internal class ODataInstanceAnnotationContainerAnnotation
{
/// <summary>
/// Initializes a new instance of <see cref="ODataInstanceAnnotationContainerAnnotation"/> class.
/// </summary>
/// <param name="propertyInfo">The backing <see cref="PropertyInfo"/>.</param>
public ODataInstanceAnnotationContainerAnnotation(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw Error.ArgumentNull("propertyInfo");
}

TypeHelper.ValidateAssignableFromForArgument(typeof(IODataInstanceAnnotationContainer), propertyInfo.PropertyType, "IODataInstanceAnnotationContainer");

PropertyInfo = propertyInfo;
}

/// <summary>
/// Gets the <see cref="PropertyInfo"/> which backs the instance annotations of the clr type/resource etc.
/// </summary>
public PropertyInfo PropertyInfo
{
get;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,10 @@ private void MapStructuralType(StructuralTypeConfiguration structuralType)
{
structuralType.AddDynamicPropertyDictionary(property);
}
else if (propertyKind == PropertyKind.InstanceAnnotations)
{
structuralType.AddInstanceAnnotationContainer(property);
}
else
{
// don't add this property if the user has already added it.
Expand Down Expand Up @@ -700,6 +704,16 @@ private PropertyKind GetPropertyType(PropertyInfo property, out bool isCollectio
return PropertyKind.Dynamic;
}

// IODataInstanceAnnotationContainer is used as a container to save/retrieve instance annotation properties for a CLR type.
// It is different from other collections (for example, IDictionary<string,IDictionary<string, int>>)
if (typeof(IODataInstanceAnnotationContainer).IsAssignableFrom(property.PropertyType))
{
mappedType = null;
isCollection = false;

return PropertyKind.InstanceAnnotations;
}

PropertyKind propertyKind;
if (TryGetPropertyTypeKind(property.PropertyType, out mappedType, out propertyKind))
{
Expand Down
Loading

0 comments on commit 1f48bed

Please sign in to comment.