public void HasODataKeyParameter_ThrowsArgumentNull_EntityType() { // Arrange & Act & Assert ActionModel action = new ActionModel(_methodInfo, new List <object>()); ExceptionAssert.ThrowsArgumentNull(() => action.HasODataKeyParameter(entityType: null), "entityType"); }
public void HasODataKeyParameter_ThrowsArgumentNull_Action() { // Arrange & Act & Assert ActionModel action = null; ExceptionAssert.ThrowsArgumentNull(() => action.HasODataKeyParameter(entityType: null), "action"); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } ActionModel action = context.Action; IEdmEntitySet entitySet = context.EntitySet; IEdmEntityType entityType = entitySet.EntityType(); // if the action has key parameter, skip it. if (action.HasODataKeyParameter(entityType, context.Options?.RouteOptions?.EnablePropertyNameCaseInsensitive ?? false)) { return(false); } string actionName = action.ActionName; // 1. Without type case if (ProcessEntitySetAction(actionName, entitySet, null, context, action)) { return(true); } // 2. process the derived type (cast) by searching all derived types // GetFrom{EntityTypeName} or Get{EntitySet}From{EntityTypeName} int index = actionName.IndexOf("From", StringComparison.Ordinal); if (index == -1) { return(false); } string castTypeName = actionName.Substring(index + 4); // + 4 means to skip the "From" if (castTypeName.Length == 0) { // Early return for the following cases: // - Get|Post|PatchFrom // - Get|Patch{EntitySet}From // - Post{EntityType}From return(false); } IEdmStructuredType castType = entityType.FindTypeInInheritance(context.Model, castTypeName); if (castType == null) { return(false); } string actionPrefix = actionName.Substring(0, index); return(ProcessEntitySetAction(actionPrefix, entitySet, castType, context, action)); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } ActionModel action = context.Action; IEdmEntitySet entitySet = context.EntitySet; IEdmEntityType entityType = entitySet.EntityType(); // if the action has key parameter, skip it. if (action.HasODataKeyParameter(entityType)) { return(false); } string actionName = action.ActionMethod.Name; // 1. Without type case if (ProcessEntitySetAction(actionName, entitySet, null, context, action)) { return(true); } // 2. process the derive type (cast) by searching all derived types // GetFrom{EntityTypeName} or Get{EntitySet}From{EntityTypeName} int index = actionName.IndexOf("From", StringComparison.Ordinal); if (index == -1) { return(false); } string castTypeName = actionName.Substring(index + 4); // + 4 means to skip the "From" IEdmStructuredType castType = entityType.FindTypeInInheritance(context.Model, castTypeName); if (castType == null) { return(false); } string actionPrefix = actionName.Substring(0, index); return(ProcessEntitySetAction(actionPrefix, entitySet, castType, context, action)); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } ActionModel action = context.Action; IEdmEntitySet entitySet = context.EntitySet; IEdmEntityType entityType = entitySet.EntityType(); // if the action has no key parameter, skip it. if (!action.HasODataKeyParameter(entityType)) { return(false); } string actionName = action.ActionMethod.Name; // We care about the action in this pattern: {HttpMethod}{EntityTypeName} (string httpMethod, string castTypeName) = Split(actionName); if (httpMethod == null) { return(false); } IEdmStructuredType castType = null; if (castTypeName != null) { castType = entityType.FindTypeInInheritance(context.Model, castTypeName); if (castType == null) { return(false); } } AddSelector(entitySet, entityType, castType, context.Prefix, context.Model, action, httpMethod); return(true); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } if (context.EntitySet == null && context.Singleton == null) { return(false); } ActionModel action = context.Action; // Filter by the action name. // The action for navigation property request should follow up {httpMethod}{PropertyName}[From{Declaring}] string actionName = action.ActionMethod.Name; string method = SplitActionName(actionName, out string property, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // eitherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } // Find the property, and we only care about the navigation property. IEdmProperty edmProperty = declaringEntityType.FindProperty(property); if (edmProperty == null || edmProperty.PropertyKind == EdmPropertyKind.Structural) { return(false); } // Starts the routing template //IList<ODataSegmentTemplate> segments = new List<ODataSegmentTemplate>(); //if (context.EntitySet != null) //{ // segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); //} //else //{ // segments.Add(new SingletonSegmentTemplate(context.Singleton)); //} //if (hasKeyParameter) //{ // segments.Add(new KeySegmentTemplate(entityType)); //} //if (declared != null) //{ // // It should be always single type // segments.Add(new CastSegmentTemplate(declaringEntityType, entityType, navigationSource)); //} IEdmNavigationProperty navigationProperty = (IEdmNavigationProperty)edmProperty; //IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); //segments.Add(new NavigationSegmentTemplate(navigationProperty, targetNavigationSource)); //ODataPathTemplate template = new ODataPathTemplate(segments); //action.AddSelector(method, context.Prefix, context.Model, template); AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, false); if (CanApplyDollarCount(navigationProperty, method)) { AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, true); } return(true); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } if (context.EntitySet == null && context.Singleton == null) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; ActionModel action = context.Action; string actionName = action.ActionMethod.Name; string method = SplitActionName(actionName, out string property, out string cast, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // eitherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } IEdmProperty edmProperty = declaringEntityType.FindProperty(property); if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural) { return(false); } if (!CanApply(edmProperty, method)) { return(false); } IEdmComplexType castType = null; if (cast != null) { IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType(); if (propertyElementType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complexType = (IEdmComplexType)propertyElementType; castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType; if (castType == null) { return(false); } } else { // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast) return(false); } } // only process structural property IEdmStructuredType castComplexType = null; if (cast != null) { IEdmTypeReference propertyType = edmProperty.Type; if (propertyType.IsCollection()) { propertyType = propertyType.AsCollection().ElementType(); } if (!propertyType.IsComplex()) { return(false); } castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast); if (castComplexType == null) { return(false); } } AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false); if (CanApplyDollarCount(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true); } if (CanApplyDollarValue(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false); } return(true); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } IEdmNavigationSource navigationSource = context.NavigationSource; if (navigationSource == null) { return(false); } ActionModel action = context.Action; string actionName = action.ActionName; string method = SplitActionName(actionName, out string property, out string cast, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType, context.Options?.RouteOptions?.EnablePropertyNameCaseInsensitive ?? false); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // otherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { if (declared.Length == 0) { // Early return for the following cases: // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}From // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of{Cast}From return(false); } declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } bool enablePropertyNameCaseInsensitive = context?.Options?.RouteOptions.EnablePropertyNameCaseInsensitive ?? false; IEdmProperty edmProperty = declaringEntityType.FindProperty(property, enablePropertyNameCaseInsensitive); if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural) { return(false); } if (!CanApply(edmProperty, method)) { return(false); } IEdmComplexType castType; // Only process structural property IEdmStructuredType castComplexType = null; if (cast != null) { if (cast.Length == 0) { // Avoid unnecessary call to FindTypeInheritance // Cases handled: Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of return(false); } IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType(); if (propertyElementType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complexType = (IEdmComplexType)propertyElementType; castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType; if (castType == null) { return(false); } } else { // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast) return(false); } IEdmTypeReference propertyType = edmProperty.Type; if (propertyType.IsCollection()) { propertyType = propertyType.AsCollection().ElementType(); } if (!propertyType.IsComplex()) { return(false); } castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast); if (castComplexType == null) { return(false); } } AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false); if (CanApplyDollarCount(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true); } if (CanApplyDollarValue(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false); } return(true); }
/// <inheritdoc /> public bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } Debug.Assert(context.Action != null); ActionModel action = context.Action; string actionMethodName = action.ActionMethod.Name; // Need to refactor the following // for example: CreateRef( with the navigation property parameter) should for all navigation properties // CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef. string method = SplitRefActionName(actionMethodName, out string httpMethod, out string property, out string declaring); if (method == null) { return(false); } // Action parameter should have a (string navigationProperty) parameter if (!action.HasParameter <string>("navigationProperty")) { return(false); } IEdmNavigationSource navigationSource; IEdmEntityType entityType; if (context.EntitySet != null) { entityType = context.EntitySet.EntityType(); navigationSource = context.EntitySet; } else { entityType = context.Singleton.EntityType(); navigationSource = context.Singleton; } // For entity set, we should have the key parameter // For Singleton, we should not have the key parameter bool hasODataKeyParameter = action.HasODataKeyParameter(entityType); if ((context.EntitySet != null && !hasODataKeyParameter) || (context.Singleton != null && hasODataKeyParameter)) { return(false); } // Find the navigation property declaring type IEdmStructuredType declaringType = entityType; if (declaring != null) { declaringType = entityType.FindTypeInInheritance(context.Model, declaring); if (declaringType == null) { return(false); } } // Find the navigation property if have IEdmNavigationProperty navigationProperty = null; if (property != null) { navigationProperty = declaringType.DeclaredNavigationProperties().FirstOrDefault(p => p.Name == property); if (navigationProperty == null) { return(false); } } IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); segments.Add(new KeySegmentTemplate(entityType)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (entityType != declaringType) { segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource)); } if (navigationProperty != null) { segments.Add(new NavigationSegmentTemplate(navigationProperty)); } else { //TODO: Add the navigation template segment template, // Or add the template for all navigation properties? return(false); } IEdmEntityType navigationPropertyType = navigationProperty.Type.GetElementTypeOrSelf().AsEntity().EntityDefinition(); bool hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedKey"); if (hasNavigationPropertyKeyParameter) { segments.Add(new KeySegmentTemplate(navigationPropertyType, "relatedKey")); } IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); segments.Add(new RefSegmentTemplate(navigationProperty, targetNavigationSource)); // TODO: support key as segment? ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod, context.Prefix, context.Model, template); // processed return(true); }
/// <inheritdoc /> public bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } Debug.Assert(context.Action != null); ActionModel action = context.Action; string actionMethodName = action.ActionName; // Need to refactor the following // for example: CreateRef( with the navigation property parameter) should for all navigation properties // CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef. string method = SplitRefActionName(actionMethodName, out string httpMethod, out string property, out string declaring); if (method == null) { return(false); } IEdmNavigationSource navigationSource = context.NavigationSource; IEdmEntityType entityType = context.EntityType; // For entity set, we should have the key parameter // For Singleton, we should not have the key parameter bool hasODataKeyParameter = action.HasODataKeyParameter(entityType); if ((context.EntitySet != null && !hasODataKeyParameter) || (context.Singleton != null && hasODataKeyParameter)) { return(false); } // Find the navigation property declaring type IEdmStructuredType declaringType = entityType; if (declaring != null) { declaringType = entityType.FindTypeInInheritance(context.Model, declaring); if (declaringType == null) { return(false); } } // Process the generic scenario if (property == null) { return(ProcessNonNavigationProperty(httpMethod, context, action, navigationSource, entityType, declaringType)); } // Find the navigation property if have IEdmNavigationProperty navigationProperty = null; if (property != null) { navigationProperty = declaringType.DeclaredNavigationProperties().FirstOrDefault(p => p.Name == property); } if (navigationProperty == null) { return(false); } IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (entityType != declaringType) { segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource)); } IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); NavigationLinkSegmentTemplate linkTemplate = new NavigationLinkSegmentTemplate(navigationProperty, targetNavigationSource); IEdmEntityType navigationPropertyType = navigationProperty.Type.GetElementTypeOrSelf().AsEntity().EntityDefinition(); bool hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedKey"); if (hasNavigationPropertyKeyParameter) { linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedKey"); } else { hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedId"); if (hasNavigationPropertyKeyParameter) { linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedId"); } } segments.Add(linkTemplate); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions); // processed return(true); }