Enum support for Action and Function
Enum with type attribute with different metadata level mode Enable Enum in FilterQueryValidator Enum support for raw value
This commit is contained in:
Родитель
a08bb56452
Коммит
c850136c24
|
@ -142,12 +142,6 @@ namespace System.Web.Http.OData.Builder
|
|||
throw Error.InvalidOperation(SRResources.ReturnEntityWithoutEntitySet, configuration.FullName);
|
||||
}
|
||||
|
||||
if (configuration == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(returnType);
|
||||
configuration = ModelBuilder.GetTypeConfigurationOrNull(typeof(TReturnType));
|
||||
}
|
||||
ReturnType = configuration;
|
||||
ReturnsImplementation<TReturnType>();
|
||||
return this;
|
||||
}
|
||||
|
@ -172,12 +166,6 @@ namespace System.Web.Http.OData.Builder
|
|||
throw Error.InvalidOperation(SRResources.ReturnEntityCollectionWithoutEntitySet, edmElementType.FullName);
|
||||
}
|
||||
|
||||
if (edmElementType == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(clrElementType);
|
||||
edmElementType = ModelBuilder.GetTypeConfigurationOrNull(clrElementType);
|
||||
}
|
||||
ReturnType = new CollectionTypeConfiguration(edmElementType, clrCollectionType);
|
||||
ReturnsCollectionImplementation<TReturnElementType>();
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -133,16 +133,15 @@ namespace System.Web.Http.OData.Builder.Conventions
|
|||
{
|
||||
Contract.Assert(value != null);
|
||||
|
||||
// TODO: Delete enum processing when OData beta1 or later is referenced.
|
||||
Type underlyingType = Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType();
|
||||
Contract.Assert(EdmLibHelpers.GetEdmPrimitiveTypeOrNull(value.GetType()) != null || underlyingType.IsEnum);
|
||||
|
||||
if (underlyingType.IsEnum)
|
||||
// TODO 1608: Delete enum processing when OData beta1 or later is referenced.
|
||||
Type type = value.GetType();
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return String.Format(CultureInfo.InvariantCulture,
|
||||
"{0}'{1}'", underlyingType.Name, value);
|
||||
"{0}'{1}'", type.EdmFullName(), value);
|
||||
}
|
||||
|
||||
Contract.Assert(EdmLibHelpers.GetEdmPrimitiveTypeOrNull(type) != null);
|
||||
value = ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(value);
|
||||
return ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V4);
|
||||
}
|
||||
|
|
|
@ -192,7 +192,10 @@ namespace System.Web.Http.OData.Builder
|
|||
Dictionary<string, EdmEntitySet> edmEntitySetMap,
|
||||
bool isAction)
|
||||
{
|
||||
IEdmTypeReference returnReference = GetEdmTypeReference(edmTypeMap, procedure.ReturnType, nullable: true);
|
||||
IEdmTypeReference returnReference = GetEdmTypeReference(
|
||||
edmTypeMap,
|
||||
procedure.ReturnType,
|
||||
procedure.ReturnType != null && EdmLibHelpers.IsNullable(procedure.ReturnType.ClrType));
|
||||
IEdmExpression expression = GetEdmEntitySetExpression(edmEntitySetMap, procedure);
|
||||
IEdmPathExpression pathExpression = procedure.EntitySetPath != null
|
||||
? new EdmPathExpression(procedure.EntitySetPath)
|
||||
|
@ -357,37 +360,51 @@ namespace System.Web.Http.OData.Builder
|
|||
if (kind == EdmTypeKind.Collection)
|
||||
{
|
||||
CollectionTypeConfiguration collectionType = configuration as CollectionTypeConfiguration;
|
||||
EdmCollectionType edmCollectionType = new EdmCollectionType(GetEdmTypeReference(availableTypes, collectionType.ElementType, false));
|
||||
EdmCollectionType edmCollectionType = new EdmCollectionType(GetEdmTypeReference(
|
||||
availableTypes,
|
||||
collectionType.ElementType,
|
||||
EdmLibHelpers.IsNullable(collectionType.ElementType.ClrType)));
|
||||
return new EdmCollectionTypeReference(edmCollectionType, nullable);
|
||||
}
|
||||
else if (availableTypes.ContainsKey(configuration.ClrType))
|
||||
{
|
||||
IEdmType type = availableTypes[configuration.ClrType];
|
||||
if (kind == EdmTypeKind.Complex)
|
||||
{
|
||||
return new EdmComplexTypeReference((IEdmComplexType)type, nullable);
|
||||
}
|
||||
else if (kind == EdmTypeKind.Entity)
|
||||
{
|
||||
return new EdmEntityTypeReference((IEdmEntityType)type, nullable);
|
||||
}
|
||||
else if (kind == EdmTypeKind.Enum)
|
||||
{
|
||||
return new EdmEnumTypeReference((IEdmEnumType)type, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.UnsupportedEdmTypeKind, kind.ToString());
|
||||
}
|
||||
}
|
||||
else if (configuration.Kind == EdmTypeKind.Primitive)
|
||||
{
|
||||
PrimitiveTypeConfiguration primitiveTypeConfiguration = configuration as PrimitiveTypeConfiguration;
|
||||
return new EdmPrimitiveTypeReference(primitiveTypeConfiguration.EdmPrimitiveType, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.NoMatchingIEdmTypeFound, configuration.FullName);
|
||||
Type configurationClrType = TypeHelper.GetUnderlyingTypeOrSelf(configuration.ClrType);
|
||||
|
||||
if (!configurationClrType.IsEnum)
|
||||
{
|
||||
configurationClrType = configuration.ClrType;
|
||||
}
|
||||
|
||||
IEdmType type;
|
||||
|
||||
if (availableTypes.TryGetValue(configurationClrType, out type))
|
||||
{
|
||||
if (kind == EdmTypeKind.Complex)
|
||||
{
|
||||
return new EdmComplexTypeReference((IEdmComplexType)type, nullable);
|
||||
}
|
||||
else if (kind == EdmTypeKind.Entity)
|
||||
{
|
||||
return new EdmEntityTypeReference((IEdmEntityType)type, nullable);
|
||||
}
|
||||
else if (kind == EdmTypeKind.Enum)
|
||||
{
|
||||
return new EdmEnumTypeReference((IEdmEnumType)type, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.UnsupportedEdmTypeKind, kind.ToString());
|
||||
}
|
||||
}
|
||||
else if (configuration.Kind == EdmTypeKind.Primitive)
|
||||
{
|
||||
PrimitiveTypeConfiguration primitiveTypeConfiguration = configuration as PrimitiveTypeConfiguration;
|
||||
return new EdmPrimitiveTypeReference(primitiveTypeConfiguration.EdmPrimitiveType, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.NoMatchingIEdmTypeFound, configuration.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace System.Web.Http.OData.Builder
|
|||
|
||||
private void CreateEdmTypeHeader(IEdmTypeConfiguration config)
|
||||
{
|
||||
if (!_types.ContainsKey(config.ClrType))
|
||||
if (GetEdmType(config.ClrType) == null)
|
||||
{
|
||||
if (config.Kind == EdmTypeKind.Complex)
|
||||
{
|
||||
|
@ -68,7 +68,7 @@ namespace System.Web.Http.OData.Builder
|
|||
if (entity.BaseType != null)
|
||||
{
|
||||
CreateEdmTypeHeader(entity.BaseType);
|
||||
baseType = _types[entity.BaseType.ClrType] as IEdmEntityType;
|
||||
baseType = GetEdmType(entity.BaseType.ClrType) as IEdmEntityType;
|
||||
|
||||
Contract.Assert(baseType != null);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ namespace System.Web.Http.OData.Builder
|
|||
|
||||
private void CreateEdmTypeBody(IEdmTypeConfiguration config)
|
||||
{
|
||||
IEdmType edmType = _types[config.ClrType];
|
||||
IEdmType edmType = GetEdmType(config.ClrType);
|
||||
|
||||
if (edmType.TypeKind == EdmTypeKind.Complex)
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ namespace System.Web.Http.OData.Builder
|
|||
|
||||
case PropertyKind.Complex:
|
||||
ComplexPropertyConfiguration complexProperty = property as ComplexPropertyConfiguration;
|
||||
IEdmComplexType complexType = _types[complexProperty.RelatedClrType] as IEdmComplexType;
|
||||
IEdmComplexType complexType = GetEdmType(complexProperty.RelatedClrType) as IEdmComplexType;
|
||||
|
||||
edmProperty = type.AddStructuralProperty(
|
||||
complexProperty.Name,
|
||||
|
@ -173,27 +173,38 @@ namespace System.Web.Http.OData.Builder
|
|||
private IEdmProperty CreateStructuralTypeCollectionPropertyBody(EdmStructuredType type, CollectionPropertyConfiguration collectionProperty)
|
||||
{
|
||||
IEdmTypeReference elementTypeReference = null;
|
||||
Type clrType = Nullable.GetUnderlyingType(collectionProperty.ElementType) ?? collectionProperty.ElementType;
|
||||
IEdmType edmType;
|
||||
Type clrType = TypeHelper.GetUnderlyingTypeOrSelf(collectionProperty.ElementType);
|
||||
|
||||
if (clrType.IsEnum)
|
||||
{
|
||||
if (!_types.TryGetValue(clrType, out edmType))
|
||||
IEdmType edmType = GetEdmType(clrType);
|
||||
|
||||
if (edmType == null)
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.EnumTypeNotExisting, clrType.Name);
|
||||
throw Error.InvalidOperation(SRResources.EnumTypeDoesNotExist, clrType.Name);
|
||||
}
|
||||
|
||||
IEdmEnumType enumElementType = (IEdmEnumType)edmType;
|
||||
elementTypeReference = new EdmEnumTypeReference(enumElementType, collectionProperty.ElementType.IsNullable());
|
||||
}
|
||||
else if (_types.TryGetValue(collectionProperty.ElementType, out edmType))
|
||||
{
|
||||
IEdmComplexType elementType = (IEdmComplexType)edmType;
|
||||
elementTypeReference = new EdmComplexTypeReference(elementType, false);
|
||||
bool isNullable = collectionProperty.ElementType != clrType;
|
||||
elementTypeReference = new EdmEnumTypeReference(enumElementType, isNullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
elementTypeReference = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(collectionProperty.ElementType);
|
||||
IEdmType edmType = GetEdmType(collectionProperty.ElementType);
|
||||
if (edmType != null)
|
||||
{
|
||||
IEdmComplexType elementType = edmType as IEdmComplexType;
|
||||
Contract.Assert(elementType != null);
|
||||
elementTypeReference = new EdmComplexTypeReference(elementType, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
elementTypeReference =
|
||||
EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(collectionProperty.ElementType);
|
||||
Contract.Assert(elementTypeReference != null);
|
||||
}
|
||||
}
|
||||
|
||||
return type.AddStructuralProperty(
|
||||
collectionProperty.Name,
|
||||
new EdmCollectionTypeReference(
|
||||
|
@ -203,12 +214,14 @@ namespace System.Web.Http.OData.Builder
|
|||
|
||||
private IEdmProperty CreateStructuralTypeEnumPropertyBody(EdmStructuredType type, StructuralTypeConfiguration config, EnumPropertyConfiguration enumProperty)
|
||||
{
|
||||
Type enumPropertyType = Nullable.GetUnderlyingType(enumProperty.RelatedClrType) ?? enumProperty.RelatedClrType;
|
||||
IEdmType edmType;
|
||||
if (!_types.TryGetValue(enumPropertyType, out edmType))
|
||||
Type enumPropertyType = TypeHelper.GetUnderlyingTypeOrSelf(enumProperty.RelatedClrType);
|
||||
IEdmType edmType = GetEdmType(enumPropertyType);
|
||||
|
||||
if (edmType == null)
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.EnumTypeNotExisting, enumPropertyType.Name);
|
||||
throw Error.InvalidOperation(SRResources.EnumTypeDoesNotExist, enumPropertyType.Name);
|
||||
}
|
||||
|
||||
IEdmEnumType enumType = (IEdmEnumType)edmType;
|
||||
IEdmTypeReference enumTypeReference = new EdmEnumTypeReference(enumType, enumProperty.OptionalProperty);
|
||||
|
||||
|
@ -225,6 +238,7 @@ namespace System.Web.Http.OData.Builder
|
|||
defaultValue: null,
|
||||
concurrencyMode: enumConcurrencyMode);
|
||||
}
|
||||
|
||||
private void CreateComplexTypeBody(EdmComplexType type, ComplexTypeConfiguration config)
|
||||
{
|
||||
Contract.Assert(type != null);
|
||||
|
@ -247,7 +261,7 @@ namespace System.Web.Http.OData.Builder
|
|||
EdmNavigationPropertyInfo info = new EdmNavigationPropertyInfo();
|
||||
info.Name = navProp.Name;
|
||||
info.TargetMultiplicity = navProp.Multiplicity;
|
||||
info.Target = _types[navProp.RelatedClrType] as IEdmEntityType;
|
||||
info.Target = GetEdmType(navProp.RelatedClrType) as IEdmEntityType;
|
||||
//TODO: If target end has a multiplity of 1 this assumes the source end is 0..1.
|
||||
// I think a better default multiplicity is *
|
||||
IEdmProperty edmProperty = type.AddUnidirectionalNavigation(info);
|
||||
|
@ -288,6 +302,16 @@ namespace System.Web.Http.OData.Builder
|
|||
}
|
||||
}
|
||||
|
||||
private IEdmType GetEdmType(Type clrType)
|
||||
{
|
||||
Contract.Assert(clrType != null);
|
||||
|
||||
IEdmType edmType;
|
||||
_types.TryGetValue(clrType, out edmType);
|
||||
|
||||
return edmType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds <see cref="IEdmType"/> and <see cref="IEdmProperty"/>'s from <paramref name="configurations"/>
|
||||
/// </summary>
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace System.Web.Http.OData.Builder
|
|||
private const string DefaultNamespace = "Default";
|
||||
private string _namespace;
|
||||
private string _name;
|
||||
private NullableEnumTypeConfiguration nullableEnumTypeConfiguration = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumTypeConfiguration"/> class.
|
||||
|
@ -236,5 +237,15 @@ namespace System.Web.Http.OData.Builder
|
|||
RemovedMembers.Add(member);
|
||||
}
|
||||
}
|
||||
|
||||
internal NullableEnumTypeConfiguration GetNullableEnumTypeConfiguration()
|
||||
{
|
||||
if (nullableEnumTypeConfiguration == null)
|
||||
{
|
||||
nullableEnumTypeConfiguration = new NullableEnumTypeConfiguration(this);
|
||||
}
|
||||
|
||||
return nullableEnumTypeConfiguration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.OData.Edm;
|
||||
|
||||
namespace System.Web.Http.OData.Builder
|
||||
{
|
||||
internal class NullableEnumTypeConfiguration : IEdmTypeConfiguration
|
||||
{
|
||||
internal NullableEnumTypeConfiguration(EnumTypeConfiguration enumTypeConfiguration)
|
||||
{
|
||||
this.ClrType = typeof(Nullable<>).MakeGenericType(enumTypeConfiguration.ClrType);
|
||||
this.FullName = enumTypeConfiguration.FullName;
|
||||
this.Namespace = enumTypeConfiguration.Namespace;
|
||||
this.Name = enumTypeConfiguration.Name;
|
||||
this.Kind = enumTypeConfiguration.Kind;
|
||||
this.ModelBuilder = enumTypeConfiguration.ModelBuilder;
|
||||
this.EnumTypeConfiguration = enumTypeConfiguration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The CLR type associated with the nullable enum type.
|
||||
/// </summary>
|
||||
public Type ClrType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The fullname (including namespace) of the EdmType.
|
||||
/// </summary>
|
||||
public string FullName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The namespace of the EdmType.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Namespace", Justification = "Namespace matches the EF naming scheme")]
|
||||
public string Namespace { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the EdmType.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The kind of the EdmType.
|
||||
/// Examples include EntityType, ComplexType, PrimitiveType, CollectionType, EnumType.
|
||||
/// </summary>
|
||||
public EdmTypeKind Kind { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ODataModelBuilder used to create this IEdmType.
|
||||
/// </summary>
|
||||
public ODataModelBuilder ModelBuilder { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The EnumTypeConfiguration used to create this class.
|
||||
/// </summary>
|
||||
internal EnumTypeConfiguration EnumTypeConfiguration { get; private set; }
|
||||
}
|
||||
}
|
|
@ -535,13 +535,17 @@ namespace System.Web.Http.OData.Builder
|
|||
throw Error.ArgumentNull("type");
|
||||
}
|
||||
|
||||
Type enumType = Nullable.GetUnderlyingType(type) ?? type;
|
||||
if (enumType.IsEnum && EnumTypes.All(e => e.ClrType != enumType))
|
||||
if (TypeHelper.IsEnum(type))
|
||||
{
|
||||
EnumTypeConfiguration enumTypeConfiguration = AddEnumType(enumType);
|
||||
foreach (object member in Enum.GetValues(enumType))
|
||||
Type enumType = TypeHelper.GetUnderlyingTypeOrSelf(type);
|
||||
|
||||
if (!EnumTypes.Any(e => e.ClrType == enumType))
|
||||
{
|
||||
enumTypeConfiguration.AddMember((Enum)member);
|
||||
EnumTypeConfiguration enumTypeConfiguration = AddEnumType(enumType);
|
||||
foreach (object member in Enum.GetValues(enumType))
|
||||
{
|
||||
enumTypeConfiguration.AddMember((Enum)member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -552,77 +556,23 @@ namespace System.Web.Http.OData.Builder
|
|||
{
|
||||
Contract.Assert(property != null);
|
||||
|
||||
if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(property.PropertyType) != null)
|
||||
PropertyKind propertyKind;
|
||||
if (TryGetPropertyTypeKind(property.PropertyType, out mappedType, out propertyKind))
|
||||
{
|
||||
isCollection = false;
|
||||
mappedType = null;
|
||||
return PropertyKind.Primitive;
|
||||
}
|
||||
|
||||
mappedType = GetStructuralTypeOrNull(property.PropertyType);
|
||||
if (mappedType != null)
|
||||
{
|
||||
isCollection = false;
|
||||
|
||||
if (mappedType is ComplexTypeConfiguration)
|
||||
{
|
||||
return PropertyKind.Complex;
|
||||
}
|
||||
else if (mappedType is EnumTypeConfiguration)
|
||||
{
|
||||
return PropertyKind.Enum;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PropertyKind.Navigation;
|
||||
}
|
||||
}
|
||||
|
||||
Type underlyingType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
|
||||
if (underlyingType.IsEnum)
|
||||
{
|
||||
isCollection = false;
|
||||
mappedType = null;
|
||||
return PropertyKind.Enum;
|
||||
return propertyKind;
|
||||
}
|
||||
|
||||
Type elementType;
|
||||
if (property.PropertyType.IsCollection(out elementType))
|
||||
{
|
||||
isCollection = true;
|
||||
|
||||
// Collection properties - can be a collection of primitives, enum, complex or entities.
|
||||
if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(elementType) != null)
|
||||
if (TryGetPropertyTypeKind(elementType, out mappedType, out propertyKind))
|
||||
{
|
||||
return PropertyKind.Primitive;
|
||||
return propertyKind;
|
||||
}
|
||||
|
||||
mappedType = GetStructuralTypeOrNull(elementType);
|
||||
if (mappedType != null)
|
||||
{
|
||||
if (mappedType is ComplexTypeConfiguration)
|
||||
{
|
||||
return PropertyKind.Complex;
|
||||
}
|
||||
else if (mappedType is EntityTypeConfiguration)
|
||||
{
|
||||
return PropertyKind.Navigation;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PropertyKind.Enum;
|
||||
}
|
||||
}
|
||||
|
||||
underlyingType = Nullable.GetUnderlyingType(elementType) ?? elementType;
|
||||
if (underlyingType.IsEnum)
|
||||
{
|
||||
isCollection = true;
|
||||
mappedType = null;
|
||||
return PropertyKind.Enum;
|
||||
}
|
||||
|
||||
// if we know nothing about this type we assume it to be an entity
|
||||
// if we know nothing about this type we assume it to be collection of entities
|
||||
// and patch up later
|
||||
return PropertyKind.Navigation;
|
||||
}
|
||||
|
@ -633,6 +583,46 @@ namespace System.Web.Http.OData.Builder
|
|||
return PropertyKind.Navigation;
|
||||
}
|
||||
|
||||
private bool TryGetPropertyTypeKind(Type propertyType, out IEdmTypeConfiguration mappedType, out PropertyKind propertyKind)
|
||||
{
|
||||
Contract.Assert(propertyType != null);
|
||||
|
||||
if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(propertyType) != null)
|
||||
{
|
||||
mappedType = null;
|
||||
propertyKind = PropertyKind.Primitive;
|
||||
return true;
|
||||
}
|
||||
|
||||
mappedType = GetStructuralTypeOrNull(propertyType);
|
||||
if (mappedType != null)
|
||||
{
|
||||
if (mappedType is ComplexTypeConfiguration)
|
||||
{
|
||||
propertyKind = PropertyKind.Complex;
|
||||
}
|
||||
else if (mappedType is EnumTypeConfiguration)
|
||||
{
|
||||
propertyKind = PropertyKind.Enum;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyKind = PropertyKind.Navigation;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeHelper.IsEnum(propertyType))
|
||||
{
|
||||
propertyKind = PropertyKind.Enum;
|
||||
return true;
|
||||
}
|
||||
|
||||
propertyKind = PropertyKind.Navigation;
|
||||
return false;
|
||||
}
|
||||
|
||||
// the convention model builder MapTypes() method might have went through deep object graphs and added a bunch of types
|
||||
// only to realise after applying the conventions that the user has ignored some of the properties. So, prune the unreachable stuff.
|
||||
private void PruneUnreachableTypes()
|
||||
|
@ -749,9 +739,10 @@ namespace System.Web.Http.OData.Builder
|
|||
IEdmTypeConfiguration configuration = StructuralTypes.SingleOrDefault(edmType => edmType.ClrType == clrType);
|
||||
if (configuration == null)
|
||||
{
|
||||
Type type = Nullable.GetUnderlyingType(clrType) ?? clrType;
|
||||
Type type = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
|
||||
configuration = EnumTypes.SingleOrDefault(edmType => edmType.ClrType == type);
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Web.Http.OData.Formatter;
|
||||
|
||||
namespace System.Web.Http.OData.Builder
|
||||
{
|
||||
|
@ -217,12 +218,7 @@ namespace System.Web.Http.OData.Builder
|
|||
internal void ReturnsImplementation<TReturnType>()
|
||||
{
|
||||
Type returnType = typeof(TReturnType);
|
||||
IEdmTypeConfiguration configuration = ModelBuilder.GetTypeConfigurationOrNull(returnType);
|
||||
if (configuration == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(returnType);
|
||||
configuration = ModelBuilder.GetTypeConfigurationOrNull(typeof(TReturnType));
|
||||
}
|
||||
IEdmTypeConfiguration configuration = GetProcedureTypeConfiguration(returnType);
|
||||
ReturnType = configuration;
|
||||
}
|
||||
|
||||
|
@ -239,12 +235,7 @@ namespace System.Web.Http.OData.Builder
|
|||
// You can imagine the override of this that takes a delegate using the correct CLR type for the return type.
|
||||
Type clrCollectionType = typeof(IEnumerable<TReturnElementType>);
|
||||
Type clrElementType = typeof(TReturnElementType);
|
||||
IEdmTypeConfiguration edmElementType = ModelBuilder.GetTypeConfigurationOrNull(clrElementType);
|
||||
if (edmElementType == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(clrElementType);
|
||||
edmElementType = ModelBuilder.GetTypeConfigurationOrNull(clrElementType);
|
||||
}
|
||||
IEdmTypeConfiguration edmElementType = GetProcedureTypeConfiguration(clrElementType);
|
||||
ReturnType = new CollectionTypeConfiguration(edmElementType, clrCollectionType);
|
||||
}
|
||||
|
||||
|
@ -273,12 +264,7 @@ namespace System.Web.Http.OData.Builder
|
|||
public ParameterConfiguration Parameter<TParameter>(string name)
|
||||
{
|
||||
Type type = typeof(TParameter);
|
||||
IEdmTypeConfiguration parameterType = ModelBuilder.GetTypeConfigurationOrNull(type);
|
||||
if (parameterType == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(type);
|
||||
parameterType = ModelBuilder.GetTypeConfigurationOrNull(type);
|
||||
}
|
||||
IEdmTypeConfiguration parameterType = GetProcedureTypeConfiguration(type);
|
||||
return AddParameter(name, parameterType);
|
||||
}
|
||||
|
||||
|
@ -289,12 +275,7 @@ namespace System.Web.Http.OData.Builder
|
|||
public ParameterConfiguration CollectionParameter<TElementType>(string name)
|
||||
{
|
||||
Type elementType = typeof(TElementType);
|
||||
IEdmTypeConfiguration elementTypeConfiguration = ModelBuilder.GetTypeConfigurationOrNull(elementType);
|
||||
if (elementTypeConfiguration == null)
|
||||
{
|
||||
ModelBuilder.AddComplexType(elementType);
|
||||
elementTypeConfiguration = ModelBuilder.GetTypeConfigurationOrNull(elementType);
|
||||
}
|
||||
IEdmTypeConfiguration elementTypeConfiguration = GetProcedureTypeConfiguration(elementType);
|
||||
CollectionTypeConfiguration parameterType = new CollectionTypeConfiguration(elementTypeConfiguration, typeof(IEnumerable<>).MakeGenericType(elementType));
|
||||
return AddParameter(name, parameterType);
|
||||
}
|
||||
|
@ -303,5 +284,48 @@ namespace System.Web.Http.OData.Builder
|
|||
/// Gets or sets the <see cref="ODataModelBuilder"/> used to create this configuration.
|
||||
/// </summary>
|
||||
protected ODataModelBuilder ModelBuilder { get; set; }
|
||||
|
||||
private IEdmTypeConfiguration GetProcedureTypeConfiguration(Type clrType)
|
||||
{
|
||||
Type type = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
|
||||
IEdmTypeConfiguration edmTypeConfiguration;
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
edmTypeConfiguration = ModelBuilder.GetTypeConfigurationOrNull(type);
|
||||
|
||||
if (edmTypeConfiguration != null && EdmLibHelpers.IsNullable(clrType))
|
||||
{
|
||||
edmTypeConfiguration = ((EnumTypeConfiguration)edmTypeConfiguration).GetNullableEnumTypeConfiguration();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edmTypeConfiguration = ModelBuilder.GetTypeConfigurationOrNull(clrType);
|
||||
}
|
||||
|
||||
if (edmTypeConfiguration == null)
|
||||
{
|
||||
if (type.IsEnum)
|
||||
{
|
||||
EnumTypeConfiguration enumTypeConfiguration = ModelBuilder.AddEnumType(type);
|
||||
|
||||
if (EdmLibHelpers.IsNullable(clrType))
|
||||
{
|
||||
edmTypeConfiguration = enumTypeConfiguration.GetNullableEnumTypeConfiguration();
|
||||
}
|
||||
else
|
||||
{
|
||||
edmTypeConfiguration = enumTypeConfiguration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edmTypeConfiguration = ModelBuilder.AddComplexType(clrType);
|
||||
}
|
||||
}
|
||||
|
||||
return edmTypeConfiguration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,9 +218,7 @@ namespace System.Web.Http.OData.Builder
|
|||
throw Error.Argument("propertyInfo", SRResources.PropertyDoesNotBelongToType, propertyInfo.Name, ClrType.FullName);
|
||||
}
|
||||
|
||||
Type enumType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
|
||||
|
||||
if (!enumType.IsEnum)
|
||||
if (!TypeHelper.IsEnum(propertyInfo.PropertyType))
|
||||
{
|
||||
throw Error.Argument("propertyInfo", SRResources.MustBeEnumProperty, propertyInfo.Name, ClrType.FullName);
|
||||
}
|
||||
|
@ -350,8 +348,7 @@ namespace System.Web.Http.OData.Builder
|
|||
EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(propertyConfiguration.ElementType);
|
||||
if (edmType == null)
|
||||
{
|
||||
Type type = Nullable.GetUnderlyingType(propertyConfiguration.ElementType) ?? propertyConfiguration.ElementType;
|
||||
if (!type.IsEnum)
|
||||
if (!TypeHelper.IsEnum(propertyConfiguration.ElementType))
|
||||
{
|
||||
ModelBuilder.AddComplexType(propertyConfiguration.ElementType);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace System.Web.Http.OData.Formatter.Deserialization
|
|||
throw Error.ArgumentNull("type");
|
||||
}
|
||||
|
||||
Type enumType = Nullable.GetUnderlyingType(type) ?? type;
|
||||
Type enumType = TypeHelper.GetUnderlyingTypeOrSelf(type);
|
||||
|
||||
// if value is of the requested type nothing to do here.
|
||||
if (value.GetType() == enumType)
|
||||
|
|
|
@ -26,6 +26,14 @@ namespace System.Web.Http.OData.Formatter.Deserialization
|
|||
{
|
||||
throw Error.ArgumentNull("messageReader");
|
||||
}
|
||||
if (type == null)
|
||||
{
|
||||
throw Error.ArgumentNull("type");
|
||||
}
|
||||
if (readContext == null)
|
||||
{
|
||||
throw Error.ArgumentNull("readContext");
|
||||
}
|
||||
|
||||
IEdmTypeReference edmType = readContext.GetEdmType(type);
|
||||
Contract.Assert(edmType != null);
|
||||
|
|
|
@ -134,7 +134,8 @@ namespace System.Web.Http.OData.Formatter
|
|||
}
|
||||
}
|
||||
|
||||
Type underlyingType = Nullable.GetUnderlyingType(clrType) ?? clrType;
|
||||
Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
|
||||
|
||||
if (underlyingType.IsEnum)
|
||||
{
|
||||
clrType = underlyingType;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Web.Http.OData.Routing;
|
||||
using Microsoft.OData.Edm;
|
||||
|
||||
namespace System.Web.Http.OData.Formatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Media type mapping that associates requests for the raw value of enum properties with
|
||||
/// the text/plain content type.
|
||||
/// </summary>
|
||||
public class ODataEnumValueMediaTypeMapping : ODataRawValueMediaTypeMapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ODataEnumValueMediaTypeMapping"/> class.
|
||||
/// </summary>
|
||||
public ODataEnumValueMediaTypeMapping()
|
||||
: base("text/plain")
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool IsMatch(PropertyAccessPathSegment propertySegment)
|
||||
{
|
||||
return propertySegment != null && propertySegment.Property.Type.IsEnum();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ namespace System.Web.Http.OData.Formatter
|
|||
{
|
||||
ODataMediaTypeFormatter formatter = CreateFormatterWithoutMediaTypes(serializerProvider, deserializerProvider, ODataPayloadKind.Value);
|
||||
formatter.MediaTypeMappings.Add(new ODataPrimitiveValueMediaTypeMapping());
|
||||
formatter.MediaTypeMappings.Add(new ODataEnumValueMediaTypeMapping());
|
||||
formatter.MediaTypeMappings.Add(new ODataBinaryValueMediaTypeMapping());
|
||||
return formatter;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using System.Web.Http.OData.Properties;
|
||||
|
@ -35,11 +38,19 @@ namespace System.Web.Http.OData.Formatter
|
|||
return new ODataModelBinder();
|
||||
}
|
||||
|
||||
if (TypeHelper.IsEnum(modelType))
|
||||
{
|
||||
return new ODataModelBinder();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal class ODataModelBinder : IModelBinder
|
||||
{
|
||||
private static MethodInfo enumTryParseMethod = typeof(Enum).GetMethods()
|
||||
.Single(m => m.Name == "TryParse" && m.GetParameters().Length == 2);
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't want to fail in model binding.")]
|
||||
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
|
||||
{
|
||||
|
@ -96,6 +107,25 @@ namespace System.Web.Http.OData.Formatter
|
|||
return null;
|
||||
}
|
||||
|
||||
// TODO 1608: ODataUriUtils.ConvertFromUriLiteral doesn't support enum
|
||||
if (TypeHelper.IsEnum(type))
|
||||
{
|
||||
string[] values = valueString.Split(new[] { '\'' }, StringSplitOptions.None);
|
||||
Contract.Assert(values.Length == 3 && values[2] == String.Empty);
|
||||
|
||||
string enumValueString = values[1];
|
||||
Type enumType = TypeHelper.GetUnderlyingTypeOrSelf(type);
|
||||
object[] parameters = new[] { enumValueString, Enum.ToObject(type, 0) };
|
||||
bool isSuccessful = (bool)enumTryParseMethod.MakeGenericMethod(enumType).Invoke(null, parameters);
|
||||
|
||||
if (!isSuccessful)
|
||||
{
|
||||
throw Error.InvalidOperation(SRResources.ModelBinderUtil_ValueCannotBeEnum, valueString, type.Name);
|
||||
}
|
||||
|
||||
return parameters[1];
|
||||
}
|
||||
|
||||
object value = ODataUriUtils.ConvertFromUriLiteral(valueString, ODataVersion.V4);
|
||||
|
||||
bool isNonStandardEdmPrimitive;
|
||||
|
|
|
@ -132,7 +132,7 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
|
||||
if (edmType != null)
|
||||
{
|
||||
if (edmType.IsPrimitive() && ODataRawValueMediaTypeMapping.IsRawValueRequest(request))
|
||||
if ((edmType.IsPrimitive() || edmType.IsEnum()) && ODataRawValueMediaTypeMapping.IsRawValueRequest(request))
|
||||
{
|
||||
return _rawValueSerializer;
|
||||
}
|
||||
|
|
|
@ -81,12 +81,76 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
}
|
||||
|
||||
ODataEnumValue enumValue = new ODataEnumValue(value, enumType.FullName());
|
||||
enumValue.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation
|
||||
{
|
||||
TypeName = null
|
||||
});
|
||||
|
||||
ODataMetadataLevel metadataLevel = writeContext != null
|
||||
? writeContext.MetadataLevel
|
||||
: ODataMetadataLevel.Default;
|
||||
AddTypeNameAnnotationAsNeeded(enumValue, enumType, metadataLevel);
|
||||
|
||||
return enumValue;
|
||||
}
|
||||
|
||||
internal static void AddTypeNameAnnotationAsNeeded(ODataEnumValue enumValue, IEdmEnumTypeReference enumType, ODataMetadataLevel metadataLevel)
|
||||
{
|
||||
// ODataLib normally has the caller decide whether or not to serialize properties by leaving properties
|
||||
// null when values should not be serialized. The TypeName property is different and should always be
|
||||
// provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not
|
||||
// to serialize the type name (a null value prevents serialization).
|
||||
|
||||
// Note that this annotation should not be used for Atom or JSON verbose formats, as it will interfere with
|
||||
// the correct default behavior for those formats.
|
||||
|
||||
Contract.Assert(enumValue != null);
|
||||
|
||||
// Only add an annotation if we want to override ODataLib's default type name serialization behavior.
|
||||
if (ShouldAddTypeNameAnnotation(metadataLevel))
|
||||
{
|
||||
string typeName;
|
||||
|
||||
// Provide the type name to serialize (or null to force it not to serialize).
|
||||
if (ShouldSuppressTypeNameSerialization(metadataLevel))
|
||||
{
|
||||
typeName = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
typeName = enumType.FullName();
|
||||
}
|
||||
|
||||
enumValue.SetAnnotation(new SerializationTypeNameAnnotation
|
||||
{
|
||||
TypeName = typeName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldAddTypeNameAnnotation(ODataMetadataLevel metadataLevel)
|
||||
{
|
||||
switch (metadataLevel)
|
||||
{
|
||||
case ODataMetadataLevel.Default:
|
||||
case ODataMetadataLevel.MinimalMetadata:
|
||||
return false;
|
||||
case ODataMetadataLevel.FullMetadata:
|
||||
case ODataMetadataLevel.NoMetadata:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldSuppressTypeNameSerialization(ODataMetadataLevel metadataLevel)
|
||||
{
|
||||
Contract.Assert(metadataLevel != ODataMetadataLevel.Default);
|
||||
Contract.Assert(metadataLevel != ODataMetadataLevel.MinimalMetadata);
|
||||
|
||||
switch (metadataLevel)
|
||||
{
|
||||
case ODataMetadataLevel.NoMetadata:
|
||||
return true;
|
||||
case ODataMetadataLevel.FullMetadata:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
public class ODataRawValueSerializer : ODataSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ODataPrimitiveSerializer"/>.
|
||||
/// Initializes a new instance of <see cref="ODataRawValueSerializer"/>.
|
||||
/// </summary>
|
||||
public ODataRawValueSerializer()
|
||||
: base(ODataPayloadKind.Value)
|
||||
|
@ -30,7 +30,14 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
throw Error.ArgumentNull("graph");
|
||||
}
|
||||
|
||||
messageWriter.WriteValue(ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(graph));
|
||||
if (graph.GetType().IsEnum)
|
||||
{
|
||||
messageWriter.WriteValue(graph.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWriter.WriteValue(ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(graph));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,9 +58,14 @@ namespace System.Web.Http.OData.Query
|
|||
/// </summary>
|
||||
Not = 0x100,
|
||||
|
||||
/// <summary>
|
||||
/// A value that corresponds to allowing 'Has' logical operator in $filter.
|
||||
/// </summary>
|
||||
Has = 0x200,
|
||||
|
||||
/// <summary>
|
||||
/// A value that corresponds to allowing all logical operators in $filter.
|
||||
/// </summary>
|
||||
All = Or | And | Equal | NotEqual | GreaterThan | GreaterThanOrEqual | LessThan | LessThanOrEqual | Not
|
||||
All = Or | And | Equal | NotEqual | GreaterThan | GreaterThanOrEqual | LessThan | LessThanOrEqual | Not | Has
|
||||
}
|
||||
}
|
||||
|
|
|
@ -400,8 +400,7 @@ namespace System.Web.Http.OData.Query.Expressions
|
|||
}
|
||||
else
|
||||
{
|
||||
Type sourceUnderlyingType = Nullable.GetUnderlyingType(source.Type) ?? source.Type;
|
||||
if (sourceUnderlyingType.IsEnum)
|
||||
if (TypeHelper.IsEnum(source.Type))
|
||||
{
|
||||
// we handle enum conversions ourselves
|
||||
return source;
|
||||
|
@ -1045,8 +1044,7 @@ namespace System.Web.Http.OData.Query.Expressions
|
|||
|
||||
if (isNonstandardEdmPrimitive)
|
||||
{
|
||||
Type sourceType = source.Type;
|
||||
sourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
|
||||
Type sourceType = TypeHelper.GetUnderlyingTypeOrSelf(source.Type);
|
||||
|
||||
Contract.Assert(sourceType != conversionType);
|
||||
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
case BinaryOperatorKind.LessThan:
|
||||
case BinaryOperatorKind.LessThanOrEqual:
|
||||
case BinaryOperatorKind.Or:
|
||||
case BinaryOperatorKind.Has:
|
||||
// binary logical operators
|
||||
ValidateLogicalOperator(binaryOperatorNode, settings);
|
||||
break;
|
||||
|
@ -288,6 +289,31 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
ValidateQueryNode(convertNode.Source, settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this method for the enum node.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method is intended to be called from method overrides in subclasses.
|
||||
/// This method also supports unit-testing scenarios and is not intended to be called from user code.
|
||||
/// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance.
|
||||
/// </remarks>
|
||||
/// <param name="enumNode"></param>
|
||||
/// <param name="settings"></param>
|
||||
public virtual void ValidateEnumNode(EnumNode enumNode, ODataValidationSettings settings)
|
||||
{
|
||||
if (enumNode == null)
|
||||
{
|
||||
throw Error.ArgumentNull("enumNode");
|
||||
}
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
throw Error.ArgumentNull("settings");
|
||||
}
|
||||
|
||||
// no default validation logic here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this method for the navigation property node.
|
||||
/// </summary>
|
||||
|
@ -575,6 +601,14 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
/// <param name="settings"></param>
|
||||
private void ValidateSingleValueNode(SingleValueNode node, ODataValidationSettings settings)
|
||||
{
|
||||
// TODO 1577: remove this and add it to switch, once the ODataLib v4 EnumNode.Kind bug is fixed.
|
||||
EnumNode enumNode = node as EnumNode;
|
||||
if (enumNode != null)
|
||||
{
|
||||
ValidateEnumNode(enumNode, settings);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.Kind)
|
||||
{
|
||||
case QueryNodeKind.BinaryOperator:
|
||||
|
@ -779,6 +813,10 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
result = AllowedLogicalOperators.Or;
|
||||
break;
|
||||
|
||||
case BinaryOperatorKind.Has:
|
||||
result = AllowedLogicalOperators.Has;
|
||||
break;
|
||||
|
||||
default:
|
||||
// should never be here
|
||||
Contract.Assert(false, "ToLogicalOperator should never be here.");
|
||||
|
|
|
@ -170,6 +170,9 @@ namespace System.Web.Http.OData.Routing
|
|||
case EdmTypeKind.Primitive:
|
||||
return ParseAtPrimitiveProperty(model, previous, previousEdmType, segment, segments);
|
||||
|
||||
case EdmTypeKind.Enum:
|
||||
return ParseAtEnumProperty(model, previous, previousEdmType, segment, segments);
|
||||
|
||||
default:
|
||||
throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous));
|
||||
}
|
||||
|
@ -395,6 +398,39 @@ namespace System.Web.Http.OData.Routing
|
|||
throw new ODataException(Error.Format(SRResources.NoActionFoundForCollection, segment, collectionType.ElementType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the next OData path segment following an enum property.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to use for path parsing.</param>
|
||||
/// <param name="previous">The previous path segment.</param>
|
||||
/// <param name="previousEdmType">The EDM type of the OData path up to the previous segment.</param>
|
||||
/// <param name="segment">The value of the segment to parse.</param>
|
||||
/// <param name="segments">The queue of pending segments.</param>
|
||||
/// <returns>A parsed representation of the segment.</returns>
|
||||
protected virtual ODataPathSegment ParseAtEnumProperty(IEdmModel model, ODataPathSegment previous,
|
||||
IEdmType previousEdmType, string segment, Queue<string> segments)
|
||||
{
|
||||
if (previous == null)
|
||||
{
|
||||
throw Error.ArgumentNull("previous");
|
||||
}
|
||||
if (segments == null)
|
||||
{
|
||||
throw Error.ArgumentNull("segments");
|
||||
}
|
||||
if (String.IsNullOrEmpty(segment))
|
||||
{
|
||||
throw Error.Argument(SRResources.SegmentNullOrEmpty);
|
||||
}
|
||||
|
||||
if (segment == ODataSegmentKinds.Value)
|
||||
{
|
||||
return new ValuePathSegment();
|
||||
}
|
||||
|
||||
throw new ODataException(Error.Format(SRResources.InvalidPathSegment, segment, previous));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the next OData path segment following a primitive property.
|
||||
/// </summary>
|
||||
|
|
|
@ -475,7 +475,7 @@ namespace System.Web.Http.OData.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This service doesn't support OData requests in the form '{0}'..
|
||||
/// Looks up a localized string similar to This service does not support OData requests in the form '{0}'..
|
||||
/// </summary>
|
||||
internal static string EntitySetControllerUnmappedRequest {
|
||||
get {
|
||||
|
@ -655,11 +655,11 @@ namespace System.Web.Http.OData.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The enum type '{0}' doesn't exist..
|
||||
/// Looks up a localized string similar to The enum type '{0}' does not exist..
|
||||
/// </summary>
|
||||
internal static string EnumTypeNotExisting {
|
||||
internal static string EnumTypeDoesNotExist {
|
||||
get {
|
||||
return ResourceManager.GetString("EnumTypeNotExisting", resourceCulture);
|
||||
return ResourceManager.GetString("EnumTypeDoesNotExist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -925,7 +925,7 @@ namespace System.Web.Http.OData.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The provided mapping doesn't contain an entry for the entity type '{0}'..
|
||||
/// Looks up a localized string similar to The provided mapping does not contain an entry for the entity type '{0}'..
|
||||
/// </summary>
|
||||
internal static string MappingDoesNotContainEntityType {
|
||||
get {
|
||||
|
@ -987,6 +987,15 @@ namespace System.Web.Http.OData.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The binding value '{0}' cannot be bound to the enum type '{1}'..
|
||||
/// </summary>
|
||||
internal static string ModelBinderUtil_ValueCannotBeEnum {
|
||||
get {
|
||||
return ResourceManager.GetString("ModelBinderUtil_ValueCannotBeEnum", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The EDM model is missing on the read context. The model is required on the read context to deserialize the payload..
|
||||
/// </summary>
|
||||
|
|
|
@ -228,8 +228,8 @@
|
|||
<data name="EnumValueCannotBeLong" xml:space="preserve">
|
||||
<value>The value of enum member '{0}' cannot be converted to a long type.</value>
|
||||
</data>
|
||||
<data name="EnumTypeNotExisting" xml:space="preserve">
|
||||
<value>The enum type '{0}' doesn't exist.</value>
|
||||
<data name="EnumTypeDoesNotExist" xml:space="preserve">
|
||||
<value>The enum type '{0}' does not exist.</value>
|
||||
</data>
|
||||
<data name="RecursiveComplexTypesNotAllowed" xml:space="preserve">
|
||||
<value>The complex type '{0}' has a reference to itself through the property '{1}'. A recursive loop of complex types is not allowed.</value>
|
||||
|
@ -238,7 +238,7 @@
|
|||
<value>'{0}' does not support Read.</value>
|
||||
</data>
|
||||
<data name="MappingDoesNotContainEntityType" xml:space="preserve">
|
||||
<value>The provided mapping doesn't contain an entry for the entity type '{0}'.</value>
|
||||
<value>The provided mapping does not contain an entry for the entity type '{0}'.</value>
|
||||
</data>
|
||||
<data name="NoIdLinkFactoryFound" xml:space="preserve">
|
||||
<value>No IdLink factory was found. Try calling HasIdLink on the EntitySetConfiguration for '{0}'.</value>
|
||||
|
@ -372,6 +372,9 @@
|
|||
<data name="ValueIsInvalid" xml:space="preserve">
|
||||
<value>The value '{0}' is invalid. {1}</value>
|
||||
</data>
|
||||
<data name="ModelBinderUtil_ValueCannotBeEnum" xml:space="preserve">
|
||||
<value>The binding value '{0}' cannot be bound to the enum type '{1}'.</value>
|
||||
</data>
|
||||
<data name="ModelBinderUtil_ModelMetadataCannotBeNull" xml:space="preserve">
|
||||
<value>The binding context cannot have a null ModelMetadata.</value>
|
||||
</data>
|
||||
|
@ -461,7 +464,7 @@
|
|||
<comment>Language tag of the error messages according to RFC4646.</comment>
|
||||
</data>
|
||||
<data name="EntitySetControllerUnmappedRequest" xml:space="preserve">
|
||||
<value>This service doesn't support OData requests in the form '{0}'.</value>
|
||||
<value>This service does not support OData requests in the form '{0}'.</value>
|
||||
</data>
|
||||
<data name="EntitySetControllerUnmappedRequestErrorCode" xml:space="preserve">
|
||||
<value>Not implemented.</value>
|
||||
|
@ -609,7 +612,7 @@
|
|||
</data>
|
||||
<data name="EdmTypeCannotBeNull" xml:space="preserve">
|
||||
<value>The EDM type of the object of type '{0}' is null. The EDM type of an {1} cannot be null.</value>
|
||||
<comment>{1} may be System.Web.Http.OData.IEdmObject which doesn't scan. https://aspnetwebstack.codeplex.com/workitem/1558</comment>
|
||||
<comment>{1} may be System.Web.Http.OData.IEdmObject which does not scan. https://aspnetwebstack.codeplex.com/workitem/1558</comment>
|
||||
</data>
|
||||
<data name="EdmObjectNull" xml:space="preserve">
|
||||
<value>The property 'EdmObject' of {0} cannot be null.</value>
|
||||
|
|
|
@ -67,8 +67,10 @@
|
|||
<Compile Include="OData\Builder\EnumPropertyConfiguration.cs" />
|
||||
<Compile Include="OData\Builder\EnumTypeConfiguration.cs" />
|
||||
<Compile Include="OData\Builder\EnumTypeConfigurationOfTEnumType.cs" />
|
||||
<Compile Include="OData\Builder\NullableEnumTypeConfiguration.cs" />
|
||||
<Compile Include="OData\Formatter\Deserialization\EnumDeserializationHelpers.cs" />
|
||||
<Compile Include="OData\Formatter\Deserialization\ODataEnumDeserializer.cs" />
|
||||
<Compile Include="OData\Formatter\ODataEnumValueMediaTypeMapping.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataEnumSerializer.cs" />
|
||||
<Compile Include="OData\Query\NonFilterableAttribute.cs" />
|
||||
<Compile Include="OData\Builder\Conventions\Attributes\NonFilterableAttributeEdmPropertyConvention.cs" />
|
||||
|
|
|
@ -72,6 +72,17 @@ namespace System.Web.Http
|
|||
return false;
|
||||
}
|
||||
|
||||
public static Type GetUnderlyingTypeOrSelf(Type type)
|
||||
{
|
||||
return Nullable.GetUnderlyingType(type) ?? type;
|
||||
}
|
||||
|
||||
public static bool IsEnum(Type type)
|
||||
{
|
||||
Type underlyingTypeOrSelf = GetUnderlyingTypeOrSelf(type);
|
||||
return underlyingTypeOrSelf.IsEnum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the given type is a primitive type or
|
||||
/// is a <see cref="string"/>, <see cref="DateTime"/>, <see cref="Decimal"/>,
|
||||
|
|
|
@ -61,9 +61,10 @@ namespace System.Web.Http.OData.Builder.Conventions
|
|||
{ new DateTimeOffset(1,1,1,0,0,0,TimeSpan.Zero), "0001-01-01T00:00:00Z" },
|
||||
{ TimeSpan.FromSeconds(86456), "duration'P1DT56S'" },
|
||||
{ DateTimeOffset.FromFileTime(0).ToUniversalTime(), "1601-01-01T00:00:00Z" },
|
||||
{ SimpleEnum.First, "SimpleEnum'First'" },
|
||||
{ FlagsEnum.One | FlagsEnum.Two, "FlagsEnum'One, Two'" },
|
||||
{ (SimpleEnum)123, "SimpleEnum'123'" },
|
||||
{ SimpleEnum.First, "Microsoft.TestCommon.Types.SimpleEnum'First'" },
|
||||
{ FlagsEnum.One | FlagsEnum.Two, "Microsoft.TestCommon.Types.FlagsEnum'One, Two'" },
|
||||
{ (SimpleEnum)123, "Microsoft.TestCommon.Types.SimpleEnum'123'" },
|
||||
{ (FlagsEnum)123, "Microsoft.TestCommon.Types.FlagsEnum'123'" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace System.Web.Http.OData.Builder
|
|||
color.Member(Color.Blue);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var colorType = model.SchemaElements.OfType<IEdmEnumType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -55,7 +55,7 @@ namespace System.Web.Http.OData.Builder
|
|||
simple.Member(SimpleEnum.Third);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var colorType = model.SchemaElements.OfType<IEdmEnumType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -71,7 +71,7 @@ namespace System.Web.Http.OData.Builder
|
|||
complexTypeConfiguration.EnumProperty(c => c.NullableColor);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var complexType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -91,7 +91,7 @@ namespace System.Web.Http.OData.Builder
|
|||
complexTypeConfiguration.CollectionProperty(c => c.Colors);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var complexType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -111,7 +111,7 @@ namespace System.Web.Http.OData.Builder
|
|||
complexTypeConfiguration.EnumProperty(c => c.RequiredColor);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var complexType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -133,7 +133,7 @@ namespace System.Web.Http.OData.Builder
|
|||
entityTypeConfiguration.EnumProperty(e => e.LongEnum);
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var entityType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
|
||||
// Assert
|
||||
|
@ -175,7 +175,7 @@ namespace System.Web.Http.OData.Builder
|
|||
entityTypeConfiguration.EnumProperty(c => c.RequiredColor).IsOptional().IsConcurrencyToken();
|
||||
|
||||
// Act
|
||||
var model = builder.GetServiceModel();
|
||||
var model = builder.GetEdmModel();
|
||||
var complexType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
IEdmStructuralProperty requiredColor = complexType.Properties().SingleOrDefault(p => p.Name == "RequiredColor") as IEdmStructuralProperty;
|
||||
|
||||
|
@ -515,7 +515,7 @@ namespace System.Web.Http.OData.Builder
|
|||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => builder.GetServiceModel(),
|
||||
"The enum type 'Color' doesn't exist.");
|
||||
"The enum type 'Color' does not exist.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -529,88 +529,106 @@ namespace System.Web.Http.OData.Builder
|
|||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => builder.GetServiceModel(),
|
||||
"The enum type 'Color' doesn't exist.");
|
||||
"The enum type 'Color' does not exist.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateEnumTypePropertyInComplexType()
|
||||
public void ODataConventionModelBuilder_CreateRequiredEnumTypePropertyInComplexType()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ODataConventionModelBuilder();
|
||||
builder.ComplexType<ComplexTypeWithEnumTypePropertyTestModel>();
|
||||
IEdmStructuredType complexType = AddComplexTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
var model = builder.GetEdmModel();
|
||||
var complexType = model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
Assert.Equal(3, complexType.Properties().Count());
|
||||
|
||||
var requiredColor = complexType.Properties().SingleOrDefault(p => p.Name == "RequiredColor");
|
||||
var nullableColor = complexType.Properties().SingleOrDefault(p => p.Name == "NullableColor");
|
||||
var colors = complexType.Properties().SingleOrDefault(p => p.Name == "Colors");
|
||||
|
||||
Assert.NotNull(requiredColor);
|
||||
Assert.NotNull(nullableColor);
|
||||
Assert.NotNull(colors);
|
||||
Assert.True(requiredColor.Type.IsEnum());
|
||||
Assert.False(requiredColor.Type.IsNullable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateNullableEnumTypePropertyInComplexType()
|
||||
{
|
||||
// Arrange
|
||||
IEdmStructuredType complexType = AddComplexTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(3, complexType.Properties().Count());
|
||||
var nullableColor = complexType.Properties().SingleOrDefault(p => p.Name == "NullableColor");
|
||||
Assert.NotNull(nullableColor);
|
||||
Assert.True(nullableColor.Type.IsEnum());
|
||||
Assert.True(nullableColor.Type.IsNullable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateEnumTypeCollectionPropertyInComplexType()
|
||||
{
|
||||
// Arrange
|
||||
IEdmStructuredType complexType = AddComplexTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(3, complexType.Properties().Count());
|
||||
var colors = complexType.Properties().SingleOrDefault(p => p.Name == "Colors");
|
||||
Assert.NotNull(colors);
|
||||
Assert.True(colors.Type.IsCollection());
|
||||
Assert.True(((IEdmCollectionTypeReference)colors.Type).ElementType().IsEnum());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateEnumTypePropertyInEntityType()
|
||||
public void ODataConventionModelBuilder_CreateRequiredEnumTypePropertyInEntityType()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ODataConventionModelBuilder();
|
||||
builder.EntitySet<EntityTypeWithEnumTypePropertyTestModel>("Entities");
|
||||
IEdmEntityType entityType = AddEntityTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
var model = builder.GetEdmModel();
|
||||
IEdmEntitySet entitySet = model.EntityContainers().Single().FindEntitySet("Entities");
|
||||
Assert.NotNull(entitySet);
|
||||
IEdmEntityType entityType = entitySet.ElementType;
|
||||
Assert.Equal(6, entityType.Properties().Count());
|
||||
|
||||
Assert.Equal(5, entityType.Properties().Count());
|
||||
var requiredColor = entityType.Properties().SingleOrDefault(p => p.Name == "RequiredColor");
|
||||
var longEnum = entityType.Properties().SingleOrDefault(p => p.Name == "LongEnum");
|
||||
var nullableColor = entityType.Properties().SingleOrDefault(p => p.Name == "NullableColor");
|
||||
var colors = entityType.Properties().SingleOrDefault(p => p.Name == "Colors");
|
||||
var complexTypeProperty = entityType.Properties().SingleOrDefault(p => p.Name == "ComplexType");
|
||||
|
||||
Assert.NotNull(requiredColor);
|
||||
Assert.NotNull(longEnum);
|
||||
Assert.NotNull(nullableColor);
|
||||
Assert.NotNull(colors);
|
||||
Assert.NotNull(complexTypeProperty);
|
||||
Assert.True(requiredColor.Type.IsEnum());
|
||||
Assert.False(requiredColor.Type.IsNullable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateNullableEnumTypePropertyInEntityType()
|
||||
{
|
||||
// Arrange
|
||||
IEdmEntityType entityType = AddEntityTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(5, entityType.Properties().Count());
|
||||
var nullableColor = entityType.Properties().SingleOrDefault(p => p.Name == "NullableColor");
|
||||
Assert.NotNull(nullableColor);
|
||||
Assert.True(nullableColor.Type.IsEnum());
|
||||
Assert.True(nullableColor.Type.IsNullable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateEnumTypeCollectionPropertyInEntityType()
|
||||
{
|
||||
// Arrange
|
||||
IEdmEntityType entityType = AddEntityTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(5, entityType.Properties().Count());
|
||||
var colors = entityType.Properties().SingleOrDefault(p => p.Name == "Colors");
|
||||
Assert.NotNull(colors);
|
||||
Assert.True(colors.Type.IsCollection());
|
||||
Assert.True(((IEdmCollectionTypeReference)colors.Type).ElementType().IsEnum());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataConventionModelBuilder_CreateLongEnumTypePropertyInEntityType()
|
||||
{
|
||||
// Arrange
|
||||
IEdmEntityType entityType = AddEntityTypeWithODataConventionModelBuilder();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(5, entityType.Properties().Count());
|
||||
var longEnum = entityType.Properties().SingleOrDefault(p => p.Name == "LongEnum");
|
||||
Assert.NotNull(longEnum);
|
||||
Assert.True(longEnum.Type.IsEnum());
|
||||
Assert.False(longEnum.Type.IsNullable);
|
||||
Assert.True(EdmCoreModel.Instance.GetInt64(false).Definition == longEnum.Type.AsEnum().EnumDefinition().UnderlyingType);
|
||||
Assert.True(nullableColor.Type.IsEnum());
|
||||
Assert.True(nullableColor.Type.IsNullable);
|
||||
Assert.True(colors.Type.IsCollection());
|
||||
Assert.True(((IEdmCollectionTypeReference)colors.Type).ElementType().IsEnum());
|
||||
Assert.True(complexTypeProperty.Type.IsComplex());
|
||||
|
||||
IEdmComplexType complexType = complexTypeProperty.Type.AsComplex().ComplexDefinition();
|
||||
Assert.Equal(3, complexType.Properties().Count());
|
||||
|
||||
requiredColor = complexType.Properties().SingleOrDefault(p => p.Name == "RequiredColor");
|
||||
nullableColor = complexType.Properties().SingleOrDefault(p => p.Name == "NullableColor");
|
||||
colors = complexType.Properties().SingleOrDefault(p => p.Name == "Colors");
|
||||
|
||||
Assert.NotNull(requiredColor);
|
||||
Assert.NotNull(nullableColor);
|
||||
Assert.NotNull(colors);
|
||||
Assert.True(requiredColor.Type.IsEnum());
|
||||
Assert.False(requiredColor.Type.IsNullable);
|
||||
Assert.True(nullableColor.Type.IsEnum());
|
||||
Assert.True(nullableColor.Type.IsNullable);
|
||||
Assert.True(colors.Type.IsCollection());
|
||||
Assert.True(((IEdmCollectionTypeReference)colors.Type).ElementType().IsEnum());
|
||||
Assert.Same(EdmCoreModel.Instance.GetInt64(false).Definition, longEnum.Type.AsEnum().EnumDefinition().UnderlyingType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -632,6 +650,255 @@ namespace System.Web.Http.OData.Builder
|
|||
// Act & Assert
|
||||
Assert.Null(EdmLibHelpers.GetEdmPrimitiveTypeOrNull(clrType));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnboundAction_ForEnumTypeInODataModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataModelBuilder builder = new ODataModelBuilder().Add_Color_EnumType();
|
||||
ActionConfiguration actionConfiguration = builder.Action("UnboundAction");
|
||||
actionConfiguration.Parameter<Color>("Color");
|
||||
actionConfiguration.Returns<Color>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmActionImport actionImport = model.EntityContainers().Single().OperationImports().Single(o => o.Name == "UnboundAction") as IEdmActionImport;
|
||||
|
||||
IEdmTypeReference color = actionImport.Action.Parameters.Single(p => p.Name == "Color").Type;
|
||||
IEdmTypeReference returnType = actionImport.Action.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.False(color.IsNullable);
|
||||
Assert.Same(colorType, color.Definition);
|
||||
Assert.False(returnType.IsNullable);
|
||||
Assert.Same(colorType, returnType.Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnboundFunction_ForEnumTypeInODataModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataModelBuilder builder = new ODataModelBuilder();
|
||||
FunctionConfiguration functionConfiguration = builder.Function("UnboundFunction");
|
||||
functionConfiguration.CollectionParameter<Color>("Colors");
|
||||
functionConfiguration.ReturnsCollection<Color>();
|
||||
builder.Add_Color_EnumType();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmFunctionImport functionImport = model.EntityContainers().Single().OperationImports().Single(o => o.Name == "UnboundFunction") as IEdmFunctionImport;
|
||||
|
||||
IEdmTypeReference colors = functionImport.Function.Parameters.Single(p => p.Name == "Colors").Type;
|
||||
IEdmTypeReference returnType = functionImport.Function.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.True(colors.IsCollection());
|
||||
Assert.Same(colorType, colors.AsCollection().ElementType().Definition);
|
||||
Assert.True(returnType.IsCollection());
|
||||
Assert.False(returnType.AsCollection().ElementType().IsNullable);
|
||||
Assert.Same(colorType, returnType.AsCollection().ElementType().Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundAction_ForEnumTypeInODataModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataModelBuilder builder = new ODataModelBuilder();
|
||||
EntityTypeConfiguration<EnumModel> entityTypeConfiguration = builder.Entity<EnumModel>();
|
||||
ActionConfiguration actionConfiguration = entityTypeConfiguration.Action("BoundAction");
|
||||
actionConfiguration.CollectionParameter<Color>("Colors");
|
||||
actionConfiguration.ReturnsCollection<Color?>();
|
||||
builder.Add_Color_EnumType();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmAction action = model.FindDeclaredOperations("Default.BoundAction").Single() as IEdmAction;
|
||||
|
||||
IEdmTypeReference colors = action.Parameters.Single(p => p.Name == "Colors").Type;
|
||||
IEdmTypeReference returnType = action.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.True(colors.IsCollection());
|
||||
Assert.Same(colorType, colors.AsCollection().ElementType().Definition);
|
||||
Assert.True(returnType.IsCollection());
|
||||
Assert.True(returnType.AsCollection().ElementType().IsNullable);
|
||||
Assert.Same(colorType, returnType.AsCollection().ElementType().Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundFunction_ForEnumTypeInODataModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataModelBuilder builder = new ODataModelBuilder().Add_Color_EnumType();
|
||||
EntityTypeConfiguration<EnumModel> entityTypeConfiguration = builder.Entity<EnumModel>();
|
||||
FunctionConfiguration functionConfiguration = entityTypeConfiguration.Function("BoundFunction");
|
||||
functionConfiguration.Parameter<Color?>("Color");
|
||||
functionConfiguration.Returns<Color>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmFunction function = model.FindDeclaredOperations("Default.BoundFunction").Single() as IEdmFunction;
|
||||
|
||||
IEdmTypeReference color = function.Parameters.Single(p => p.Name == "Color").Type;
|
||||
IEdmTypeReference returnType = function.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.True(color.IsNullable);
|
||||
Assert.Same(colorType, color.Definition);
|
||||
Assert.Same(colorType, returnType.Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnboundAction_ForEnumTypeInODataConventionModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
ActionConfiguration actionConfiguration = builder.Action("UnboundAction");
|
||||
actionConfiguration.CollectionParameter<Color>("Colors");
|
||||
actionConfiguration.Returns<Color?>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmActionImport actionImport = model.EntityContainers().Single().OperationImports().Single(o => o.Name == "UnboundAction") as IEdmActionImport;
|
||||
|
||||
IEdmTypeReference colors = actionImport.Action.Parameters.Single(p => p.Name == "Colors").Type;
|
||||
IEdmTypeReference returnType = actionImport.Action.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.True(colors.IsCollection());
|
||||
Assert.False(colors.AsCollection().ElementType().IsNullable);
|
||||
Assert.Same(colorType, colors.AsCollection().ElementType().Definition);
|
||||
Assert.True(returnType.IsNullable);
|
||||
Assert.Same(colorType, returnType.Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnboundFunction_ForEnumTypeInODataConventionModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
FunctionConfiguration functionConfiguration = builder.Function("UnboundFunction");
|
||||
functionConfiguration.Parameter<Color>("Color");
|
||||
functionConfiguration.ReturnsCollection<Color>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmFunctionImport functionImport = model.EntityContainers().Single().OperationImports().Single(o => o.Name == "UnboundFunction") as IEdmFunctionImport;
|
||||
|
||||
IEdmTypeReference color = functionImport.Function.Parameters.Single(p => p.Name == "Color").Type;
|
||||
IEdmTypeReference returnType = functionImport.Function.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.Same(colorType, color.Definition);
|
||||
Assert.True(returnType.IsCollection());
|
||||
Assert.Same(colorType, returnType.AsCollection().ElementType().Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundAction_ForEnumTypeInODataConventionModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
EntityTypeConfiguration<EnumModel> entityTypeConfiguration = builder.Entity<EnumModel>();
|
||||
ActionConfiguration actionConfiguration = entityTypeConfiguration.Action("BoundAction");
|
||||
actionConfiguration.Parameter<Color>("Color");
|
||||
actionConfiguration.ReturnsCollection<Color>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmAction action = model.FindDeclaredOperations("Default.BoundAction").Single() as IEdmAction;
|
||||
|
||||
IEdmTypeReference color = action.Parameters.Single(p => p.Name == "Color").Type;
|
||||
IEdmTypeReference returnType = action.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.Same(colorType, color.Definition);
|
||||
Assert.True(returnType.IsCollection());
|
||||
Assert.Same(colorType, returnType.AsCollection().ElementType().Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundFunction_ForEnumTypeInODataConventionModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
EntityTypeConfiguration<EnumModel> entityTypeConfiguration = builder.Entity<EnumModel>();
|
||||
FunctionConfiguration functionConfiguration = entityTypeConfiguration.Function("BoundFunction");
|
||||
functionConfiguration.CollectionParameter<Color?>("Colors");
|
||||
functionConfiguration.Returns<Color>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmFunction function = model.FindDeclaredOperations("Default.BoundFunction").Single() as IEdmFunction;
|
||||
|
||||
IEdmTypeReference colors = function.Parameters.Single(p => p.Name == "Colors").Type;
|
||||
IEdmTypeReference returnType = function.ReturnType;
|
||||
IEdmEnumType colorType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "Color");
|
||||
|
||||
Assert.True(colors.IsCollection());
|
||||
Assert.True(colors.AsCollection().ElementType().IsNullable);
|
||||
Assert.Same(colorType, colors.AsCollection().ElementType().Definition);
|
||||
Assert.Same(colorType, returnType.Definition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoundFunction_ForEnumWithLongUnderlyingTypeInODataModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataModelBuilder builder = new ODataModelBuilder();
|
||||
builder.Add_LongEnum_EnumType();
|
||||
EntityTypeConfiguration<EnumModel> entityTypeConfiguration = builder.Entity<EnumModel>();
|
||||
FunctionConfiguration functionConfiguration = entityTypeConfiguration.Function("BoundFunction");
|
||||
functionConfiguration.Parameter<LongEnum>("LongEnum");
|
||||
functionConfiguration.Returns<int>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmFunction function = model.FindDeclaredOperations("Default.BoundFunction").Single() as IEdmFunction;
|
||||
|
||||
IEdmTypeReference longEnumParameter = function.Parameters.Single(p => p.Name == "LongEnum").Type;
|
||||
|
||||
IEdmEnumType longEnumType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "LongEnum");
|
||||
|
||||
Assert.Same(longEnumType, longEnumParameter.Definition);
|
||||
Assert.Equal(EdmPrimitiveTypeKind.Int64, longEnumParameter.AsEnum().EnumDefinition().UnderlyingType.PrimitiveKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnboundAction_ForEnumWithShortUnderlyingTypeInODataConventionModelBuilder()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
ActionConfiguration actionConfiguration = builder.Action("UnboundAction");
|
||||
actionConfiguration.Returns<ShortEnum>();
|
||||
|
||||
// Act & Assert
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmAction action = model.FindDeclaredOperations("Default.UnboundAction").Single() as IEdmAction;
|
||||
|
||||
IEdmTypeReference returnType = action.ReturnType;
|
||||
IEdmEnumType shortEnumType = model.SchemaElements.OfType<IEdmEnumType>().Single(e => e.Name == "ShortEnum");
|
||||
|
||||
Assert.Same(shortEnumType, returnType.Definition);
|
||||
Assert.Equal(EdmPrimitiveTypeKind.Int16, returnType.AsEnum().EnumDefinition().UnderlyingType.PrimitiveKind);
|
||||
}
|
||||
|
||||
private IEdmStructuredType AddComplexTypeWithODataConventionModelBuilder()
|
||||
{
|
||||
var builder = new ODataConventionModelBuilder();
|
||||
builder.ComplexType<ComplexTypeWithEnumTypePropertyTestModel>();
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
return model.SchemaElements.OfType<IEdmStructuredType>().Single();
|
||||
}
|
||||
|
||||
private IEdmEntityType AddEntityTypeWithODataConventionModelBuilder()
|
||||
{
|
||||
var builder = new ODataConventionModelBuilder();
|
||||
builder.EntitySet<EntityTypeWithEnumTypePropertyTestModel>("Entities");
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
IEdmEntitySet entitySet = model.EntityContainers().Single().FindEntitySet("Entities");
|
||||
return entitySet.ElementType;
|
||||
}
|
||||
}
|
||||
|
||||
public class ComplexTypeWithEnumTypePropertyTestModel
|
||||
|
@ -648,7 +915,6 @@ namespace System.Web.Http.OData.Builder
|
|||
public LongEnum LongEnum { get; set; }
|
||||
public Color? NullableColor { get; set; }
|
||||
public List<Color> Colors { get; set; }
|
||||
public ComplexTypeWithEnumTypePropertyTestModel ComplexType { get; set; }
|
||||
}
|
||||
|
||||
public abstract class BaseTypeWithEnumTypePropertyTestModel
|
||||
|
|
|
@ -173,7 +173,7 @@ namespace System.Web.Http.OData
|
|||
EntityInstanceContext entityContext = new EntityInstanceContext { EntityType = entityType, EdmModel = model, EdmObject = instance };
|
||||
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => entityContext.EntityInstance, "The provided mapping doesn't contain an entry for the entity type 'NS.Name'.");
|
||||
() => entityContext.EntityInstance, "The provided mapping does not contain an entry for the entity type 'NS.Name'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Http.OData.Builder;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using System.Web.Http.OData.Formatter;
|
||||
using System.Web.Http.OData.Formatter.Deserialization;
|
||||
|
@ -107,6 +108,34 @@ namespace System.Web.Http.OData
|
|||
"messageReader");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataEnumDeserializerRead_Throws_ForNullTypeParameter()
|
||||
{
|
||||
// Arrange
|
||||
ODataMessageReader messageReader = new ODataMessageReader(new Mock<IODataRequestMessage>().Object);
|
||||
Type type = null;
|
||||
ODataDeserializerContext readContext = new ODataDeserializerContext();
|
||||
|
||||
// Act & Assert
|
||||
Assert.ThrowsArgumentNull(
|
||||
() => new ODataEnumDeserializer().Read(messageReader, type, readContext),
|
||||
"type");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ODataEnumDeserializerRead_Throws_ForNullReadContextParameter()
|
||||
{
|
||||
// Arrange
|
||||
ODataMessageReader messageReader = new ODataMessageReader(new Mock<IODataRequestMessage>().Object);
|
||||
Type type = typeof(Color);
|
||||
ODataDeserializerContext readContext = null;
|
||||
|
||||
// Act & Assert
|
||||
Assert.ThrowsArgumentNull(
|
||||
() => new ODataEnumDeserializer().Read(messageReader, type, readContext),
|
||||
"readContext");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullEnumValueDeserializerTest()
|
||||
{
|
||||
|
@ -117,23 +146,21 @@ namespace System.Web.Http.OData
|
|||
{
|
||||
Properties = new[]
|
||||
{
|
||||
new ODataProperty { Name = "RequiredColor", Value = "Red"},
|
||||
new ODataProperty { Name = "NullableColor", Value = null}
|
||||
},
|
||||
TypeName = "TestModel.EnumComplex"
|
||||
TypeName = "System.Web.Http.OData.EnumComplexWithNullableEnum"
|
||||
};
|
||||
|
||||
IEdmModel model = GetEdmModel();
|
||||
ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model };
|
||||
IEdmComplexTypeReference enumComplexrTypeReference = model.GetEdmTypeReference(typeof(EnumComplex)).AsComplex();
|
||||
IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithNullableEnum)).AsComplex();
|
||||
|
||||
// Act
|
||||
var enumComplex = deserializer.ReadComplexValue(complexValue, enumComplexrTypeReference, readContext) as EnumComplex;
|
||||
var enumComplexWithNullableEnum = deserializer.ReadComplexValue(complexValue, enumComplexTypeReference, readContext) as EnumComplexWithNullableEnum;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(enumComplex);
|
||||
Assert.Equal(Color.Red, enumComplex.RequiredColor);
|
||||
Assert.Null(enumComplex.NullableColor);
|
||||
Assert.NotNull(enumComplexWithNullableEnum);
|
||||
Assert.Null(enumComplexWithNullableEnum.NullableColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -146,49 +173,69 @@ namespace System.Web.Http.OData
|
|||
{
|
||||
Properties = new[]
|
||||
{
|
||||
new ODataProperty { Name = "RequiredColor", Value = (Color)123},
|
||||
new ODataProperty { Name = "NullableColor", Value = Color.Green | Color.Blue}
|
||||
new ODataProperty { Name = "RequiredColor", Value = (Color)123}
|
||||
},
|
||||
TypeName = "TestModel.EnumComplex"
|
||||
TypeName = "System.Web.Http.OData.EnumComplexWithRequiredEnum"
|
||||
};
|
||||
|
||||
IEdmModel model = GetEdmModel();
|
||||
ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model };
|
||||
IEdmComplexTypeReference enumComplexrTypeReference = model.GetEdmTypeReference(typeof(EnumComplex)).AsComplex();
|
||||
IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithRequiredEnum)).AsComplex();
|
||||
|
||||
// Act
|
||||
var enumComplex = deserializer.ReadComplexValue(complexValue, enumComplexrTypeReference, readContext) as EnumComplex;
|
||||
var enumComplexWithRequiredEnum = deserializer.ReadComplexValue(complexValue, enumComplexTypeReference, readContext) as EnumComplexWithRequiredEnum;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(enumComplex);
|
||||
Assert.Equal((Color)123, enumComplex.RequiredColor);
|
||||
Assert.Equal(Color.Green | Color.Blue, enumComplex.NullableColor);
|
||||
Assert.NotNull(enumComplexWithRequiredEnum);
|
||||
Assert.Equal((Color)123, enumComplexWithRequiredEnum.RequiredColor);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Color.Red)]
|
||||
[InlineData(Color.Green | Color.Blue)]
|
||||
[InlineData((Color)1)]
|
||||
[InlineData((Color)123)]
|
||||
public void EnumValueDeserializerTest(Color color)
|
||||
{
|
||||
// Arrange
|
||||
var deserializerProvider = new Mock<ODataDeserializerProvider>().Object;
|
||||
var deserializer = new ODataComplexTypeDeserializer(deserializerProvider);
|
||||
ODataComplexValue complexValue = new ODataComplexValue
|
||||
{
|
||||
Properties = new[]
|
||||
{
|
||||
new ODataProperty { Name = "RequiredColor", Value = color}
|
||||
},
|
||||
TypeName = "System.Web.Http.OData.EnumComplexWithRequiredEnum"
|
||||
};
|
||||
|
||||
IEdmModel model = GetEdmModel();
|
||||
ODataDeserializerContext readContext = new ODataDeserializerContext() { Model = model };
|
||||
IEdmComplexTypeReference enumComplexTypeReference = model.GetEdmTypeReference(typeof(EnumComplexWithRequiredEnum)).AsComplex();
|
||||
|
||||
// Act
|
||||
var enumComplexWithRequiredEnum = deserializer.ReadComplexValue(complexValue, enumComplexTypeReference, readContext) as EnumComplexWithRequiredEnum;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(enumComplexWithRequiredEnum);
|
||||
Assert.Equal(color, enumComplexWithRequiredEnum.RequiredColor);
|
||||
}
|
||||
|
||||
private IEdmModel GetEdmModel()
|
||||
{
|
||||
EdmModel model = new EdmModel();
|
||||
|
||||
EdmEnumType color = new EdmEnumType("TestModel", "Color");
|
||||
color.AddMember(new EdmEnumMember(color, "Red", new EdmIntegerConstant(1)));
|
||||
color.AddMember(new EdmEnumMember(color, "Green", new EdmIntegerConstant(2)));
|
||||
color.AddMember(new EdmEnumMember(color, "Blue", new EdmIntegerConstant(4)));
|
||||
model.AddElement(color);
|
||||
|
||||
EdmComplexType enumComplex = new EdmComplexType("TestModel", "EnumComplex");
|
||||
enumComplex.AddStructuralProperty("RequiredColor", color.ToEdmTypeReference(isNullable: false));
|
||||
enumComplex.AddStructuralProperty("NullableColor", color.ToEdmTypeReference(isNullable: true));
|
||||
model.AddElement(enumComplex);
|
||||
|
||||
model.SetAnnotationValue<ClrTypeAnnotation>(
|
||||
model.FindDeclaredType("TestModel.EnumComplex"), new ClrTypeAnnotation(typeof(EnumComplex)));
|
||||
|
||||
return model;
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
builder.ComplexType<EnumComplexWithRequiredEnum>();
|
||||
builder.ComplexType<EnumComplexWithNullableEnum>();
|
||||
return builder.GetEdmModel();
|
||||
}
|
||||
|
||||
private class EnumComplex
|
||||
private class EnumComplexWithRequiredEnum
|
||||
{
|
||||
public Color RequiredColor { get; set; }
|
||||
}
|
||||
|
||||
private class EnumComplexWithNullableEnum
|
||||
{
|
||||
public Color? NullableColor { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace System.Web.Http.OData
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateODataValue_Throws_ForNotEnumTypeon()
|
||||
public void CreateODataValue_Throws_ForNonEnumType()
|
||||
{
|
||||
// Arrange
|
||||
object graph = null;
|
||||
|
@ -109,6 +109,7 @@ namespace System.Web.Http.OData
|
|||
|
||||
private void EnumTypeSerializerTestForOData(string expectedContent, bool isJson)
|
||||
{
|
||||
// Arrange
|
||||
ODataMediaTypeFormatter formatter = GetFormatter();
|
||||
ObjectContent<EnumComplex> content = new ObjectContent<EnumComplex>(
|
||||
new EnumComplex()
|
||||
|
@ -119,6 +120,8 @@ namespace System.Web.Http.OData
|
|||
},
|
||||
formatter,
|
||||
GetMediaType(isJson));
|
||||
|
||||
// Act & Assert
|
||||
AssertEqual(isJson, expectedContent, content.ReadAsStringAsync().Result);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace System.Web.Http.OData.Formatter.Deserialization
|
|||
{
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => ODataComplexTypeDeserializer.CreateResource(_addressEdmType, new ODataDeserializerContext { Model = EdmCoreModel.Instance }),
|
||||
"The provided mapping doesn't contain an entry for the entity type 'ODataDemo.Address'.");
|
||||
"The provided mapping does not contain an entry for the entity type 'ODataDemo.Address'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -312,7 +312,7 @@ namespace System.Web.Http.OData.Formatter.Deserialization
|
|||
var deserializer = new ODataEntityDeserializer(_deserializerProvider);
|
||||
Assert.Throws<ODataException>(
|
||||
() => deserializer.CreateEntityResource(_productEdmType, new ODataDeserializerContext { Model = EdmCoreModel.Instance }),
|
||||
"The provided mapping doesn't contain an entry for the entity type 'ODataDemo.Product'.");
|
||||
"The provided mapping does not contain an entry for the entity type 'ODataDemo.Product'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Web.Http.OData.Builder.TestModels;
|
|||
using System.Web.Http.OData.Formatter.Deserialization;
|
||||
using System.Web.Http.OData.Formatter.Serialization;
|
||||
using System.Web.Http.Tracing;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.OData.Core;
|
||||
using Microsoft.OData.Core.Atom;
|
||||
|
@ -400,11 +401,13 @@ namespace System.Web.Http.OData.Formatter
|
|||
using (HttpClient client = new HttpClient(host))
|
||||
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers"))
|
||||
{
|
||||
request.Content = new StringContent(string.Format(
|
||||
@"{{'@odata.type':'#System.Web.Http.OData.Formatter.EnumCustomer','ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
|
||||
request.Content = new StringContent(
|
||||
string.Format(@"{{'@odata.type':'#System.Web.Http.OData.Formatter.EnumCustomer',
|
||||
'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
|
||||
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
request.Headers.Accept.ParseAdd("application/json");
|
||||
//Act
|
||||
|
||||
// Act
|
||||
using (HttpResponseMessage response = client.SendAsync(request).Result)
|
||||
{
|
||||
// Assert
|
||||
|
@ -421,6 +424,105 @@ namespace System.Web.Http.OData.Formatter
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnumSerializer_HasODataType_ForFullMetadata()
|
||||
{
|
||||
// Arrange & Act
|
||||
string acceptHeader = "application/json;odata.metadata=full";
|
||||
HttpResponseMessage response = GetEnumResponse(acceptHeader);
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
JObject customer = response.Content.ReadAsAsync<JObject>().Result;
|
||||
Assert.Equal("#System.Web.Http.OData.Builder.TestModels.Color",
|
||||
customer.GetValue("Color@odata.type"));
|
||||
Assert.Equal("#Collection(System.Web.Http.OData.Builder.TestModels.Color)",
|
||||
customer.GetValue("Colors@odata.type"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json;odata.metadata=minimal")]
|
||||
[InlineData("application/json;odata.metadata=none")]
|
||||
public void EnumSerializer_HasNoODataType_ForNonFullMetadata(string acceptHeader)
|
||||
{
|
||||
// Arrange & Act
|
||||
HttpResponseMessage response = GetEnumResponse(acceptHeader);
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
JObject customer = response.Content.ReadAsAsync<JObject>().Result;
|
||||
Assert.False(customer.Values().Contains("Color@odata.type"));
|
||||
Assert.False(customer.Values().Contains("Colors@odata.type"));
|
||||
}
|
||||
|
||||
private HttpResponseMessage GetEnumResponse(string acceptHeader)
|
||||
{
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
builder.EntitySet<EnumCustomer>("EnumCustomers");
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
|
||||
HttpConfiguration configuration = new HttpConfiguration();
|
||||
configuration.Routes.MapODataRoute("odata", routePrefix: null, model: model);
|
||||
HttpServer host = new HttpServer(configuration);
|
||||
HttpClient client = new HttpClient(host);
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers");
|
||||
request.Content = new StringContent(
|
||||
string.Format(@"{{'@odata.type':'#System.Web.Http.OData.Formatter.EnumCustomer',
|
||||
'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
|
||||
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
request.Headers.Accept.ParseAdd(acceptHeader);
|
||||
|
||||
HttpResponseMessage response = client.SendAsync(request).Result;
|
||||
return response;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnumSerializer_HasMetadataType_InAtom()
|
||||
{
|
||||
// Arrange
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
builder.EntitySet<EnumCustomer>("EnumCustomers");
|
||||
IEdmModel model = builder.GetEdmModel();
|
||||
|
||||
using (HttpConfiguration configuration = new HttpConfiguration())
|
||||
{
|
||||
configuration.Routes.MapODataRoute("odata", routePrefix: null, model: model);
|
||||
using (HttpServer host = new HttpServer(configuration))
|
||||
using (HttpClient client = new HttpClient(host))
|
||||
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers"))
|
||||
{
|
||||
request.Content = new StringContent(
|
||||
string.Format(@"{{'@odata.type':'#System.Web.Http.OData.Formatter.EnumCustomer',
|
||||
'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
|
||||
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
request.Headers.Accept.ParseAdd("application/atom+xml");
|
||||
|
||||
// Act
|
||||
using (HttpResponseMessage response = client.SendAsync(request).Result)
|
||||
{
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
var atomResult = response.Content.ReadAsStreamAsync().Result;
|
||||
var atomXmlDocument = new XmlDocument();
|
||||
atomXmlDocument.Load(atomResult);
|
||||
|
||||
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(atomXmlDocument.NameTable);
|
||||
namespaceManager.AddNamespace("ns", atomXmlDocument.DocumentElement.NamespaceURI);
|
||||
namespaceManager.AddNamespace("m", atomXmlDocument.DocumentElement.GetNamespaceOfPrefix("m"));
|
||||
namespaceManager.AddNamespace("d", atomXmlDocument.DocumentElement.GetNamespaceOfPrefix("d"));
|
||||
|
||||
var colorMetadataType = atomXmlDocument.DocumentElement.SelectNodes(
|
||||
"ns:content/m:properties/d:Color/attribute::m:type", namespaceManager).Cast<XmlNode>().Select(e => e.Value);
|
||||
var colorsMetadataType = atomXmlDocument.DocumentElement.SelectNodes(
|
||||
"ns:content/m:properties/d:Colors/attribute::m:type", namespaceManager).Cast<XmlNode>().Select(e => e.Value);
|
||||
Assert.Equal("#System.Web.Http.OData.Builder.TestModels.Color", colorMetadataType.Single());
|
||||
Assert.Equal("#Collection(System.Web.Http.OData.Builder.TestModels.Color)", colorsMetadataType.Single());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumCustomer
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
@ -599,10 +701,6 @@ namespace System.Web.Http.OData.Formatter
|
|||
|
||||
public short Int16 { get; set; }
|
||||
|
||||
public FlagsEnum FlagsEnum { get; set; }
|
||||
|
||||
public List<FlagsEnum> FlagsEnums { get; set; }
|
||||
|
||||
public RelatedEntity Related { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,17 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.Dispatcher;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using System.Web.Http.OData.Builder;
|
||||
using System.Web.Http.OData.Builder.Conventions;
|
||||
using System.Web.Http.OData.Routing;
|
||||
using System.Web.Http.OData.TestCommon;
|
||||
using System.Web.Http.Routing;
|
||||
using System.Web.Http.ValueProviders;
|
||||
using Microsoft.OData.Core;
|
||||
using Microsoft.OData.Core.UriParser;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.TestCommon;
|
||||
using Microsoft.TestCommon.Types;
|
||||
|
||||
|
@ -51,12 +56,11 @@ namespace System.Web.Http.OData.Formatter
|
|||
{ (byte)1, "GetByte" },
|
||||
{ "123", "GetString" },
|
||||
{ Guid.Empty, "GetGuid" },
|
||||
// TODO: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
// TODO 1559: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
{ TimeSpan.FromTicks(424242), "GetTimeSpan" },
|
||||
{ DateTimeOffset.MaxValue, "GetDateTimeOffset" },
|
||||
{ float.NaN, "GetFloat" },
|
||||
// TODO: ODataLib v4 issue on decimal handling, bug filed.
|
||||
//{ decimal.MaxValue, "GetDecimal" }
|
||||
// TODO 1560: ODataLib v4 issue on decimal handling, bug filed.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -68,14 +72,14 @@ namespace System.Web.Http.OData.Formatter
|
|||
return new TheoryDataSet<object, string>
|
||||
{
|
||||
{ "123", "GetBool" },
|
||||
//{ 123, "GetDateTime" }, // v4 does not support DateTime
|
||||
// TODO 1559: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
{ "abc", "GetInt32" },
|
||||
{ "abc", "GetGuid" },
|
||||
{ "abc", "GetByte" },
|
||||
{ "abc", "GetFloat" },
|
||||
{ "abc", "GetDouble" },
|
||||
{ "abc", "GetDecimal" },
|
||||
//{ "abc", "GetDateTime" }, // v4 does not support DateTime
|
||||
// TODO 1559: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
{ "abc", "GetTimeSpan" },
|
||||
{ "abc", "GetDateTimeOffset" },
|
||||
{ -1, "GetUInt16"},
|
||||
|
@ -201,6 +205,85 @@ namespace System.Web.Http.OData.Formatter
|
|||
"name-2009",
|
||||
response.Content.ReadAsAsync<string>().Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SimpleEnum.First, "GetEnum", "simpleEnum")]
|
||||
[InlineData(FlagsEnum.One | FlagsEnum.Two, "GetFlagsEnum", "flagsEnum")]
|
||||
[InlineData((SimpleEnum)12, "GetEnum", "simpleEnum")]
|
||||
[InlineData((FlagsEnum)23, "GetFlagsEnum", "flagsEnum")]
|
||||
public void ODataModelBinderProvider_Works_ForEnum(object value, string action, string parameterName)
|
||||
{
|
||||
// Arrange
|
||||
HttpConfiguration configuration = new HttpConfiguration();
|
||||
configuration.Services.Replace(typeof(ModelBinderProvider), new ODataModelBinderProvider());
|
||||
configuration.Routes.MapODataRoute("odata", "", GetEdmModel())
|
||||
.MapODataRouteAttributes(configuration);
|
||||
|
||||
var controllers = new[] { typeof(ODataModelBinderProviderTestODataController) };
|
||||
TestAssemblyResolver resolver = new TestAssemblyResolver(new MockAssembly(controllers));
|
||||
configuration.Services.Replace(typeof(IAssembliesResolver), resolver);
|
||||
|
||||
HttpServer server = new HttpServer(configuration);
|
||||
HttpClient client = new HttpClient(server);
|
||||
|
||||
// Act
|
||||
string url = String.Format(
|
||||
"http://localhost/{0}({1}={2})",
|
||||
action,
|
||||
parameterName,
|
||||
Uri.EscapeDataString(ConventionsHelpers.GetUriRepresentationForValue(value)));
|
||||
HttpResponseMessage response = client.GetAsync(url).Result;
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal(
|
||||
value,
|
||||
response.Content.ReadAsAsync(value.GetType(), configuration.Formatters).Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("abc", "GetEnum", "simpleEnum")]
|
||||
public void ODataModelBinderProvider_Throws_ForInvalidEnum(object value, string action, string parameterName)
|
||||
{
|
||||
// Arrange
|
||||
HttpConfiguration configuration = new HttpConfiguration();
|
||||
configuration.Services.Replace(typeof(ModelBinderProvider), new ODataModelBinderProvider());
|
||||
configuration.Routes.MapODataRoute("odata", "", GetEdmModel())
|
||||
.MapODataRouteAttributes(configuration);
|
||||
|
||||
var controllers = new[] { typeof(ODataModelBinderProviderTestODataController) };
|
||||
TestAssemblyResolver resolver = new TestAssemblyResolver(new MockAssembly(controllers));
|
||||
configuration.Services.Replace(typeof(IAssembliesResolver), resolver);
|
||||
|
||||
HttpServer server = new HttpServer(configuration);
|
||||
HttpClient client = new HttpClient(server);
|
||||
|
||||
// Act
|
||||
string url = String.Format(
|
||||
"http://localhost/{0}({1}={2})",
|
||||
action,
|
||||
parameterName,
|
||||
Uri.EscapeDataString(ConventionsHelpers.GetUriRepresentationForValue(value)));
|
||||
HttpResponseMessage response = client.GetAsync(url).Result;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
|
||||
private IEdmModel GetEdmModel()
|
||||
{
|
||||
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
|
||||
|
||||
FunctionConfiguration getEnum = builder.Function("GetEnum");
|
||||
getEnum.Parameter<SimpleEnum>("simpleEnum");
|
||||
getEnum.Returns<SimpleEnum>();
|
||||
|
||||
FunctionConfiguration getFlagsEnum = builder.Function("GetFlagsEnum");
|
||||
getFlagsEnum.Parameter<FlagsEnum>("flagsEnum");
|
||||
getFlagsEnum.Returns<FlagsEnum>();
|
||||
|
||||
return builder.GetEdmModel();
|
||||
}
|
||||
}
|
||||
|
||||
public class ODataKeyAttribute : ModelBinderAttribute
|
||||
|
@ -312,13 +395,8 @@ namespace System.Web.Http.OData.Formatter
|
|||
return id;
|
||||
}
|
||||
|
||||
// TODO: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
//public DateTime GetDateTime(DateTime id)
|
||||
//{
|
||||
// ThrowIfInsideThrowsController();
|
||||
// return id;
|
||||
//}
|
||||
|
||||
// TODO 1559: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
|
||||
public TimeSpan GetTimeSpan(TimeSpan id)
|
||||
{
|
||||
ThrowIfInsideThrowsController();
|
||||
|
@ -393,4 +471,22 @@ namespace System.Web.Http.OData.Formatter
|
|||
return name + "-" + model;
|
||||
}
|
||||
}
|
||||
|
||||
public class ODataModelBinderProviderTestODataController : ODataController
|
||||
{
|
||||
[HttpGet]
|
||||
[ODataRoute("GetEnum(simpleEnum={simpleEnum})")]
|
||||
public SimpleEnum GetEnum(SimpleEnum simpleEnum)
|
||||
{
|
||||
return simpleEnum;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ODataRoute("GetFlagsEnum(flagsEnum={flagsEnum})")]
|
||||
public FlagsEnum GetFlagsEnum(FlagsEnum flagsEnum)
|
||||
{
|
||||
return flagsEnum;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System.Net.Http;
|
||||
using System.Web.Http.OData.Builder;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using System.Web.Http.OData.Routing;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.TestCommon;
|
||||
|
@ -10,11 +11,24 @@ namespace System.Web.Http.OData.Formatter
|
|||
{
|
||||
public class ODataRawValueMediaTypeMappingTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryMatchMediaTypeWithPrimitiveRawValueThrowsArgumentNullWhenRequestIsNull()
|
||||
public static TheoryDataSet<ODataRawValueMediaTypeMapping> ODataRawValueMediaTypeMappings
|
||||
{
|
||||
ODataPrimitiveValueMediaTypeMapping mapping = new ODataPrimitiveValueMediaTypeMapping();
|
||||
get
|
||||
{
|
||||
return new TheoryDataSet<ODataRawValueMediaTypeMapping>
|
||||
{
|
||||
new ODataPrimitiveValueMediaTypeMapping(),
|
||||
new ODataBinaryValueMediaTypeMapping(),
|
||||
new ODataEnumValueMediaTypeMapping()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[PropertyData("ODataRawValueMediaTypeMappings")]
|
||||
public void TryMatchMediaType_ThrowsArgumentNull_WhenRequestIsNull(ODataRawValueMediaTypeMapping mapping)
|
||||
{
|
||||
// Arrange, Act & Assert
|
||||
Assert.ThrowsArgumentNull(() => { mapping.TryMatchMediaType(null); }, "request");
|
||||
}
|
||||
|
||||
|
@ -34,14 +48,17 @@ namespace System.Web.Http.OData.Formatter
|
|||
Assert.Equal(1.0, mapResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryMatchMediaTypeWithNonODataRequestDoesntMatchRequest()
|
||||
[Theory]
|
||||
[PropertyData("ODataRawValueMediaTypeMappings")]
|
||||
public void TryMatchMediaType_DoesntMatchRequest_WithNonODataRequest(ODataRawValueMediaTypeMapping mapping)
|
||||
{
|
||||
ODataPrimitiveValueMediaTypeMapping mapping = new ODataPrimitiveValueMediaTypeMapping();
|
||||
// Arrange
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/");
|
||||
|
||||
// Act
|
||||
double mapResult = mapping.TryMatchMediaType(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, mapResult);
|
||||
}
|
||||
|
||||
|
@ -61,6 +78,44 @@ namespace System.Web.Http.OData.Formatter
|
|||
Assert.Equal(0, mapResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryMatchMediaType_MatchesRequest_WithEnumRawValue()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = GetEnumModel();
|
||||
PropertyAccessPathSegment propertySegment = new PropertyAccessPathSegment((model.GetEdmType(typeof(EnumEntity)) as IEdmEntityType).FindProperty("EnumProperty"));
|
||||
ODataPath path = new ODataPath(new EntitySetPathSegment("EnumEntity"), new KeyValuePathSegment("1"), propertySegment, new ValuePathSegment());
|
||||
ODataEnumValueMediaTypeMapping mapping = new ODataEnumValueMediaTypeMapping();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EnumEntity(1)/EnumProperty/$value");
|
||||
request.SetEdmModel(model);
|
||||
request.SetODataPath(path);
|
||||
|
||||
// Act
|
||||
double mapResult = mapping.TryMatchMediaType(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1.0, mapResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryMatchMediaType_DoesnotMatchRequest_ODataEnumValueMediaTypeMappingWithNonRawvalueRequest()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = GetEnumModel();
|
||||
PropertyAccessPathSegment propertySegment = new PropertyAccessPathSegment((model.GetEdmType(typeof(EnumEntity)) as IEdmEntityType).FindProperty("EnumProperty"));
|
||||
ODataPath path = new ODataPath(new EntitySetPathSegment("EnumEntity"), new KeyValuePathSegment("1"), propertySegment);
|
||||
ODataEnumValueMediaTypeMapping mapping = new ODataEnumValueMediaTypeMapping();
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EnumEntity(1)/EnumProperty/");
|
||||
request.SetEdmModel(model);
|
||||
request.SetODataPath(path);
|
||||
|
||||
// Act
|
||||
double mapResult = mapping.TryMatchMediaType(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, mapResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryMatchMediaTypeWithBinaryRawValueMatchesRequest()
|
||||
{
|
||||
|
@ -89,5 +144,18 @@ namespace System.Web.Http.OData.Formatter
|
|||
builder.EntitySet<RawValueEntity>("RawValue");
|
||||
return builder.GetEdmModel();
|
||||
}
|
||||
|
||||
private class EnumEntity
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public Color EnumProperty { get; set; }
|
||||
}
|
||||
|
||||
private static IEdmModel GetEnumModel()
|
||||
{
|
||||
ODataModelBuilder builder = new ODataConventionModelBuilder();
|
||||
builder.EntitySet<EnumEntity>("EnumEntity");
|
||||
return builder.GetEdmModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Net.Http;
|
|||
using System.Net.Http.Headers;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Http.OData.Builder;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using System.Web.Http.OData.Formatter.Deserialization;
|
||||
using System.Web.Http.OData.Formatter.Serialization;
|
||||
using System.Web.Http.OData.Routing;
|
||||
|
@ -68,6 +69,11 @@ namespace System.Web.Http.OData.Formatter
|
|||
{
|
||||
ODataModelBuilder model = new ODataModelBuilder();
|
||||
|
||||
var color = model.EnumType<Color>();
|
||||
color.Member(Color.Red);
|
||||
color.Member(Color.Green);
|
||||
color.Member(Color.Blue);
|
||||
|
||||
var people = model.EntitySet<FormatterPerson>("People");
|
||||
people.HasFeedSelfLink(context => new Uri(context.Url.ODataLink(new EntitySetPathSegment(
|
||||
context.EntitySet))));
|
||||
|
@ -84,6 +90,7 @@ namespace System.Web.Http.OData.Formatter
|
|||
person.Property(p => p.Age);
|
||||
person.Property(p => p.MyGuid);
|
||||
person.Property(p => p.Name);
|
||||
person.EnumProperty(p => p.FavoriteColor);
|
||||
person.ComplexProperty<FormatterOrder>(p => p.Order);
|
||||
|
||||
var order = model.ComplexType<FormatterOrder>();
|
||||
|
@ -122,6 +129,7 @@ namespace System.Web.Http.OData.Formatter
|
|||
public Guid MyGuid { get; set; }
|
||||
public string Name { get; set; }
|
||||
public FormatterOrder Order { get; set; }
|
||||
public Color FavoriteColor { get; set; }
|
||||
[Key]
|
||||
public int PerId { get; set; }
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
|
||||
namespace System.Web.Http.OData.Formatter
|
||||
{
|
||||
|
@ -21,7 +22,7 @@ namespace System.Web.Http.OData.Formatter
|
|||
|
||||
public FormatterPerson GetFormatterPerson(int key)
|
||||
{
|
||||
FormatterPerson obj = new FormatterPerson() { MyGuid = new Guid("f99080c0-2f9e-472e-8c72-1a8ecd9f902d"), PerId = key, Age = 10, Name = "Asha", Order = new FormatterOrder() { OrderName = "FirstOrder", OrderAmount = 235342 } };
|
||||
FormatterPerson obj = new FormatterPerson() { MyGuid = new Guid("f99080c0-2f9e-472e-8c72-1a8ecd9f902d"), PerId = key, Age = 10, Name = "Asha", Order = new FormatterOrder() { OrderName = "FirstOrder", OrderAmount = 235342 }, FavoriteColor = Color.Red | Color.Green };
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Web.Http.OData.Routing;
|
|||
using Microsoft.OData.Core;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Library;
|
||||
using Microsoft.OData.Edm.Library.Values;
|
||||
using Microsoft.TestCommon;
|
||||
using Moq;
|
||||
|
||||
|
@ -26,8 +27,7 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
{ typeof(byte[]), EdmPrimitiveTypeKind.Binary },
|
||||
{ typeof(bool), EdmPrimitiveTypeKind.Boolean },
|
||||
{ typeof(byte), EdmPrimitiveTypeKind.Byte },
|
||||
// TODO: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
// { typeof(DateTime), EdmPrimitiveTypeKind.DateTimeOffset },
|
||||
// TODO 1559: Investigate how to add support for DataTime in webapi.odata, ODataLib v4 does not support it.
|
||||
{ typeof(DateTimeOffset), EdmPrimitiveTypeKind.DateTimeOffset },
|
||||
{ typeof(decimal), EdmPrimitiveTypeKind.Decimal },
|
||||
{ typeof(double), EdmPrimitiveTypeKind.Double },
|
||||
|
@ -104,6 +104,32 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
Assert.Equal(ODataPayloadKind.Value, serializer.ODataPayloadKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetODataSerializer_Enum()
|
||||
{
|
||||
var serializerProvider = new DefaultODataSerializerProvider();
|
||||
HttpRequestMessage request = new HttpRequestMessage();
|
||||
var serializer = serializerProvider.GetODataPayloadSerializer(GetEnumModel(), typeof(TestEnum), request);
|
||||
|
||||
Assert.NotNull(serializer);
|
||||
var enumSerializer = Assert.IsType<ODataEnumSerializer>(serializer);
|
||||
Assert.Equal(ODataPayloadKind.Property, enumSerializer.ODataPayloadKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetODataPayloadSerializer_ReturnsRawValueSerializer_ForEnumValueRequests()
|
||||
{
|
||||
ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider();
|
||||
HttpRequestMessage request = new HttpRequestMessage();
|
||||
request.SetODataPath(new ODataPath(new ValuePathSegment()));
|
||||
|
||||
var serializer = serializerProvider.GetODataPayloadSerializer(GetEnumModel(), typeof(TestEnum), request);
|
||||
|
||||
Assert.NotNull(serializer);
|
||||
var rawValueSerializer = Assert.IsType<ODataRawValueSerializer>(serializer);
|
||||
Assert.Equal(ODataPayloadKind.Value, rawValueSerializer.ODataPayloadKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetODataSerializer_Entity()
|
||||
{
|
||||
|
@ -231,6 +257,20 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
Assert.Same(instance1, instance2);
|
||||
}
|
||||
|
||||
private static IEdmModel GetEnumModel()
|
||||
{
|
||||
EdmModel model = new EdmModel();
|
||||
|
||||
EdmEnumType enumType = new EdmEnumType("TestModel", "TestEnum");
|
||||
enumType.AddMember(new EdmEnumMember(enumType, "FirstValue", new EdmIntegerConstant(0)));
|
||||
enumType.AddMember(new EdmEnumMember(enumType, "FirstValue", new EdmIntegerConstant(1)));
|
||||
model.AddElement(enumType);
|
||||
|
||||
model.SetAnnotationValue(model.FindDeclaredType("TestModel.TestEnum"), new ClrTypeAnnotation(typeof(TestEnum)));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private enum TestEnum
|
||||
{
|
||||
FirstValue,
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.OData.Core;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Library;
|
||||
using Microsoft.TestCommon;
|
||||
|
||||
namespace System.Web.Http.OData.Formatter.Serialization
|
||||
{
|
||||
public class ODataEnumTypeSerializerTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(ODataMetadataLevel.Default)]
|
||||
[InlineData(ODataMetadataLevel.MinimalMetadata)]
|
||||
public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation(ODataMetadataLevel metadataLevel)
|
||||
{
|
||||
// Arrange
|
||||
ODataEnumValue enumValue = new ODataEnumValue("value");
|
||||
IEdmEnumTypeReference enumType = new EdmEnumTypeReference(
|
||||
new EdmEnumType("TestModel", "EnumType"), isNullable: false);
|
||||
|
||||
// Act
|
||||
ODataEnumSerializer.AddTypeNameAnnotationAsNeeded(enumValue, enumType, metadataLevel);
|
||||
|
||||
// Assert
|
||||
SerializationTypeNameAnnotation annotation = enumValue.GetAnnotation<SerializationTypeNameAnnotation>();
|
||||
Assert.Null(annotation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTypeNameAnnotationAsNeeded_AddAnnotation_InFullMetadataMode()
|
||||
{
|
||||
// Arrange
|
||||
ODataEnumValue enumValue = new ODataEnumValue("value");
|
||||
IEdmEnumTypeReference enumType = new EdmEnumTypeReference(
|
||||
new EdmEnumType("TestModel", "EnumType"), isNullable: false);
|
||||
|
||||
// Act
|
||||
ODataEnumSerializer.AddTypeNameAnnotationAsNeeded(enumValue, enumType, ODataMetadataLevel.FullMetadata);
|
||||
|
||||
// Assert
|
||||
SerializationTypeNameAnnotation annotation = enumValue.GetAnnotation<SerializationTypeNameAnnotation>();
|
||||
Assert.NotNull(annotation);
|
||||
Assert.Equal("TestModel.EnumType", annotation.TypeName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTypeNameAnnotationAsNeeded_AddsNullAnnotation_InNoMetadataMode()
|
||||
{
|
||||
// Arrange
|
||||
ODataEnumValue enumValue = new ODataEnumValue("value");
|
||||
IEdmEnumTypeReference enumType = new EdmEnumTypeReference(
|
||||
new EdmEnumType("TestModel", "EnumType"), isNullable: false);
|
||||
|
||||
// Act
|
||||
ODataEnumSerializer.AddTypeNameAnnotationAsNeeded(enumValue, enumType, ODataMetadataLevel.NoMetadata);
|
||||
|
||||
// Assert
|
||||
SerializationTypeNameAnnotation annotation = enumValue.GetAnnotation<SerializationTypeNameAnnotation>();
|
||||
Assert.NotNull(annotation);
|
||||
Assert.Null(annotation.TypeName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using Microsoft.OData.Core;
|
||||
using Microsoft.TestCommon;
|
||||
using Moq;
|
||||
|
@ -50,5 +51,23 @@ namespace System.Web.Http.OData.Formatter.Serialization
|
|||
|
||||
Assert.Equal(value.ToString(), reader.ReadToEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializesEnumType()
|
||||
{
|
||||
ODataRawValueSerializer serializer = new ODataRawValueSerializer();
|
||||
Mock<IODataRequestMessage> mockRequest = new Mock<IODataRequestMessage>();
|
||||
Stream stream = new MemoryStream();
|
||||
mockRequest.Setup(r => r.GetStream()).Returns(stream);
|
||||
ODataMessageWriter messageWriter = new ODataMessageWriter(mockRequest.Object);
|
||||
object value = Color.Red | Color.Blue;
|
||||
|
||||
serializer.WriteObject(value, value.GetType(), messageWriter, null);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
TextReader reader = new StreamReader(stream);
|
||||
string result = reader.ReadToEnd();
|
||||
|
||||
Assert.Equal(value.ToString(), result, ignoreCase: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,7 +385,7 @@ namespace System.Web.Http.OData.Query.Expressions
|
|||
|
||||
Assert.Throws<ODataException>(
|
||||
() => _binder.CreatePropertyNameExpression(_model.Customer, specialOrdersProperty, customer),
|
||||
"The provided mapping doesn't contain an entry for the entity type 'NS.SpecialCustomer'.");
|
||||
"The provided mapping does not contain an entry for the entity type 'NS.SpecialCustomer'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -421,7 +421,7 @@ namespace System.Web.Http.OData.Query.Expressions
|
|||
|
||||
Assert.Throws<ODataException>(
|
||||
() => _binder.CreatePropertyValueExpression(_model.Customer, specialOrdersProperty, customer),
|
||||
"The provided mapping doesn't contain an entry for the entity type 'NS.SpecialCustomer'.");
|
||||
"The provided mapping does not contain an entry for the entity type 'NS.SpecialCustomer'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -506,7 +506,7 @@ namespace System.Web.Http.OData.Query.Expressions
|
|||
// Act & Assert
|
||||
Assert.Throws<ODataException>(
|
||||
() => SelectExpandBinder.CreateTypeNameExpression(source, baseType, model),
|
||||
"The provided mapping doesn't contain an entry for the entity type 'NS.DerivedType'.");
|
||||
"The provided mapping does not contain an entry for the entity type 'NS.DerivedType'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -492,6 +492,29 @@ namespace System.Web.Http.OData.Query
|
|||
actualCustomers.Select(enumModel => enumModel.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Simple has null", typeof(ODataException))]
|
||||
[InlineData("null has Microsoft.TestCommon.Types.SimpleEnum'First'", typeof(ODataException))]
|
||||
[InlineData("Id has Microsoft.TestCommon.Types.SimpleEnum'First'", typeof(ODataException))]
|
||||
[InlineData("null has null", typeof(NotSupportedException))]
|
||||
[InlineData("Simple has 23", typeof(ODataException))]
|
||||
[InlineData("'Some string' has 0", typeof(ODataException))]
|
||||
public void ApplyToEnums_Throws_WithInvalidFilter(string filter, Type exceptionType)
|
||||
{
|
||||
// Arrange
|
||||
var model = GetEnumModel();
|
||||
var context = new ODataQueryContext(model, typeof(EnumModel));
|
||||
var filterOption = new FilterQueryOption(filter, context);
|
||||
IEnumerable<EnumModel> enumModels = EnumModelTestData;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws(
|
||||
exceptionType,
|
||||
() => filterOption.ApplyTo(
|
||||
enumModels.AsQueryable(),
|
||||
new ODataQuerySettings { HandleNullPropagation = HandleNullPropagationOption.True }));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(
|
||||
"Simple eq Microsoft.TestCommon.Types.SimpleEnum'4'",
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using Microsoft.OData.Core;
|
||||
|
||||
namespace System.Web.Http.OData.Query
|
||||
|
@ -192,6 +193,7 @@ namespace System.Web.Http.OData.Query
|
|||
public byte[] Image { get; set; }
|
||||
public DateTimeOffset Birthday { get; set; }
|
||||
public double AmountSpent { get; set; }
|
||||
public Color FavoriteColor { get; set; }
|
||||
|
||||
|
||||
public QueryCompositionAddress NavigationWithNonFilterableProperty { get; set; }
|
||||
|
|
|
@ -108,6 +108,19 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
"Arithmetic operator 'Modulo' is not allowed. To allow it, set the 'AllowedArithmeticOperators' property on QueryableAttribute or QueryValidationSettings.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateThrowsIfHasIsNotAllowed()
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
_validator.Validate(new FilterQueryOption("FavoriteColor has System.Web.Http.OData.Builder.TestModels.Color'Red'", _context),
|
||||
new ODataValidationSettings() { AllowedLogicalOperators = AllowedLogicalOperators.All }));
|
||||
|
||||
Assert.Throws<ODataException>(() =>
|
||||
_validator.Validate(new FilterQueryOption("FavoriteColor has System.Web.Http.OData.Builder.TestModels.Color'Red'", _context),
|
||||
new ODataValidationSettings() { AllowedLogicalOperators = AllowedLogicalOperators.Equal }),
|
||||
"Logical operator 'Has' is not allowed. To allow it, set the 'AllowedLogicalOperators' property on QueryableAttribute or QueryValidationSettings.");
|
||||
}
|
||||
|
||||
// want to test if all the virtual methods are being invoked correctly
|
||||
[Fact]
|
||||
public void ValidateVisitAll()
|
||||
|
@ -318,6 +331,25 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
Assert.Equal(1, _validator.Times["ValidateParameterQueryNode"]); // $it
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateVisitLogicalOperatorHas()
|
||||
{
|
||||
// Arrange
|
||||
FilterQueryOption option = new FilterQueryOption("FavoriteColor has System.Web.Http.OData.Builder.TestModels.Color'Red'", _context);
|
||||
|
||||
// Act
|
||||
_validator.Validate(option, _settings);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(6, _validator.Times.Keys.Count);
|
||||
Assert.Equal(1, _validator.Times["Validate"]); // entry
|
||||
Assert.Equal(1, _validator.Times["ValidateSingleValuePropertyAccessNode"]); // FavouriteColor
|
||||
Assert.Equal(1, _validator.Times["ValidateLogicalOperator"]); // has
|
||||
Assert.Equal(1, _validator.Times["ValidateEnumQueryNode"]); // Red
|
||||
Assert.Equal(1, _validator.Times["ValidateBinaryOperatorQueryNode"]); // has
|
||||
Assert.Equal(1, _validator.Times["ValidateParameterQueryNode"]); // $it
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Id eq 1")]
|
||||
[InlineData("Id ne 1")]
|
||||
|
@ -353,6 +385,7 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
[InlineData("Tags/all(t : t eq '1')")]
|
||||
[InlineData("System.Web.Http.OData.Query.QueryCompositionCustomerBase/Id eq 1")]
|
||||
[InlineData("Contacts/System.Web.Http.OData.Query.QueryCompositionCustomerBase/any()")]
|
||||
[InlineData("FavoriteColor has System.Web.Http.OData.Builder.TestModels.Color'Red'")]
|
||||
public void Validator_Doesnot_Throw_For_ValidQueries(string filter)
|
||||
{
|
||||
// Arrange
|
||||
|
@ -430,6 +463,12 @@ namespace System.Web.Http.OData.Query.Validators
|
|||
base.ValidateConvertNode(convertQueryNode, settings);
|
||||
}
|
||||
|
||||
public override void ValidateEnumNode(EnumNode enumNode, ODataValidationSettings settings)
|
||||
{
|
||||
IncrementCount("ValidateEnumQueryNode");
|
||||
base.ValidateEnumNode(enumNode, settings);
|
||||
}
|
||||
|
||||
public override void ValidateLogicalOperator(BinaryOperatorNode binaryNode, ODataValidationSettings settings)
|
||||
{
|
||||
IncrementCount("ValidateLogicalOperator");
|
||||
|
|
|
@ -97,6 +97,8 @@ namespace System.Web.Http.OData.Routing
|
|||
[InlineData("RoutingCustomers(112)/GetRelatedRoutingCustomers", "~/entityset/key/action")]
|
||||
[InlineData("RoutingCustomers/System.Web.Http.OData.Routing.VIP/GetMostProfitable", "~/entityset/cast/action")]
|
||||
[InlineData("Products(1)/RoutingCustomers/System.Web.Http.OData.Routing.VIP(1)/RelationshipManager/ManagedProducts", "~/entityset/key/navigation/cast/key/navigation/navigation")]
|
||||
[InlineData("EnumCustomers(1)/Color", "~/entityset/key/property")]
|
||||
[InlineData("EnumCustomers(1)/Color/$value", "~/entityset/key/property/$value")]
|
||||
public void Parse_ReturnsPath_WithCorrectTemplate(string odataPath, string template)
|
||||
{
|
||||
ODataPath path = _parser.Parse(_model, odataPath);
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
|
|||
using System.Linq;
|
||||
using System.Web.Http.Dispatcher;
|
||||
using System.Web.Http.OData.Builder;
|
||||
using System.Web.Http.OData.Builder.TestModels;
|
||||
using System.Web.Http.OData.TestCommon;
|
||||
using Microsoft.OData.Edm;
|
||||
|
||||
|
@ -22,6 +23,7 @@ namespace System.Web.Http.OData.Routing
|
|||
builder.EntitySet<SalesPerson>("SalesPeople");
|
||||
builder.EntitySet<EmailAddress>("EmailAddresses");
|
||||
builder.EntitySet<üCategory>("üCategories");
|
||||
builder.EntitySet<EnumCustomer>("EnumCustomers");
|
||||
|
||||
ActionConfiguration getRoutingCustomerById = builder.Action("GetRoutingCustomerById");
|
||||
getRoutingCustomerById.Parameter<int>("RoutingCustomerId");
|
||||
|
@ -172,5 +174,11 @@ namespace System.Web.Http.OData.Routing
|
|||
{
|
||||
public int ID { get; set; }
|
||||
}
|
||||
|
||||
public class EnumCustomer
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public Color Color { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<m:value xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||
<m:element m:type="#System.Web.Http.OData.TestCommon.Models.Person">
|
||||
<Age m:type="Int32" xmlns="http://docs.oasis-open.org/odata/ns/data">20</Age>
|
||||
<Gender xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender" xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<FirstName xmlns="http://docs.oasis-open.org/odata/ns/data">Frank</FirstName>
|
||||
<Alias m:type="#Collection(String)" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<m:element>Alias0</m:element>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<CountryCode m:type="Int32">1</CountryCode>
|
||||
<AreaCode m:type="Int32">425</AreaCode>
|
||||
<Number m:type="Int32">9879089</Number>
|
||||
<PhoneType>HomePhone</PhoneType>
|
||||
<PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</PhoneType>
|
||||
</HomeNumber>
|
||||
<FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<ActivityName>Xbox Gaming</ActivityName>
|
||||
|
@ -25,7 +25,7 @@
|
|||
</m:element>
|
||||
<m:element m:type="#System.Web.Http.OData.TestCommon.Models.Person">
|
||||
<Age m:type="Int32" xmlns="http://docs.oasis-open.org/odata/ns/data">21</Age>
|
||||
<Gender xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender" xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<FirstName xmlns="http://docs.oasis-open.org/odata/ns/data">Steve</FirstName>
|
||||
<Alias m:type="#Collection(String)" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<m:element>Alias1</m:element>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<CountryCode m:type="Int32">1</CountryCode>
|
||||
<AreaCode m:type="Int32">425</AreaCode>
|
||||
<Number m:type="Int32">9879090</Number>
|
||||
<PhoneType>HomePhone</PhoneType>
|
||||
<PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</PhoneType>
|
||||
</HomeNumber>
|
||||
<FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<ActivityName>Xbox Gaming</ActivityName>
|
||||
|
@ -48,7 +48,7 @@
|
|||
</m:element>
|
||||
<m:element m:type="#System.Web.Http.OData.TestCommon.Models.Person">
|
||||
<Age m:type="Int32" xmlns="http://docs.oasis-open.org/odata/ns/data">22</Age>
|
||||
<Gender xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender" xmlns="http://docs.oasis-open.org/odata/ns/data">Male</Gender>
|
||||
<FirstName xmlns="http://docs.oasis-open.org/odata/ns/data">Tom</FirstName>
|
||||
<Alias m:type="#Collection(String)" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<m:element>Alias2</m:element>
|
||||
|
@ -63,7 +63,7 @@
|
|||
<CountryCode m:type="Int32">1</CountryCode>
|
||||
<AreaCode m:type="Int32">425</AreaCode>
|
||||
<Number m:type="Int32">9879091</Number>
|
||||
<PhoneType>HomePhone</PhoneType>
|
||||
<PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</PhoneType>
|
||||
</HomeNumber>
|
||||
<FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity" xmlns="http://docs.oasis-open.org/odata/ns/data">
|
||||
<ActivityName>Xbox Gaming</ActivityName>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<m:properties>
|
||||
<d:EmployeeId m:type="Int64">0</d:EmployeeId>
|
||||
<d:Age m:type="Int32">20</d:Age>
|
||||
<d:Gender>Male</d:Gender>
|
||||
<d:Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender">Male</d:Gender>
|
||||
<d:FirstName>Frank</d:FirstName>
|
||||
<d:Alias m:type="#Collection(String)">
|
||||
<m:element>Alias0</m:element>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<d:CountryCode m:type="Int32">1</d:CountryCode>
|
||||
<d:AreaCode m:type="Int32">425</d:AreaCode>
|
||||
<d:Number m:type="Int32">9879089</d:Number>
|
||||
<d:PhoneType>HomePhone</d:PhoneType>
|
||||
<d:PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</d:PhoneType>
|
||||
</d:HomeNumber>
|
||||
<d:FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity">
|
||||
<d:ActivityName>Xbox Gaming</d:ActivityName>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<m:value xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost/#System.Web.Http.OData.EnumComplex" m:type="#System.Web.Http.OData.EnumComplex" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||
<d:RequiredColor>Red, Blue</d:RequiredColor>
|
||||
<d:RequiredColor m:type="#System.Web.Http.OData.Builder.TestModels.Color">Red, Blue</d:RequiredColor>
|
||||
<d:NullableColor m:null="true" />
|
||||
<d:UndefinedColor>123</d:UndefinedColor>
|
||||
<d:UndefinedColor m:type="#System.Web.Http.OData.Builder.TestModels.Color">123</d:UndefinedColor>
|
||||
</m:value>
|
|
@ -21,7 +21,7 @@
|
|||
<m:properties>
|
||||
<d:EmployeeId m:type="Int64">0</d:EmployeeId>
|
||||
<d:Age m:type="Int32">20</d:Age>
|
||||
<d:Gender>Male</d:Gender>
|
||||
<d:Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender">Male</d:Gender>
|
||||
<d:FirstName>Frank</d:FirstName>
|
||||
<d:Alias m:type="#Collection(String)">
|
||||
<m:element>Alias0</m:element>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<d:CountryCode m:type="Int32">1</d:CountryCode>
|
||||
<d:AreaCode m:type="Int32">425</d:AreaCode>
|
||||
<d:Number m:type="Int32">9879089</d:Number>
|
||||
<d:PhoneType>HomePhone</d:PhoneType>
|
||||
<d:PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</d:PhoneType>
|
||||
</d:HomeNumber>
|
||||
<d:FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity">
|
||||
<d:ActivityName>Xbox Gaming</d:ActivityName>
|
||||
|
@ -61,7 +61,7 @@
|
|||
<m:properties>
|
||||
<d:EmployeeId m:type="Int64">1</d:EmployeeId>
|
||||
<d:Age m:type="Int32">21</d:Age>
|
||||
<d:Gender>Male</d:Gender>
|
||||
<d:Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender">Male</d:Gender>
|
||||
<d:FirstName>Steve</d:FirstName>
|
||||
<d:Alias m:type="#Collection(String)">
|
||||
<m:element>Alias1</m:element>
|
||||
|
@ -76,7 +76,7 @@
|
|||
<d:CountryCode m:type="Int32">1</d:CountryCode>
|
||||
<d:AreaCode m:type="Int32">425</d:AreaCode>
|
||||
<d:Number m:type="Int32">9879090</d:Number>
|
||||
<d:PhoneType>HomePhone</d:PhoneType>
|
||||
<d:PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</d:PhoneType>
|
||||
</d:HomeNumber>
|
||||
<d:FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity">
|
||||
<d:ActivityName>Xbox Gaming</d:ActivityName>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<m:value xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost/#System.Web.Http.OData.TestCommon.Models.Person" m:type="#System.Web.Http.OData.TestCommon.Models.Person" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||
<d:Age m:type="Int32">20</d:Age>
|
||||
<d:Gender>Male</d:Gender>
|
||||
<d:Gender m:type="#System.Web.Http.OData.TestCommon.Models.Gender">Male</d:Gender>
|
||||
<d:FirstName>Frank</d:FirstName>
|
||||
<d:Alias m:type="#Collection(String)">
|
||||
<m:element>Alias0</m:element>
|
||||
|
@ -16,7 +16,7 @@
|
|||
<d:CountryCode m:type="Int32">1</d:CountryCode>
|
||||
<d:AreaCode m:type="Int32">425</d:AreaCode>
|
||||
<d:Number m:type="Int32">9879089</d:Number>
|
||||
<d:PhoneType>HomePhone</d:PhoneType>
|
||||
<d:PhoneType m:type="#System.Web.Http.OData.TestCommon.Models.PhoneType">HomePhone</d:PhoneType>
|
||||
</d:HomeNumber>
|
||||
<d:FavoriteHobby m:type="#System.Web.Http.OData.TestCommon.Models.IActivity">
|
||||
<d:ActivityName>Xbox Gaming</d:ActivityName>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<d:Age m:type="Int32">10</d:Age>
|
||||
<d:MyGuid m:type="Guid">f99080c0-2f9e-472e-8c72-1a8ecd9f902d</d:MyGuid>
|
||||
<d:Name>Asha</d:Name>
|
||||
<d:FavoriteColor m:type="#System.Web.Http.OData.Builder.TestModels.Color">Red, Green</d:FavoriteColor>
|
||||
<d:Order m:type="#System.Web.Http.OData.Formatter.FormatterOrder">
|
||||
<d:OrderAmount m:type="Int32">235342</d:OrderAmount>
|
||||
<d:OrderName>FirstOrder</d:OrderName>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","Order":{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","FavoriteColor":"Red, Green","Order":{
|
||||
"OrderAmount":235342,"OrderName":"FirstOrder"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.type":"#System.Web.Http.OData.Formatter.FormatterPerson","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid@odata.type":"Edm.Guid","MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","Order":{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.type":"#System.Web.Http.OData.Formatter.FormatterPerson","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid@odata.type":"Edm.Guid","MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","FavoriteColor@odata.type":"#System.Web.Http.OData.Builder.TestModels.Color","FavoriteColor":"Red, Green","Order":{
|
||||
"@odata.type":"#System.Web.Http.OData.Formatter.FormatterOrder","OrderAmount":235342,"OrderName":"FirstOrder"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","Order":{
|
||||
"@odata.context":"http://localhost:8081/$metadata#People/$entity","@odata.id":"http://localhost:8081/People(10)","PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","FavoriteColor":"Red, Green","Order":{
|
||||
"OrderAmount":235342,"OrderName":"FirstOrder"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","Order":{
|
||||
"PerId":10,"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","FavoriteColor":"Red, Green","Order":{
|
||||
"OrderAmount":235342,"OrderName":"FirstOrder"
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","Order":{"OrderAmount":235342,"OrderName":"FirstOrder"},"PerId":10}
|
||||
{"Age":10,"MyGuid":"f99080c0-2f9e-472e-8c72-1a8ecd9f902d","Name":"Asha","FavoriteColor":3,"Order":{"OrderAmount":235342,"OrderName":"FirstOrder"},"PerId":10}
|
|
@ -115,6 +115,7 @@
|
|||
<Compile Include="OData\Formatter\ODataRawValueMediaTypeMappingTests.cs" />
|
||||
<Compile Include="OData\Formatter\ODataValueExtensionsTest.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataEntityReferenceLinksSerializerTest.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataEnumTypeSerializerTests.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataRawValueSerializerTests.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataSerializerContextTest.cs" />
|
||||
<Compile Include="OData\Formatter\Serialization\ODataWorkspaceSerializerTest.cs" />
|
||||
|
@ -354,7 +355,7 @@
|
|||
<EmbeddedResource Include="Resources\DecimalInJsonFullMetadata.json" />
|
||||
<EmbeddedResource Include="Resources\DoubleInJsonFullMetadata.json" />
|
||||
<EmbeddedResource Include="Resources\EmployeeEntryInJsonLight.json" />
|
||||
<EmbeddedResource Include="Resources\EnumComplexTypeInJsonLight.json" />
|
||||
<EmbeddedResource Include="Resources\EnumComplexTypeInJsonLight.json" />
|
||||
<EmbeddedResource Include="Resources\FeedOfEmployeeInJsonLight.json" />
|
||||
<EmbeddedResource Include="Resources\GuidInJsonFullMetadata.json" />
|
||||
<EmbeddedResource Include="Resources\Int16InJsonFullMetadata.json" />
|
||||
|
|
|
@ -51,6 +51,33 @@ namespace System.Web.Http.OData
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static ODataModelBuilder Add_ByteEnum_EnumType(this ODataModelBuilder builder)
|
||||
{
|
||||
EnumTypeConfiguration<ByteEnum> byteEnum = builder.EnumType<ByteEnum>();
|
||||
byteEnum.Member(ByteEnum.FirstByte);
|
||||
byteEnum.Member(ByteEnum.SecondByte);
|
||||
byteEnum.Member(ByteEnum.ThirdByte);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static ODataModelBuilder Add_SByteEnum_EnumType(this ODataModelBuilder builder)
|
||||
{
|
||||
EnumTypeConfiguration<SByteEnum> sByteEnum = builder.EnumType<SByteEnum>();
|
||||
sByteEnum.Member(SByteEnum.FirstSByte);
|
||||
sByteEnum.Member(SByteEnum.SecondSByte);
|
||||
sByteEnum.Member(SByteEnum.ThirdSByte);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static ODataModelBuilder Add_ShortEnum_EnumType(this ODataModelBuilder builder)
|
||||
{
|
||||
EnumTypeConfiguration<ShortEnum> shortEnum = builder.EnumType<ShortEnum>();
|
||||
shortEnum.Member(ShortEnum.FirstShort);
|
||||
shortEnum.Member(ShortEnum.SecondShort);
|
||||
shortEnum.Member(ShortEnum.ThirdShort);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static ODataModelBuilder Add_Address_ComplexType(this ODataModelBuilder builder)
|
||||
{
|
||||
var address = builder.ComplexType<Address>();
|
||||
|
|
Загрузка…
Ссылка в новой задаче