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;
        }
示例#3
0
 /// <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());
     }
 }
示例#4
0
 /// <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());
     }
 }
示例#5
0
 /// <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)
 {
 }
示例#6
0
        /// <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.");
        }
示例#7
0
        /// <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);
                    }
                }
            }
        }
示例#9
0
        /// <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.");
        }
示例#10
0
        /// <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");
            }
        }
示例#11
0
        /// <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();
        }
示例#12
0
 /// <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)
 {
 }