public MaximoResult Execute(ApplicationMetadata application, JObject json, string id, string operation) { var entityMetadata = MetadataProvider.Entity(application.Entity); var operationWrapper = new OperationWrapper(application, entityMetadata, operation, json, id); return(_maximoConnectorEngine.Execute(operationWrapper)); }
public OperationSerializerTests() { ResourceType intType = ResourceType.GetPrimitiveResourceType(typeof(int)); var customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "FQ.NS", "Customer", false); customerType.CanReflectOnInstanceType = false; customerType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, intType) { CanReflectOnInstanceTypeProperty = false }); customerType.SetReadOnly(); var operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", intType) }, null); operation.SetReadOnly(); this.baseTypeOperation = new OperationWrapper(operation); var bestCustomerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, customerType, "FQ.NS", "BestCustomer", false); bestCustomerType.SetReadOnly(); operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", bestCustomerType) }, null); operation.SetReadOnly(); this.derivedTypeOperation = new OperationWrapper(operation); operation = new ServiceAction("Unambiguous", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType) }, null); operation.SetReadOnly(); this.unambiguousOperation = new OperationWrapper(operation); this.entityToSerialize = EntityToSerialize.CreateFromExplicitValues(new object(), bestCustomerType, new TestSerializedEntityKey("http://odata.org/Service.svc/Customers(0)/", bestCustomerType.FullName)); this.testSubject = CreateOperationSerializer(AlwaysAdvertiseActions); }
/// <summary> /// Creates a segment for a service operation /// </summary> /// <param name="serviceOperation">The service operation for the segment.</param> /// <returns>A fully populated PathSegment representing the service operation</returns> private static SegmentInfo CreateSegmentForServiceOperation(OperationWrapper serviceOperation) { Debug.Assert(serviceOperation != null, "serviceOperation != null"); WebUtil.DebugEnumIsDefined(serviceOperation.ResultKind); SegmentInfo segment = new SegmentInfo { Identifier = serviceOperation.Name, Operation = serviceOperation, TargetSource = RequestTargetSource.ServiceOperation, TargetResourceSet = serviceOperation.ResourceSet }; if (serviceOperation.ResultKind != ServiceOperationResultKind.Void) { segment.TargetResourceType = serviceOperation.ResultType; segment.TargetKind = TargetKindFromType(segment.TargetResourceType); // this service operation returns results // we should check service operation rights // SingleResult operations are service operations defined with [SingleResult] attribute, returns a DirectValue // or a service operation returning multiple results, but contains key predicates in the query portion. // For these operations, you MUST have ReadSingle defined // For multiple-result-operations(IQueryable/IEnumerable), you MUST have ReadMultiple defined. segment.SingleResult = (serviceOperation.ResultKind == ServiceOperationResultKind.QueryWithSingleResult || serviceOperation.ResultKind == ServiceOperationResultKind.DirectValue); } else { segment.TargetResourceType = null; segment.TargetKind = RequestTargetKind.VoidOperation; } return(segment); }
private static bool AlwaysAdvertiseActions(OperationWrapper serviceAction, object resourceInstance, bool resourceInstanceInFeed, ref ODataAction actionToSerialize) { // the links should always be provided and always be absolute, even if they will be written relative in JSON-Light. actionToSerialize.Metadata.Should().NotBeNull().And.Subject.As <Uri>().IsAbsoluteUri.Should().BeTrue(); actionToSerialize.Target.Should().NotBeNull().And.Subject.As <Uri>().IsAbsoluteUri.Should().BeTrue(); return(true); }
/// <summary> /// Gets the IEdmOperationI for a specified <paramref name="serviceOperation"/>. /// </summary> /// <param name="serviceOperation">The service action or function to get the function import for.</param> /// <returns>The function import.</returns> protected IEdmOperation GetOperation(OperationWrapper serviceOperation) { var model = this.Service.Provider.GetMetadataProviderEdmModel(); model.EnsureDefaultEntityContainer().EnsureOperationImport(serviceOperation); return(model.GetRelatedOperation(serviceOperation)); }
internal static void CheckServiceOperationRights(OperationWrapper operation, bool singleResult) { if (operation.ResultKind != ServiceOperationResultKind.Void) { ServiceOperationRights requiredRights = singleResult ? ServiceOperationRights.ReadSingle : ServiceOperationRights.ReadMultiple; CheckServiceOperationRights(operation, requiredRights); } }
internal static void CheckServiceOperationRights(OperationWrapper operation, ServiceOperationRights requiredRights) { ServiceOperationRights serviceOperationRights = operation.ServiceOperationRights; if ((requiredRights & serviceOperationRights) == ServiceOperationRights.None) { throw DataServiceException.CreateForbidden(); } }
/// <summary> /// Determines if the previous segment can be composed upon. /// </summary> /// <param name="previous">previous segment info.</param> /// <returns> /// <c>true</c> if the segment can be composed upon; otherwise, <c>false</c>. /// </returns> private static bool IsSegmentComposable(SegmentInfo previous) { OperationWrapper op = previous.Operation; return(op == null || (op.ResultKind != ServiceOperationResultKind.Enumeration && op.ResultKind != ServiceOperationResultKind.DirectValue && (op.ResultKind != ServiceOperationResultKind.QueryWithSingleResult || op.ResultType.ResourceTypeKind == ResourceTypeKind.EntityType))); }
/// <summary>Checks whether this request has the specified rights.</summary> /// <param name="operation">Operation to check.</param> /// <param name="requiredRights">Required rights.</param> /// <exception cref="DataServiceException">Thrown if <paramref name="requiredRights"/> aren't available.</exception> internal static void CheckServiceOperationRights(OperationWrapper operation, ServiceOperationRights requiredRights) { Debug.Assert(operation != null, "operation != null"); Debug.Assert(requiredRights != ServiceOperationRights.None, "requiredRights != EntitySetRights.None"); ServiceOperationRights effectiveRights = operation.ServiceOperationRights; if ((requiredRights & effectiveRights) == 0) { throw DataServiceException.CreateForbidden(); } }
/// <summary>Writes multiple top-level elements, possibly none.</summary> /// <param name="expanded">Expanded results for elements.</param> /// <param name="elements">Enumerator for elements to write.</param> protected override void WriteTopLevelElements(IExpandedResult expanded, QueryResultInfo elements) { Debug.Assert( !this.RequestDescription.IsSingleResult, "!this.RequestDescription.IsSingleResult -- otherwise WriteTopLevelElement should have been called"); if (this.RequestDescription.LinkUri) { bool needPop = this.PushSegmentForRoot(); this.WriteLinkCollection(elements); this.PopSegmentName(needPop); } else { MetadataProviderEdmModel model = this.Service.Provider.GetMetadataProviderEdmModel(); OperationWrapper operation = this.RequestDescription.LastSegmentInfo.Operation; IEdmOperation edmOperation = model.GetRelatedOperation(operation); Debug.Assert(edmOperation != null, "edmOperation != null"); IEdmCollectionTypeReference collectionType = (IEdmCollectionTypeReference)edmOperation.ReturnType; bool isJsonLightResponse = ContentTypeUtil.IsResponseMediaTypeJsonLight(this.Service, /*isEntryOrFeed*/ false); this.collectionWriter = this.writer.CreateODataCollectionWriter(isJsonLightResponse ? null : collectionType.ElementType()); ODataCollectionStart collectionStart = new ODataCollectionStart { Name = this.ComputeContainerName() }; collectionStart.SetSerializationInfo(new ODataCollectionStartSerializationInfo { CollectionTypeName = collectionType.FullName() }); this.collectionWriter.WriteStart(collectionStart); while (elements.HasMoved) { object element = elements.Current; ResourceType resourceType = element == null ? this.RequestDescription.TargetResourceType : WebUtil.GetResourceType(this.Provider, element); if (resourceType == null) { throw new InvalidOperationException(Microsoft.OData.Service.Strings.Serializer_UnsupportedTopLevelType(element.GetType())); } this.collectionWriter.WriteItem(this.GetPropertyValue(XmlConstants.XmlCollectionItemElementName, resourceType, element, false /*openProperty*/).FromODataValue()); elements.MoveNext(); } this.collectionWriter.WriteEnd(); this.collectionWriter.Flush(); } }
internal Uri BuildMetadataLink(OperationWrapper operation, bool entityHasMultipleActionsWithSameName) { Debug.Assert(!String.IsNullOrEmpty(operation.Name), "!string.IsNullOrEmpty(operation.Name)"); StringBuilder builder = new StringBuilder(); builder.Append(UriUtil.UriToString(this.metadataUri)); builder.Append('#'); builder.Append(Uri.EscapeDataString(namespaceName)); builder.Append('.'); builder.Append(Uri.EscapeDataString(operation.Name)); return(new Uri(builder.ToString())); }
public OperationLinkBuilderTests() { ResourceType intType = ResourceType.GetPrimitiveResourceType(typeof(int)); var customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "FQ.NS", "Customer", false); customerType.CanReflectOnInstanceType = false; customerType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, intType) { CanReflectOnInstanceTypeProperty = false }); customerType.SetReadOnly(); var operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", intType) }, null); operation.SetReadOnly(); this.operationWithParameters = new OperationWrapper(operation); var typeWithEscapedName = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "FQ NS", "+ /", false); typeWithEscapedName.CanReflectOnInstanceType = false; typeWithEscapedName.AddProperty(new ResourceProperty("Number", ResourcePropertyKind.Primitive, intType) { CanReflectOnInstanceTypeProperty = false }); typeWithEscapedName.SetReadOnly(); operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", typeWithEscapedName) }, null); operation.SetReadOnly(); this.operationWithEscapedParameter = new OperationWrapper(operation); var bestCustomerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, customerType, "FQ.NS", "BestCustomer", false); bestCustomerType.SetReadOnly(); operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType) }, null); operation.SetReadOnly(); this.operationBoundToBaseType = new OperationWrapper(operation); this.entityToSerialize = EntityToSerialize.CreateFromExplicitValues(new object(), bestCustomerType, new TestSerializedEntityKey("http://odata.org/Service.svc/Customers/", bestCustomerType.FullName)); var metadataUri = new Uri("http://odata.org/Service.svc/$metadata"); this.testSubject = new OperationLinkBuilder("MyContainer", metadataUri); }
public OperationCacheTests() { this.entityType1 = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "My.Namespace", "Entity1", false); this.entityType2 = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "My.Namespace", "Entity2", false); var intType = ResourceType.GetPrimitiveResourceType(typeof(int)); this.actionWithBindingParameter1 = CreateAction("SameName", intType, this.entityType1); this.actionWithBindingParameter2 = CreateAction("SameName", intType, this.entityType2); this.serviceOperation = CreateServiceOperation("SameName", intType); this.actionWithBindingParameter1.SetReadOnly(); this.actionWithBindingParameter2.SetReadOnly(); this.serviceOperation.SetReadOnly(); this.actionWithBindingParameterWrapper1 = new OperationWrapper(this.actionWithBindingParameter1); this.actionWithBindingParameterWrapper2 = new OperationWrapper(this.actionWithBindingParameter2); this.serviceOperationWrapper = new OperationWrapper(this.serviceOperation); }
/// <summary> /// Gets the target link value for an <see cref="ODataOperation"/> /// </summary> /// <param name="entityToSerialize">The current entity being serialized.</param> /// <param name="operation">The operation to generate the link for.</param> /// <param name="entityHasMultipleActionsWithSameName">Whether or not there are multiple operations in the current scope with the same name as the current operation.</param> /// <returns>Uri representing link to use for invoking this operation.</returns> internal Uri BuildTargetLink(EntityToSerialize entityToSerialize, OperationWrapper operation, bool entityHasMultipleActionsWithSameName) { Debug.Assert(entityToSerialize != null, "entityToSerialize != null"); Debug.Assert(operation != null, "operation != null"); Debug.Assert(operation.BindingParameter != null, "operation.BindingParameter != null"); Debug.Assert(operation.BindingParameter.ParameterType != null, "operation.BindingParameter.ParameterType != null"); string targetSegment = operation.GetActionTargetSegmentByResourceType(entityToSerialize.ResourceType, this.namespaceName); // If there are multiple operations with the same name, then using the edit link of the entry would cause the target to potentially resolve to the wrong // operation. Instead, use the actual binding type of the specific operation. if (entityHasMultipleActionsWithSameName) { Uri editLinkWithBindingType = RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.AbsoluteEditLinkWithoutSuffix, operation.BindingParameter.ParameterType.FullName); return(RequestUriProcessor.AppendUnescapedSegment(editLinkWithBindingType, targetSegment)); } return(RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.AbsoluteEditLink, targetSegment)); }
public MaximoResult InvokeCustomOperation(OperationWrapper operationWrapper) { var operationName = operationWrapper.OperationName; var entityMetadata = operationWrapper.EntityMetadata; try { var mi = ReflectionUtil.GetMethodNamed(_connectorTemplate, operationName); if (mi == null) { throw new InvalidOperationException(String.Format("operation {0} not found on entity {1}", operationName, entityMetadata.Name)); } if (mi.GetParameters().Count() != 1) { throw new InvalidOperationException( String.Format(ErrorParameter, operationName, entityMetadata.Name)); } var fp = mi.GetParameters().First(); if (!typeof(OperationData).IsAssignableFrom(fp.ParameterType)) { throw new InvalidOperationException( String.Format(ErrorParameter, operationName, entityMetadata.Name)); } var param = operationWrapper.OperationData(fp.ParameterType); if (mi.ReturnType == typeof(void)) { mi.Invoke(_connectorTemplate, new object[] { param }); return(null); } var ob = mi.Invoke(_connectorTemplate, new object[] { param }); if (ob is MaximoResult) { return((MaximoResult)ob); } return(new MaximoResult(param.Id, ob)); } catch (AmbiguousMatchException e) { throw new InvalidOperationException( String.Format("multiples methods found for operation {0} on entity {1}. Unable to decide", operationName, entityMetadata.Name)); } }
public void Init() { this.baseType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Fake.NS", "BaseType", false) { CanReflectOnInstanceType = false }; this.baseType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Key | ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(int))) { CanReflectOnInstanceTypeProperty = false }); this.baseType.SetReadOnly(); this.entityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, this.baseType, "Fake.NS", "Type", false) { CanReflectOnInstanceType = false }; this.entityType.SetReadOnly(); this.derivedType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, this.entityType, "Fake.NS", "DerivedType", false) { CanReflectOnInstanceType = false }; this.derivedType.SetReadOnly(); var resourceSet = new ResourceSet("Set", this.entityType); resourceSet.SetReadOnly(); this.resourceSetWrapper = ResourceSetWrapper.CreateForTests(resourceSet); this.action = new ServiceAction("Fake", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("p1", this.entityType) }, null); this.action.SetReadOnly(); this.actionWrapper = new OperationWrapper(action); this.derivedAction = new ServiceAction("Fake", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("p1", this.derivedType) }, null); this.derivedAction.SetReadOnly(); this.derivedActionWrapper = new OperationWrapper(derivedAction); this.testSubject = new SelectedOperationsCache(); }
/// <summary> /// Creates a segment for the given service action. /// </summary> /// <param name="previousSegment">The previous segment before the operation to be invoked.</param> /// <param name="serviceAction">The service action to create the segment for.</param> /// <returns>A fully populated PathSegment representing the service action</returns> private SegmentInfo CreateSegmentForServiceAction(SegmentInfo previousSegment, OperationWrapper serviceAction) { Debug.Assert(serviceAction != null && serviceAction.Kind == OperationKind.Action, "serviceAction != null && serviceAction.Kind == OperationKind.Action"); SegmentInfo segment = new SegmentInfo() { Identifier = serviceAction.Name, Operation = serviceAction }; WebUtil.DebugEnumIsDefined(serviceAction.ResultKind); Debug.Assert(segment.IsServiceActionSegment, "IsServiceActionSegment(segment)"); if (previousSegment != null && previousSegment.TargetKind == RequestTargetKind.Link) { throw DataServiceException.CreateBadRequestError(Strings.RequestUriProcessor_LinkSegmentMustBeFollowedByEntitySegment(serviceAction.Name, XmlConstants.UriLinkSegment)); } segment.TargetSource = RequestTargetSource.ServiceOperation; if (serviceAction.ResultKind != ServiceOperationResultKind.Void) { segment.TargetResourceSet = serviceAction.GetResultSet(this.providerWrapper, previousSegment == null ? null : previousSegment.TargetResourceSet); segment.TargetResourceType = serviceAction.ReturnType; segment.TargetKind = TargetKindFromType(segment.TargetResourceType); if (segment.TargetKind == RequestTargetKind.Resource && segment.TargetResourceSet == null) { // Service actions are either visible (ServiceActionRights.Invoke) or not (ServiceActionRight.None). The fact that // DataServiceActionProviderWrapper.TryResolveServiceAction() returns a non-null value means the action is visible. // If the result of the action is of entity type, we need to make sure the target set is visible or else the self // and edit links of the entities in the response payload would not be usable. Debug.Assert(serviceAction.IsVisible, "serviceAction.IsVisible"); throw DataServiceException.CreateForbidden(); } segment.SingleResult = serviceAction.ResultKind == ServiceOperationResultKind.DirectValue; Debug.Assert(serviceAction.ResultKind != ServiceOperationResultKind.QueryWithSingleResult, "QueryWithSingleResult is not applicable for Actions."); } else { segment.TargetResourceSet = null; segment.TargetResourceType = null; segment.TargetKind = RequestTargetKind.VoidOperation; } return(segment); }
private static bool AppendToLinks(OperationWrapper serviceAction, object resourceInstance, bool resourceInstanceInFeed, ref ODataAction actionToSerialize) { actionToSerialize.Metadata = new Uri(actionToSerialize.Metadata.OriginalString + "/SomethingThatWasAppended"); actionToSerialize.Target = new Uri(actionToSerialize.Target.OriginalString + "/SomethingThatWasAppended"); return(true); }
protected IEdmFunctionImport GetFunctionImport(OperationWrapper serviceOperation) { return(base.Service.Provider.GetMetadataProviderEdmModel(base.Service.OperationContext).EnsureDefaultEntityContainer().EnsureFunctionImport(serviceOperation)); }
/// <summary> /// Creates the next segment. /// </summary> /// <param name="previous">The previous segment.</param> /// <param name="segment">The the next segment.</param> /// <returns>The newly created next segment.</returns> private SegmentInfo CreateNextSegment(SegmentInfo previous, ODataPathSegment segment) { if (segment is ValueSegment) { return(CreateValueSegment(previous)); } SegmentInfo segmentInfo; if (segment is CountSegment) { segmentInfo = CreateCountSegment(previous); // DEVNOTE: Prior to refactor, $count was handled alongside properties. See more detailed comment in HandleCountSegment Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property"); return(segmentInfo); } // if its not one of the recognized special segments, then it must be a property, type-segment, or key value. Debug.Assert( previous.TargetKind == RequestTargetKind.ComplexObject || previous.TargetKind == RequestTargetKind.Resource || previous.TargetKind == RequestTargetKind.OpenProperty || previous.TargetKind == RequestTargetKind.Link, "previous.TargetKind(" + previous.TargetKind + ") can have properties"); CheckSegmentIsComposable(previous); // if the segment corresponds to a declared property, handle it // otherwise, fall back to type-segments, actions, and dynamic/open properties ResourceProperty projectedProperty; if (TryGetPropertyFromSegment(segment, out projectedProperty)) { CheckSingleResult(previous.SingleResult, previous.Identifier); if (projectedProperty.IsOfKind(ResourcePropertyKind.Stream)) { segmentInfo = CreateNamedStreamSegment(previous, projectedProperty); Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property"); return(segmentInfo); } segmentInfo = this.CreatePropertySegment(previous, projectedProperty); Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property"); return(segmentInfo); } // If the property resolution failed, and the previous segment was targeting an entity, then we should // try and resolve the identifier as type name. SegmentInfo typeNameSegment; if (this.TryCreateTypeNameSegment(previous, segment, out typeNameSegment)) { Debug.Assert(typeNameSegment.TargetSource == previous.TargetSource, "segment.TargetSource == previous.TargetSource"); return(typeNameSegment); } OperationWrapper serviceAction = null; var actionSegment = segment as OperationSegment; if (actionSegment != null) { Debug.Assert(actionSegment.Operations.Count() == 1, "Operation segment should only ever have exactly one operation. Was a change made to how MetadataProviderEdmModel finds actions/service operations"); serviceAction = ((MetadataProviderEdmOperation)actionSegment.Operations.Single()).ServiceOperation; Debug.Assert(serviceAction != null, "serviceAction != null"); Debug.Assert(serviceAction.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action"); } if (serviceAction != null) { Debug.Assert(serviceAction.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action"); // Service Actions can bind to a set with any ResourceSetRights except ResourceSetRights.None. segmentInfo = this.CreateSegmentForServiceAction(previous, serviceAction); Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.ServiceOperation, "segment.TargetSource == RequestTargetSource.ServiceOperation"); return(segmentInfo); } CheckSingleResult(previous.SingleResult, previous.Identifier); segmentInfo = CreateOpenPropertySegment(previous, ((DynamicPathSegment)segment).Identifier); Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property"); return(segmentInfo); }
public bool TryGetCachedOperationWrapper(string serviceActionName, ResourceType bindingType, out OperationWrapper actionWrapper) { actionWrapper = null; return(false); }
public void AddOperationToEdmModel(OperationWrapper actionWrapper) { }
private void ApplyProjectionsToExpandTree(List <List <string> > selectPathsAsText) { for (int i = selectPathsAsText.Count - 1; i >= 0; i--) { List <string> list = selectPathsAsText[i]; ExpandedProjectionNode rootProjectionNode = this.GetRootProjectionNode(); ResourceType type = null; for (int j = 0; j < list.Count; j++) { bool flag2; string containerQualifiedName = list[j]; bool lastPathSegment = j == (list.Count - 1); rootProjectionNode.ProjectionFound = true; if (containerQualifiedName == "*") { rootProjectionNode.ProjectAllImmediateProperties = true; break; } if (this.service.Provider.GetNameFromContainerQualifiedName(containerQualifiedName, out flag2) == "*") { rootProjectionNode.ProjectAllImmediateOperations = true; break; } ResourceType previousSegmentResourceType = type ?? rootProjectionNode.ResourceType; ResourceProperty property = previousSegmentResourceType.TryResolvePropertyName(containerQualifiedName); if (property == null) { type = WebUtil.ResolveTypeIdentifier(this.service.Provider, containerQualifiedName, previousSegmentResourceType, type != null); if (type != null) { this.description.VerifyProtocolVersion(RequestDescription.Version3Dot0, this.service); continue; } Func <OperationWrapper, bool> predicate = null; string serviceActionName = this.service.Provider.GetNameFromContainerQualifiedName(containerQualifiedName, out flag2); OperationWrapper operation = null; if (!previousSegmentResourceType.IsOpenType || flag2) { if (predicate == null) { predicate = o => o.Name == serviceActionName; } operation = this.service.ActionProvider.GetServiceActionsByBindingParameterType(this.service.OperationContext, previousSegmentResourceType).SingleOrDefault <OperationWrapper>(predicate); } if (operation != null) { rootProjectionNode.AddOperation(operation); if (!lastPathSegment) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_ServiceActionMustBeLastSegmentInSelect(containerQualifiedName)); } continue; } if (!previousSegmentResourceType.IsOpenType) { throw DataServiceException.CreateSyntaxError(System.Data.Services.Strings.RequestUriProcessor_PropertyNotFound(previousSegmentResourceType.FullName, containerQualifiedName)); } if (!lastPathSegment) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(containerQualifiedName)); } } rootProjectionNode = ApplyProjectionForProperty(rootProjectionNode, containerQualifiedName, property, previousSegmentResourceType, lastPathSegment); type = null; } if (type != null) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_QueryParametersPathCannotEndInTypeIdentifier("$select", type.FullName)); } } }
/// <summary> /// Asks the provider if the action should be advertised in payloads. /// </summary> /// <param name="entityToSerialize">The entity to serialize.</param> /// <param name="resourceInstanceInFeed">Whether or not the entity is being serialized in a feed.</param> /// <param name="serviceOperationWrapper">The service operation wrapper.</param> /// <param name="lazyActionTargetUri">Target uri of the action, which will only be generated if needed.</param> /// <param name="entityHasMultipleActionsWithSameName">Whether or not there are multiple operations in the current scope with the same name as the current operation.</param> /// <param name="odataAction">The ODL object-model representation of the action.</param> /// <returns>Whether or not the action should be advertised.</returns> private bool AskProviderIfActionShouldBeAdvertised(EntityToSerialize entityToSerialize, bool resourceInstanceInFeed, OperationWrapper serviceOperationWrapper, SimpleLazy <Uri> lazyActionTargetUri, bool entityHasMultipleActionsWithSameName, ref ODataAction odataAction) { if (this.advertiseServiceAction(serviceOperationWrapper, entityToSerialize.Entity, resourceInstanceInFeed, ref odataAction)) { if (odataAction == null) { throw new DataServiceException(500, Microsoft.OData.Service.Strings.DataServiceActionProviderWrapper_AdvertiseServiceActionCannotReturnNullActionToSerialize); } // Always set target and title if there are overloaded actions. if (!entityHasMultipleActionsWithSameName) { this.metadataPropertyManager.CheckForUnmodifiedTitle(odataAction, serviceOperationWrapper.Name); this.metadataPropertyManager.CheckForUnmodifiedTarget(odataAction, () => lazyActionTargetUri.Value); } // make the target link relative this.MakeOperationTargetRelativeFromMetadataUriIfJsonLight(odataAction); return(true); } odataAction = null; return(false); }
/// <summary> /// Tries to serialize the operation. /// </summary> /// <param name="entityToSerialize">The entity to serialize.</param> /// <param name="resourceInstanceInFeed">Whether or not the entity is being serialized in a feed.</param> /// <param name="entityHasMultipleActionsWithSameName">Whether or not there are multiple operations in the current scope with the same name as the current operation.</param> /// <param name="serviceOperationWrapper">The service operation wrapper.</param> /// <param name="odataAction">The ODL object-model representation of the action.</param> /// <returns>Whether or not to serialize the operation.</returns> private bool TrySerializeOperation(EntityToSerialize entityToSerialize, bool resourceInstanceInFeed, bool entityHasMultipleActionsWithSameName, OperationWrapper serviceOperationWrapper, out ODataAction odataAction) { Debug.Assert(serviceOperationWrapper != null, "serviceOperationWrapper != null"); // We only advertise actions. This is a debug assert because GetServiceOperationsByResourceType only returns actions. Debug.Assert(serviceOperationWrapper.Kind == OperationKind.Action, "Only actions can be advertised"); Uri metadata = this.operationLinkBuilder.BuildMetadataLink(serviceOperationWrapper, entityHasMultipleActionsWithSameName); // If the action has OperationParameterBindingKind set to "Always" then we advertise the action without calling "AdvertiseServiceAction". bool isAlwaysAvailable = serviceOperationWrapper.OperationParameterBindingKind == OperationParameterBindingKind.Always; odataAction = new ODataAction { Metadata = metadata }; // There is some subtlety to the interaction between action advertisement and whether or not to include title/target on the wire. // // 1) If an action is always available: // The provider author does not get a chance to customize the title/target values... // so the values will be based on conventions... // so by default do not write them on the wire // 2) If it is only sometimes available: // The values need to be computed to provide them on the instance given to the provider... // but they might not be changed by the provider author... // so compare them to the computed values, and do not write them if they match. // TODO: Action provider should be able to customize title/target even if the action is 'always' advertised // If this gets fixed, then all the behavior should collapse to emulate case #2 above // Create a lazy Uri for the target, because we may need it more than once (see case #2 above). SimpleLazy <Uri> lazyActionTargetUri = new SimpleLazy <Uri>(() => this.operationLinkBuilder.BuildTargetLink(entityToSerialize, serviceOperationWrapper, entityHasMultipleActionsWithSameName)); this.metadataPropertyManager.SetTitle(odataAction, isAlwaysAvailable, serviceOperationWrapper.Name); this.metadataPropertyManager.SetTarget(odataAction, isAlwaysAvailable, () => lazyActionTargetUri.Value); // If the operation is always available, // 1. Return true for MetadataQueryOption.All. // 2. Return false for MetadataQueryOption.None. // 3. Return false for MetadataQueryOption.Default. if (isAlwaysAvailable) { return(this.payloadMetadataParameterInterpreter.ShouldIncludeAlwaysAvailableOperation()); } return(this.AskProviderIfActionShouldBeAdvertised(entityToSerialize, resourceInstanceInFeed, serviceOperationWrapper, lazyActionTargetUri, entityHasMultipleActionsWithSameName, ref odataAction)); }