public void PathExpressionTest() { var expression = new ResourceSetPathExpression("param1"); Assert.AreEqual("param1", expression.PathExpression, "Invalid value in PathExpression."); expression = new ResourceSetPathExpression("param1/P1"); Assert.AreEqual("param1/P1", expression.PathExpression, "Invalid value in PathExpression."); expression = new ResourceSetPathExpression("param1/P1/P2"); Assert.AreEqual("param1/P1/P2", expression.PathExpression, "Invalid value in PathExpression."); expression = new ResourceSetPathExpression("param1/FQNS.T1/P1/FQNS.T2/P2"); Assert.AreEqual("param1/FQNS.T1/P1/FQNS.T2/P2", expression.PathExpression, "Invalid value in PathExpression."); }
/// <summary> /// Constructor. /// </summary> /// <param name="model">The model this instance belongs to.</param> /// <param name="container">The container this instance belongs to.</param> /// <param name="edmOperation">The edm operation underlying this function import.</param> /// <remarks>This constructor assumes that the entity set for this service operation has already be created.</remarks> protected internal MetadataProviderEdmOperationImport( MetadataProviderEdmModel model, MetadataProviderEdmEntityContainer container, MetadataProviderEdmOperation edmOperation) { Debug.Assert(model != null, "model != null"); Debug.Assert(container != null, "container != null"); Debug.Assert(edmOperation != null, "edmOperation != null"); this.container = container; this.model = model; this.edmOperation = edmOperation; // EntitySetPath=<path string> ResourceSetPathExpression resultSetPathExpression = edmOperation.ServiceOperation.ResultSetPathExpression; this.entitySetPath = resultSetPathExpression == null ? null : resultSetPathExpression.PathExpression; }
/// <summary> /// Initializes a new <see cref="ServiceAction"/> instance. /// </summary> /// <param name="name">Name of the action.</param> /// <param name="returnType">Return type of the action.</param> /// <param name="resultSet">Result resource set of the action if the action returns an entity or a collection of entity; null otherwise.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result resource set of the function if the action returns an entity or a collection of entity; null otherwise.</param> /// <param name="parameters">In-order parameters for this action; the first parameter is the binding parameter.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <remarks>The value of <paramref name="operationParameterBindingKind"/> must be set to <see cref="OperationParameterBindingKind.Sometimes"/> or /// <see cref="OperationParameterBindingKind.Always"/> if the first parameter in <paramref name="parameters"/> is the binding parameter /// or <see cref="OperationParameterBindingKind.Never"/> if the first parameter is not a binding parameter. If the value of <paramref name="operationParameterBindingKind"/> /// is set to <see cref="OperationParameterBindingKind.Always"/> then the IDataServiceActionProvider.AdvertiseServiceAction method will not be called for the action /// and the action will be always advertised by the default convention.</remarks> private ServiceAction(string name, ResourceType returnType, ResourceSet resultSet, ResourceSetPathExpression resultSetPathExpression, IEnumerable<ServiceActionParameter> parameters, OperationParameterBindingKind operationParameterBindingKind) : base( name, Operation.GetResultKindFromReturnType(returnType, isComposable: false), returnType, resultSet, resultSetPathExpression, XmlConstants.HttpMethodPost, parameters, operationParameterBindingKind, OperationKind.Action) { Debug.Assert(this.OperationParameters != null, "this.OperationParameters != null"); if (this.OperationParameters == OperationParameter.EmptyOperationParameterCollection) { this.parameters = ServiceActionParameter.EmptyServiceActionParameterCollection; } else { this.parameters = new ReadOnlyCollection<ServiceActionParameter>(this.OperationParameters.Cast<ServiceActionParameter>().ToList()); } }
/// <summary> /// Initializes a new <see cref="ServiceAction"/> instance. /// </summary> /// <param name="name">Name of the action.</param> /// <param name="returnType">Return type of the action.</param> /// <param name="resultSet">Result resource set of the action if the action returns an entity or a collection of entity; null otherwise.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result resource set of the function if the action returns an entity or a collection of entity; null otherwise.</param> /// <param name="parameters">In-order parameters for this action; the first parameter is the binding parameter.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <remarks>The value of <paramref name="operationParameterBindingKind"/> must be set to <see cref="OperationParameterBindingKind.Sometimes"/> or /// <see cref="OperationParameterBindingKind.Always"/> if the first parameter in <paramref name="parameters"/> is the binding parameter /// or <see cref="OperationParameterBindingKind.Never"/> if the first parameter is not a binding parameter. If the value of <paramref name="operationParameterBindingKind"/> /// is set to <see cref="OperationParameterBindingKind.Always"/> then the IDataServiceActionProvider.AdvertiseServiceAction method will not be called for the action /// and the action will be always advertised by the default convention.</remarks> private ServiceAction(string name, ResourceType returnType, ResourceSet resultSet, ResourceSetPathExpression resultSetPathExpression, IEnumerable <ServiceActionParameter> parameters, OperationParameterBindingKind operationParameterBindingKind) : base( name, Operation.GetResultKindFromReturnType(returnType, isComposable: false), returnType, resultSet, resultSetPathExpression, XmlConstants.HttpMethodPost, parameters, operationParameterBindingKind, OperationKind.Action) { Debug.Assert(this.OperationParameters != null, "this.OperationParameters != null"); if (this.OperationParameters == OperationParameter.EmptyOperationParameterCollection) { this.parameters = ServiceActionParameter.EmptyServiceActionParameterCollection; } else { this.parameters = new ReadOnlyCollection <ServiceActionParameter>(this.OperationParameters.Cast <ServiceActionParameter>().ToList()); } }
/// <summary>Initializes a new <see cref="T:Microsoft.OData.Service.Providers.ServiceAction" /> instance.</summary> /// <param name="name">Name of the action.</param> /// <param name="returnType">Return type of the action.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <param name="parameters">In-order parameters for this action; the first parameter is the binding parameter.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result resource set of the function if the action returns an entity or a collection of entity; null otherwise.</param> /// <remarks>The value of <paramref name="operationParameterBindingKind"/> must be set to <see cref="OperationParameterBindingKind.Sometimes"/> or /// <see cref="OperationParameterBindingKind.Always"/> if the first parameter in <paramref name="parameters"/> is the binding parameter /// or <see cref="OperationParameterBindingKind.Never"/> if the first parameter is not a binding parameter. If the value of <paramref name="operationParameterBindingKind"/> /// is set to <see cref="OperationParameterBindingKind.Always"/> then the IDataServiceActionProvider.AdvertiseServiceAction method will not be called for the action /// and the action will be always advertised by the default convention.</remarks> public ServiceAction(string name, ResourceType returnType, OperationParameterBindingKind operationParameterBindingKind, IEnumerable <ServiceActionParameter> parameters, ResourceSetPathExpression resultSetPathExpression) : this(name, returnType, null /*resultSet*/, resultSetPathExpression, parameters, operationParameterBindingKind) { }
/// <summary> /// Initializes a new <see cref="Operation"/> instance. /// </summary> /// <param name="name">name of the operation.</param> /// <param name="resultKind">Kind of result expected from this operation.</param> /// <param name="returnType">Return type of the operation.</param> /// <param name="resultSet">EntitySet of the result expected from this operation, must be null if <paramref name="resultSetPathExpression"/> is not null.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result set of the operation, must be null if <paramref name="resultSet"/> is not null.</param> /// <param name="method">Protocol (for example HTTP) method the service operation responds to.</param> /// <param name="parameters">In-order parameters for this operation.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <param name="kind">The kind of the current service operation.</param> internal Operation( string name, ServiceOperationResultKind resultKind, ResourceType returnType, ResourceSet resultSet, ResourceSetPathExpression resultSetPathExpression, string method, IEnumerable <OperationParameter> parameters, OperationParameterBindingKind operationParameterBindingKind, OperationKind kind) { WebUtil.CheckStringArgumentNullOrEmpty(name, "name"); WebUtil.CheckServiceOperationResultKind(resultKind, "resultKind"); WebUtil.CheckStringArgumentNullOrEmpty(method, "method"); Debug.Assert( this.GetType() == typeof(ServiceOperation) && kind == OperationKind.ServiceOperation || this.GetType() == typeof(ServiceAction) && kind == OperationKind.Action, "OperationKind and the current type doesn't match."); ValidateConstructorArguments(name, returnType, resultSet, resultSetPathExpression, method, operationParameterBindingKind, kind); this.name = name; this.resultKind = resultKind; this.returnType = returnType; this.resourceSet = resultSet; this.resultSetPathExpression = resultSetPathExpression; this.method = method; this.kind = kind; this.operationParameterBindingKind = operationParameterBindingKind; this.operationParameters = Operation.ValidateParameters(this.operationParameterBindingKind, parameters); if (this.operationParameterBindingKind != OperationParameterBindingKind.Never) { Debug.Assert( this.operationParameterBindingKind == OperationParameterBindingKind.Always || this.operationParameterBindingKind == OperationParameterBindingKind.Sometimes, "Value of operationParameterBindingKind was expected to be 'always' or 'sometimes'."); Debug.Assert(this.kind != OperationKind.ServiceOperation, "ServiceOperations should never be bindable."); this.bindingParameter = this.operationParameters.FirstOrDefault(); if (this.bindingParameter == null) { throw new ArgumentException(Strings.ServiceOperation_BindableOperationMustHaveAtLeastOneParameter, "operationParameterBindingKind"); } if (resourceSet != null) { throw new ArgumentException(Strings.Opereration_BoundOperationsMustNotSpecifyEntitySetOnlyEntitySetPath(this.name), "resourceSet"); } if (resultSetPathExpression != null && this.bindingParameter.ParameterType.ResourceTypeKind != ResourceTypeKind.EntityType && this.bindingParameter.ParameterType.ResourceTypeKind != ResourceTypeKind.EntityCollection) { throw new ArgumentException(Strings.ServiceOperation_BindingParameterMustBeEntityToUsePathExpression("resultSetPathExpression")); } if (this.kind == OperationKind.Action && !(this.bindingParameter.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityType || this.bindingParameter.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityCollection)) { throw new ArgumentException(Strings.ServiceOperation_ActionBindingMustBeEntityOrEntityCollection, "parameters"); } if (this.resultSetPathExpression != null) { this.resultSetPathExpression.SetBindingParameter(this.bindingParameter); } } Debug.Assert(this.kind != OperationKind.Action || string.CompareOrdinal(XmlConstants.HttpMethodPost, this.method) == 0, "HttpMethod must be POST for Actions."); Debug.Assert(this.resourceSet == null || this.resultSetPathExpression == null, "'resultSet' and 'resultSetPathExpression' cannot be both set by the constructor."); }
/// <summary> /// Validates arguments to the constructor. /// </summary> /// <param name="operationName">Name of the operation.</param> /// <param name="returnType">Return type of the operation.</param> /// <param name="resultSet">EntitySet of the result expected from this operation, must be null if <paramref name="resultSetPathExpression"/> is not null.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result set of the operation, must be null if <paramref name="resultSet"/> is not null.</param> /// <param name="method">Protocol (for example HTTP) method the service operation responds to.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <param name="kind">The kind of the current service operation.</param> private static void ValidateConstructorArguments( string operationName, ResourceType returnType, ResourceSet resultSet, ResourceSetPathExpression resultSetPathExpression, string method, OperationParameterBindingKind operationParameterBindingKind, OperationKind kind) { if (returnType != null && (returnType.ResourceTypeKind == ResourceTypeKind.EntityType || returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection)) { ResourceType resultType = returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection ? ((EntityCollectionResourceType)returnType).ItemType : returnType; if (resultSet == null && resultSetPathExpression == null || resultSet != null && !resultSet.ResourceType.IsAssignableFrom(resultType)) { if (kind == OperationKind.ServiceOperation) { throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndResultSetMustMatch("resultType", "resultSet")); } throw new ArgumentException(Strings.ServiceOperation_ReturnTypeAndResultSetMustMatch("returnType", "resultSetPathExpression", "resultSet")); } } else { if (resultSet != null || resultSetPathExpression != null) { string setParameterName = resultSet != null ? "resultSet" : "resultSetPathExpression"; if (kind == OperationKind.ServiceOperation) { throw new ArgumentException(Strings.ServiceOperation_ResultSetMustBeNullForGivenResultType(setParameterName, "resultType")); } throw new ArgumentException(Strings.ServiceOperation_ResultSetMustBeNullForGivenReturnType(setParameterName, "returnType")); } } if (returnType != null && returnType == ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream))) { string parameterName; string errorMessage; if (kind == OperationKind.ServiceOperation) { parameterName = "resultType"; errorMessage = Strings.ServiceOperation_InvalidResultType(returnType.FullName); } else { parameterName = "returnType"; errorMessage = Strings.ServiceOperation_InvalidReturnType(returnType.FullName); } throw new ArgumentException(errorMessage, parameterName); } if (string.CompareOrdinal(XmlConstants.HttpMethodGet, method) != 0 && string.CompareOrdinal(XmlConstants.HttpMethodPost, method) != 0) { throw new ArgumentException(Strings.ServiceOperation_NotSupportedProtocolMethod(method, operationName), "method"); } if (resultSetPathExpression != null && operationParameterBindingKind == OperationParameterBindingKind.Never) { // If the operation is not bindable, we want users to call the constructor that uses resultSet. throw new ArgumentException(Strings.ServiceOperation_MustBeBindableToUsePathExpression("resultSetPathExpression"), "resultSetPathExpression"); } }
public void GetTargetSetTestsSetBindingTypeShouldPerformCorrectValidation() { ResourceType actorEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Actor", false) { CanReflectOnInstanceType = false }; ResourceProperty idProperty = new ResourceProperty("ID", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, ResourceType.GetPrimitiveResourceType(typeof(int))) { CanReflectOnInstanceTypeProperty = false }; actorEntityType.AddProperty(idProperty); ResourceType addressComplexType = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "foo", "Address", false) { CanReflectOnInstanceType = false }; addressComplexType.AddProperty(new ResourceProperty("StreetAddress", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(string))) { CanReflectOnInstanceTypeProperty = false }); addressComplexType.AddProperty(new ResourceProperty("ZipCode", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(int))) { CanReflectOnInstanceTypeProperty = false }); actorEntityType.AddProperty(new ResourceProperty("PrimaryAddress", ResourcePropertyKind.ComplexType, addressComplexType) { CanReflectOnInstanceTypeProperty = false }); actorEntityType.AddProperty(new ResourceProperty("OtherAddresses", ResourcePropertyKind.Collection, ResourceType.GetCollectionResourceType(addressComplexType)) { CanReflectOnInstanceTypeProperty = false }); ResourceType movieEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Movie", false) { CanReflectOnInstanceType = false }; movieEntityType.AddProperty(idProperty); ResourceProperty moviesNavProp = new ResourceProperty("Movies", ResourcePropertyKind.ResourceSetReference, movieEntityType) { CanReflectOnInstanceTypeProperty = false }; actorEntityType.AddProperty(moviesNavProp); ResourceProperty actorsNavProp = new ResourceProperty("Actors", ResourcePropertyKind.ResourceSetReference, actorEntityType) { CanReflectOnInstanceTypeProperty = false }; movieEntityType.AddProperty(actorsNavProp); ResourceType derivedActorEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, actorEntityType, "foo", "DerivedActor", false) { CanReflectOnInstanceType = false }; ResourceType derivedMovieEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, movieEntityType, "foo", "DerivedMovie", false) { CanReflectOnInstanceType = false }; actorEntityType.SetReadOnly(); derivedActorEntityType.SetReadOnly(); movieEntityType.SetReadOnly(); derivedMovieEntityType.SetReadOnly(); addressComplexType.SetReadOnly(); DataServiceProviderSimulator providerSimulator = new DataServiceProviderSimulator(); providerSimulator.AddResourceType(actorEntityType); providerSimulator.AddResourceType(derivedActorEntityType); providerSimulator.AddResourceType(movieEntityType); providerSimulator.AddResourceType(derivedMovieEntityType); providerSimulator.AddResourceType(addressComplexType); ResourceSet actorSet = new ResourceSet("Actors", actorEntityType); ResourceSet movieSet = new ResourceSet("Movies", movieEntityType); actorSet.SetReadOnly(); movieSet.SetReadOnly(); providerSimulator.AddResourceSet(actorSet); providerSimulator.AddResourceSet(movieSet); providerSimulator.AddResourceAssociationSet(new ResourceAssociationSet("Actors_Movies", new ResourceAssociationSetEnd(actorSet, actorEntityType, moviesNavProp), new ResourceAssociationSetEnd(movieSet, movieEntityType, actorsNavProp))); DataServiceConfiguration config = new DataServiceConfiguration(providerSimulator); config.SetEntitySetAccessRule("*", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = ODataProtocolVersion.V4; var dataService = new DataServiceSimulator() { OperationContext = new DataServiceOperationContext(new DataServiceHostSimulator()) }; dataService.ProcessingPipeline = new DataServiceProcessingPipeline(); DataServiceStaticConfiguration staticConfiguration = new DataServiceStaticConfiguration(dataService.Instance.GetType(), providerSimulator); IDataServiceProviderBehavior providerBehavior = DataServiceProviderBehavior.CustomDataServiceProviderBehavior; DataServiceProviderWrapper provider = new DataServiceProviderWrapper( new DataServiceCacheItem( config, staticConfiguration), providerSimulator, providerSimulator, dataService, false); dataService.Provider = provider; provider.ProviderBehavior = providerBehavior; var testCases = new[] { new { AppendParameterName = true, Path = "", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), ErrorMessage = default(string) }, new { AppendParameterName = true, Path = "/Movies", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set), ErrorMessage = default(string) }, new { AppendParameterName = true, Path = "/Movies/Actors/Movies", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set), ErrorMessage = default(string) }, new { AppendParameterName = true, Path = "/foo.DerivedActor/Movies/foo.DerivedMovie/Actors/foo.DerivedActor/Movies", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set), ErrorMessage = default(string) }, new { AppendParameterName = true, Path = "/", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/' is not a valid expression because it contains an empty segment or it ends with '/'." }, new { AppendParameterName = true, Path = "/Movies/", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/Movies/' is not a valid expression because it contains an empty segment or it ends with '/'." }, new { AppendParameterName = true, Path = "/Movies//Actors", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set), ErrorMessage = "The path expression '{0}/Movies//Actors' is not a valid expression because it contains an empty segment or it ends with '/'." }, new { AppendParameterName = true, Path = "/foo.DerivedActor", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/foo.DerivedActor' is not a valid expression because it ends with the type identifier 'foo.DerivedActor'. A valid path expression must not end in a type identifier." }, new { AppendParameterName = true, Path = "/Movies/foo.DerivedMovie", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/Movies/foo.DerivedMovie' is not a valid expression because it ends with the type identifier 'foo.DerivedMovie'. A valid path expression must not end in a type identifier." }, new { AppendParameterName = true, Path = "/Foo", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/Foo' is not a valid expression because the segment 'Foo' is not a type identifier or a property on the resource type 'foo.Actor'." }, new { AppendParameterName = true, Path = "/ID", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/ID' is not a valid expression because the segment 'ID' is a property of type 'Edm.Int32'. A valid path expression must only contain properties of entity type." }, new { AppendParameterName = true, Path = "/OtherAddresses", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/OtherAddresses' is not a valid expression because the segment 'OtherAddresses' is a property of type 'Collection(foo.Address)'. A valid path expression must only contain properties of entity type." }, new { AppendParameterName = true, Path = "/Movies/Actors/PrimaryAddress", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression '{0}/Movies/Actors/PrimaryAddress' is not a valid expression because the segment 'PrimaryAddress' is a property of type 'foo.Address'. A valid path expression must only contain properties of entity type." }, new { AppendParameterName = false, Path = "foo", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression 'foo' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'." }, new { AppendParameterName = false, Path = "abc/pqr", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression 'abc/pqr' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'." }, new { AppendParameterName = false, Path = "actorParameter", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression 'actorParameter' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'." }, new { AppendParameterName = false, Path = "actorsParameter", BindingSet = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set), TargetSet = default(ResourceSetWrapper), ErrorMessage = "The path expression 'actorsParameter' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'." }, }; ServiceActionParameter actorParameter = new ServiceActionParameter("actor", actorEntityType); ServiceActionParameter actorsParameter = new ServiceActionParameter("actors", ResourceType.GetEntityCollectionResourceType(actorEntityType)); var parameters = new ServiceActionParameter[] { actorParameter, actorsParameter }; foreach (var parameter in parameters) { foreach (var testCase in testCases) { string pathString = testCase.AppendParameterName ? parameter.Name + testCase.Path : testCase.Path; var path = new ResourceSetPathExpression(pathString); Assert.AreEqual(pathString, path.PathExpression); string expectedErrorMessage = testCase.ErrorMessage == null ? null : string.Format(testCase.ErrorMessage, parameter.Name); try { path.SetBindingParameter(parameter); path.InitializePathSegments(provider); var targetSet = path.GetTargetSet(provider, testCase.BindingSet); Assert.IsNull(expectedErrorMessage, "Expecting exception but received none."); Assert.AreEqual(targetSet.Name, testCase.TargetSet.Name); } catch (InvalidOperationException e) { Assert.AreEqual(expectedErrorMessage, e.Message); } } } }
/// <summary> /// Initializes a new <see cref="Operation"/> instance. /// </summary> /// <param name="name">name of the operation.</param> /// <param name="resultKind">Kind of result expected from this operation.</param> /// <param name="returnType">Return type of the operation.</param> /// <param name="resultSet">EntitySet of the result expected from this operation, must be null if <paramref name="resultSetPathExpression"/> is not null.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result set of the operation, must be null if <paramref name="resultSet"/> is not null.</param> /// <param name="method">Protocol (for example HTTP) method the service operation responds to.</param> /// <param name="parameters">In-order parameters for this operation.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <param name="kind">The kind of the current service operation.</param> internal Operation( string name, ServiceOperationResultKind resultKind, ResourceType returnType, ResourceSet resultSet, ResourceSetPathExpression resultSetPathExpression, string method, IEnumerable<OperationParameter> parameters, OperationParameterBindingKind operationParameterBindingKind, OperationKind kind) { WebUtil.CheckStringArgumentNullOrEmpty(name, "name"); WebUtil.CheckServiceOperationResultKind(resultKind, "resultKind"); WebUtil.CheckStringArgumentNullOrEmpty(method, "method"); Debug.Assert( this.GetType() == typeof(ServiceOperation) && kind == OperationKind.ServiceOperation || this.GetType() == typeof(ServiceAction) && kind == OperationKind.Action, "OperationKind and the current type doesn't match."); ValidateConstructorArguments(name, returnType, resultSet, resultSetPathExpression, method, operationParameterBindingKind, kind); this.name = name; this.resultKind = resultKind; this.returnType = returnType; this.resourceSet = resultSet; this.resultSetPathExpression = resultSetPathExpression; this.method = method; this.kind = kind; this.operationParameterBindingKind = operationParameterBindingKind; this.operationParameters = Operation.ValidateParameters(this.operationParameterBindingKind, parameters); if (this.operationParameterBindingKind != OperationParameterBindingKind.Never) { Debug.Assert( this.operationParameterBindingKind == OperationParameterBindingKind.Always || this.operationParameterBindingKind == OperationParameterBindingKind.Sometimes, "Value of operationParameterBindingKind was expected to be 'always' or 'sometimes'."); Debug.Assert(this.kind != OperationKind.ServiceOperation, "ServiceOperations should never be bindable."); this.bindingParameter = this.operationParameters.FirstOrDefault(); if (this.bindingParameter == null) { throw new ArgumentException(Strings.ServiceOperation_BindableOperationMustHaveAtLeastOneParameter, "operationParameterBindingKind"); } if (resourceSet != null) { throw new ArgumentException(Strings.Opereration_BoundOperationsMustNotSpecifyEntitySetOnlyEntitySetPath(this.name), "resourceSet"); } if (resultSetPathExpression != null && this.bindingParameter.ParameterType.ResourceTypeKind != ResourceTypeKind.EntityType && this.bindingParameter.ParameterType.ResourceTypeKind != ResourceTypeKind.EntityCollection) { throw new ArgumentException(Strings.ServiceOperation_BindingParameterMustBeEntityToUsePathExpression("resultSetPathExpression")); } if (this.kind == OperationKind.Action && !(this.bindingParameter.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityType || this.bindingParameter.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityCollection)) { throw new ArgumentException(Strings.ServiceOperation_ActionBindingMustBeEntityOrEntityCollection, "parameters"); } if (this.resultSetPathExpression != null) { this.resultSetPathExpression.SetBindingParameter(this.bindingParameter); } } Debug.Assert(this.kind != OperationKind.Action || string.CompareOrdinal(XmlConstants.HttpMethodPost, this.method) == 0, "HttpMethod must be POST for Actions."); Debug.Assert(this.resourceSet == null || this.resultSetPathExpression == null, "'resultSet' and 'resultSetPathExpression' cannot be both set by the constructor."); }
/// <summary> /// Constructor. /// </summary> /// <param name="model">The model this instance belongs to.</param> /// <param name="operation">The resource operation underlying this function import.</param> /// <param name="namespaceName">The namespace of the operation.</param> /// <remarks>This constructor assumes that the entity set for this service operation has already be created.</remarks> protected internal MetadataProviderEdmOperation(MetadataProviderEdmModel model, OperationWrapper operation, string namespaceName) { Debug.Assert(model != null, "model != null"); Debug.Assert(operation != null, "operation != null"); this.model = model; this.ServiceOperation = operation; this.Namespace = namespaceName; if (operation.Kind == OperationKind.Action) { this.isBound = this.ServiceOperation.BindingParameter != null; } else { Debug.Assert(operation.Kind == OperationKind.ServiceOperation, "serviceOperation.Kind == OperationKind.ServiceOperation"); Debug.Assert(operation.OperationParameterBindingKind == OperationParameterBindingKind.Never, "operation.OperationParameterBindingKind == OperationParameterBindingKind.Never"); this.isBound = DefaultIsBindable; } // EntitySetPath=<path string> ResourceSetPathExpression resultSetPathExpression = operation.ResultSetPathExpression; this.entitySetPath = resultSetPathExpression == null ? null : resultSetPathExpression.PathExpression; #if DEBUG ResourceType returnType = operation.ReturnType; ResourceSetWrapper resultSet = operation.ResourceSet; Debug.Assert( returnType == null || returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection || returnType.ResourceTypeKind == ResourceTypeKind.EntityType || (resultSet == null && resultSetPathExpression == null), "resultSet and resultSetPathExpression must be both null when the return type is not an entity type or an entity collection type."); Debug.Assert( (returnType == null || returnType.ResourceTypeKind != ResourceTypeKind.EntityCollection && returnType.ResourceTypeKind != ResourceTypeKind.EntityType) || (resultSet != null || resultSetPathExpression != null), "One of resultSet or resultSetPathExpression must be set when the return type is either an entity type or an entity collection type."); Debug.Assert(resultSet == null || resultSetPathExpression == null, "resultSet and resultSetPathExpression cannot be both set."); #endif string mimeType = operation.MimeType; if (!string.IsNullOrEmpty(mimeType)) { model.SetMimeType(this, mimeType); } switch (this.ServiceOperation.OperationParameterBindingKind) { case OperationParameterBindingKind.Always: break; default: Debug.Assert( this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Sometimes || this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Never, "this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Sometimes || this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Never"); break; } ReadOnlyCollection <OperationParameter> operationParameters = operation.Parameters; if (operationParameters != null && operationParameters.Count > 0) { List <IEdmOperationParameter> list = new List <IEdmOperationParameter>(operationParameters.Count); foreach (OperationParameter parameter in operationParameters) { IEdmTypeReference parameterType = this.model.EnsureTypeReference(parameter.ParameterType, /*annotations*/ null); EdmOperationParameter edmParameter = new EdmOperationParameter(this, parameter.Name, parameterType); list.Add(edmParameter); } this.parameters = new ReadOnlyCollection <IEdmOperationParameter>(list); } this.ReturnType = this.CreateReturnTypeReference(); }
/// <summary>Initializes a new <see cref="T:Microsoft.OData.Service.Providers.ServiceAction" /> instance.</summary> /// <param name="name">Name of the action.</param> /// <param name="returnType">Return type of the action.</param> /// <param name="operationParameterBindingKind">the kind of the operation parameter binding (Never, Sometimes, Always).</param> /// <param name="parameters">In-order parameters for this action; the first parameter is the binding parameter.</param> /// <param name="resultSetPathExpression">Path expression to calculate the result resource set of the function if the action returns an entity or a collection of entity; null otherwise.</param> /// <remarks>The value of <paramref name="operationParameterBindingKind"/> must be set to <see cref="OperationParameterBindingKind.Sometimes"/> or /// <see cref="OperationParameterBindingKind.Always"/> if the first parameter in <paramref name="parameters"/> is the binding parameter /// or <see cref="OperationParameterBindingKind.Never"/> if the first parameter is not a binding parameter. If the value of <paramref name="operationParameterBindingKind"/> /// is set to <see cref="OperationParameterBindingKind.Always"/> then the IDataServiceActionProvider.AdvertiseServiceAction method will not be called for the action /// and the action will be always advertised by the default convention.</remarks> public ServiceAction(string name, ResourceType returnType, OperationParameterBindingKind operationParameterBindingKind, IEnumerable<ServiceActionParameter> parameters, ResourceSetPathExpression resultSetPathExpression) : this(name, returnType, null /*resultSet*/, resultSetPathExpression, parameters, operationParameterBindingKind) { }